KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_edit_cfg.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "dialog_edit_cfg.h"
21
22#include <advanced_config.h>
23#include <config_params.h>
24#include <paths.h>
25#include <wx/button.h>
26#include <wx/display.h>
27#include <wx/log.h>
28#include <wx/menu.h>
29#include <wx/sizer.h>
30#include <wx/settings.h>
31#include <wx/srchctrl.h>
32#include <widgets/wx_grid.h>
33#include <algorithm>
34#include <functional>
35#include <memory>
36
37
38static wxString paramValueString( const PARAM_CFG& aParam )
39{
40 wxString s;
41
42 try
43 {
44 switch( aParam.m_Type )
45 {
47 s << *static_cast<const PARAM_CFG_INT&>( aParam ).m_Pt_param;
48 break;
49
51 s = wxString::FromCDouble( *static_cast<const PARAM_CFG_DOUBLE&>( aParam ).m_Pt_param );
52 break;
53
55 s = *static_cast<const PARAM_CFG_WXSTRING&>( aParam ).m_Pt_param;
56 break;
57
59 s << ( *static_cast<const PARAM_CFG_BOOL&>( aParam ).m_Pt_param ? wxS( "true" ) : wxS( "false" ) );
60 break;
61
62 default:
63 wxLogError( wxS( "Unsupported PARAM_CFG variant: " ) + wxString::Format( wxS( "%d" ), aParam.m_Type ) );
64 }
65 }
66 catch( ... )
67 {
68 wxLogError( wxS( "Error converting parameter value to string." ) );
69 }
70 return s;
71}
72
73
74static wxString paramDefaultString( const PARAM_CFG& aParam )
75{
76 wxString s;
77
78 try
79 {
80 switch( aParam.m_Type )
81 {
83 s << static_cast<const PARAM_CFG_INT&>( aParam ).m_Default;
84 break;
85
87 s = wxString::FromCDouble( static_cast<const PARAM_CFG_DOUBLE&>( aParam ).m_Default );
88 break;
89
91 s << static_cast<const PARAM_CFG_WXSTRING&>( aParam ).m_default;
92 break;
93
95 s << ( static_cast<const PARAM_CFG_BOOL&>( aParam ).m_Default ? wxS( "true" ) : wxS( "false" ) );
96 break;
97
98 default:
99 break;
100 }
101 }
102 catch( ... )
103 {
104 wxLogError( wxS( "Error converting parameter default value to string." ) );
105 }
106
107 return s;
108}
109
110
111static void writeParam( PARAM_CFG& aParam, const wxString& aValue )
112{
113 switch( aParam.m_Type )
114 {
116 {
117 PARAM_CFG_INT& param = static_cast<PARAM_CFG_INT&>( aParam );
118 *param.m_Pt_param = wxAtoi( aValue );
119 break;
120 }
121
123 {
124 PARAM_CFG_BOOL& param = static_cast<PARAM_CFG_BOOL&>( aParam );
125
126 if( aValue.CmpNoCase( wxS( "true" ) ) == 0 || aValue.CmpNoCase( wxS( "yes" ) ) == 0
127 || aValue.CmpNoCase( wxS( "1" ) ) == 0 )
128 {
129 *param.m_Pt_param = true;
130 }
131 else
132 {
133 *param.m_Pt_param = false;
134 }
135 break;
136 }
137
139 {
140 PARAM_CFG_DOUBLE& param = static_cast<PARAM_CFG_DOUBLE&>( aParam );
141 aValue.ToCDouble( param.m_Pt_param );
142 break;
143 }
144
146 {
147 PARAM_CFG_WXSTRING& param = static_cast<PARAM_CFG_WXSTRING&>( aParam );
148 *param.m_Pt_param = aValue;
149 break;
150 }
151
152 default:
153 wxASSERT_MSG( false, wxS( "Unsupported PARAM_CFG variant: " )
154 + wxString::Format( wxS( "%d" ), aParam.m_Type ) );
155 }
156}
157
158
160 wxDialog( aParent, wxID_ANY, _( "Edit Advanced Configuration" ), wxDefaultPosition, wxDefaultSize,
161 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
162{
163 m_cfgFile = wxFileName( PATHS::GetUserSettingsPath(), wxS( "kicad_advanced" ) );
164
165 m_filterCtrl = new wxSearchCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize );
166 m_filterCtrl->ShowCancelButton( true );
167 m_filterCtrl->SetDescriptiveText( _( "Filter" ) );
168
169 m_grid = new WX_GRID( this, wxID_ANY );
170 m_grid->CreateGrid( 0, 3 );
171 m_grid->SetColSize( 0, 100 ); // SetColumnAutosizer() will use these for minimum size
172 m_grid->SetColSize( 1, 80 );
173 m_grid->SetColLabelValue( 0, _( "Key" ) );
174 m_grid->SetColLabelValue( 1, _( "Value" ) );
175 m_grid->SetColLabelValue( 2, _( "Extant" ) );
176 m_grid->HideCol( 2 );
177 m_grid->SetRowLabelSize( 0 );
178 m_grid->SetupColumnAutosizer( 1 );
179
180 wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
181 wxButton* okButton = new wxButton( this, wxID_OK, _( "OK" ) );
182 okButton->SetDefault();
183 buttonSizer->AddButton( okButton );
184 buttonSizer->Realize();
185
186 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
187 sizer->Add( m_filterCtrl, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5 );
188 sizer->Add( m_grid, 1, wxEXPAND | wxALL, 5 );
189 sizer->Add( buttonSizer, 0, wxEXPAND | wxALL, 5 );
190 SetSizer( sizer );
191
192 wxDisplay display( wxDisplay::GetFromWindow( this ) );
193 wxRect displayRect = display.GetClientArea();
194
195 SetMinSize( wxSize( 500, 300 ) );
196 SetMaxSize( wxSize( displayRect.GetWidth() - 100, displayRect.GetHeight() - 100 ) );
197 SetSizeHints( wxSize( 700, 500 ) );
198
199 m_grid->Bind( wxEVT_GRID_CELL_CHANGED, &DIALOG_EDIT_CFG::OnCellChange, this );
200 m_grid->Bind( wxEVT_GRID_CELL_RIGHT_CLICK, &DIALOG_EDIT_CFG::OnCellRightClick, this );
201 m_grid->Bind( wxEVT_GRID_CELL_LEFT_DCLICK, &DIALOG_EDIT_CFG::OnCellLeftDClick, this );
202 m_filterCtrl->Bind( wxEVT_TEXT, &DIALOG_EDIT_CFG::OnFilterChanged, this );
203 m_filterCtrl->Bind( wxEVT_SEARCHCTRL_CANCEL_BTN, &DIALOG_EDIT_CFG::OnFilterChanged, this );
204 Bind( wxEVT_SIZE, &DIALOG_EDIT_CFG::OnSize, this );
205
206 m_contextRow = -1;
207
208 Layout();
209 Centre();
210}
211
212
214{
215 m_allEntries.clear();
216
217 for( const std::unique_ptr<PARAM_CFG>& entry : ADVANCED_CFG::GetCfg().GetEntries() )
218 {
219 ConfigEntry cfg;
220 cfg.key = entry->m_Ident;
221 cfg.value = paramValueString( *entry );
222 wxString def = paramDefaultString( *entry );
223 cfg.extant = ( def == cfg.value ? wxS( "0" ) : wxS( "1" ) );
224 m_allEntries.push_back( cfg );
225 }
226
227 std::sort( m_allEntries.begin(), m_allEntries.end(),
228 []( const ConfigEntry& a, const ConfigEntry& b )
229 {
230 return a.key.CmpNoCase( b.key ) < 0;
231 } );
232
233 applyFilter();
234
235 return true;
236}
237
238
240{
241 if( !m_grid->CommitPendingChanges() )
242 return false;
243
244 saveSettings();
245 return true;
246}
247
248
250{
251 int rows = m_grid->GetNumberRows();
252
253 for( int row = 0; row < rows; ++row )
254 {
255 wxString key = m_grid->GetCellValue( row, 0 );
256 wxString val = m_grid->GetCellValue( row, 1 );
257 wxString ext = m_grid->GetCellValue( row, 2 );
258
259 if( key.IsEmpty() || ext != wxS( "1" ) )
260 continue;
261
262 for( const std::unique_ptr<PARAM_CFG>& entry : ADVANCED_CFG::GetCfg().GetEntries() )
263 {
264 if( entry->m_Ident == key )
265 {
266 writeParam( *entry, val );
267 break;
268 }
269 }
270 }
271
272 ADVANCED_CFG& adv = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() );
273 adv.Save();
274}
275
276
277void DIALOG_EDIT_CFG::OnCellChange( wxGridEvent& aEvent )
278{
279 int row = aEvent.GetRow();
280 int col = aEvent.GetCol();
281
282 if( col == 0 || col == 1 )
283 {
284 m_grid->SetCellValue( row, 2, wxS( "1" ) );
285 updateRowAppearance( row );
286
287 wxString key = m_grid->GetCellValue( row, 0 );
288 wxString value = m_grid->GetCellValue( row, 1 );
289
290 for( ConfigEntry& entry : m_allEntries )
291 {
292 if( entry.key == key )
293 {
294 entry.value = value;
295 entry.extant = wxS( "1" );
296 break;
297 }
298 }
299 }
300
301 saveSettings();
302
303 aEvent.Skip();
304}
305
306
307void DIALOG_EDIT_CFG::OnCellRightClick( wxGridEvent& aEvent )
308{
309 m_contextRow = aEvent.GetRow();
310 wxMenu menu;
311 menu.Append( wxID_ANY, _( "Reset to default" ) );
312 menu.Bind( wxEVT_MENU, &DIALOG_EDIT_CFG::OnResetDefault, this );
313 PopupMenu( &menu );
314 menu.Unbind( wxEVT_MENU, &DIALOG_EDIT_CFG::OnResetDefault, this );
315}
316
317
318void DIALOG_EDIT_CFG::OnResetDefault( wxCommandEvent& aEvent )
319{
320 if( m_contextRow < 0 )
321 return;
322
323 wxString key = m_grid->GetCellValue( m_contextRow, 0 );
324 wxString def;
325
326 for( const std::unique_ptr<PARAM_CFG>& entry : ADVANCED_CFG::GetCfg().GetEntries() )
327 {
328 if( entry->m_Ident == key )
329 {
330 def = paramDefaultString( *entry );
331 break;
332 }
333 }
334
335 m_grid->SetCellValue( m_contextRow, 1, def );
336 m_grid->SetCellValue( m_contextRow, 2, wxS( "0" ) );
338 saveSettings();
339}
340
341
343{
344 bool ext = m_grid->GetCellValue( aRow, 2 ) == wxS( "1" );
345 wxFont font = m_grid->GetCellFont( aRow, 0 );
346 font.SetWeight( ext ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL );
347 m_grid->SetCellFont( aRow, 0, font );
348 m_grid->SetCellFont( aRow, 1, font );
349}
350
351
352void DIALOG_EDIT_CFG::OnFilterChanged( wxCommandEvent& aEvent )
353{
354 m_filterText = m_filterCtrl->GetValue();
355 applyFilter();
356 aEvent.Skip();
357}
358
359
361{
362 if( m_grid->GetNumberRows() > 0 )
363 m_grid->DeleteRows( 0, m_grid->GetNumberRows() );
364
365 for( const ConfigEntry& entry : m_allEntries )
366 {
367 if( m_filterText.IsEmpty() || entry.key.Upper().Contains( m_filterText.Upper() ) )
368 {
369 int row = m_grid->GetNumberRows();
370 m_grid->AppendRows( 1 );
371 m_grid->SetCellValue( row, 0, entry.key );
372 m_grid->SetCellValue( row, 1, entry.value );
373 m_grid->SetCellValue( row, 2, entry.extant );
374 m_grid->SetReadOnly( row, 2 );
375 updateRowAppearance( row );
376 }
377 }
378}
379
380
381void DIALOG_EDIT_CFG::OnCellLeftDClick( wxGridEvent& aEvent )
382{
383 int row = aEvent.GetRow();
384 int col = aEvent.GetCol();
385
386 if( col != 1 )
387 {
388 aEvent.Skip();
389 return;
390 }
391
392 wxString key = m_grid->GetCellValue( row, 0 );
393
394 for( const std::unique_ptr<PARAM_CFG>& entry : ADVANCED_CFG::GetCfg().GetEntries() )
395 {
396 if( entry->m_Ident == key && entry->m_Type == paramcfg_id::PARAM_BOOL )
397 {
398 wxString currentValue = m_grid->GetCellValue( row, 1 );
399 bool isTrueValue = currentValue.CmpNoCase( wxS( "true" ) ) == 0
400 || currentValue.CmpNoCase( wxS( "yes" ) ) == 0
401 || currentValue.CmpNoCase( wxS( "1" ) ) == 0;
402
403 wxString newValue = isTrueValue ? wxS( "false" ) : wxS( "true" );
404 m_grid->SetCellValue( row, 1, newValue );
405 m_grid->SetCellValue( row, 2, wxS( "1" ) );
406 updateRowAppearance( row );
407 saveSettings();
408
409 for( ConfigEntry& cfg : m_allEntries )
410 {
411 if( cfg.key == key )
412 {
413 cfg.value = newValue;
414 cfg.extant = wxS( "1" );
415 break;
416 }
417 }
418
419 return;
420 }
421 }
422
423 aEvent.Skip();
424}
425
426
427void DIALOG_EDIT_CFG::OnSize( wxSizeEvent& aEvent )
428{
429 aEvent.Skip();
430}
void Save()
Save the configuration to the configuration file.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void OnSize(wxSizeEvent &aEvent)
DIALOG_EDIT_CFG(wxWindow *aParent)
void OnCellChange(wxGridEvent &aEvent)
void OnCellRightClick(wxGridEvent &aEvent)
bool TransferDataToWindow() override
void OnResetDefault(wxCommandEvent &aEvent)
void OnFilterChanged(wxCommandEvent &aEvent)
wxFileName m_cfgFile
void OnCellLeftDClick(wxGridEvent &aEvent)
void updateRowAppearance(int aRow)
bool TransferDataFromWindow() override
wxSearchCtrl * m_filterCtrl
std::vector< ConfigEntry > m_allEntries
Configuration object for booleans.
bool * m_Pt_param
Pointer to the parameter value.
Configuration object for double precision floating point numbers.
double * m_Pt_param
Pointer to the parameter value.
Configuration object for integers.
int * m_Pt_param
Pointer to the parameter value.
Configuration object for wxString objects.
wxString * m_Pt_param
Pointer to the parameter value.
A base class which establishes the interface functions ReadParam and SaveParam, which are implemented...
paramcfg_id m_Type
Type of parameter.
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
Definition paths.cpp:624
@ PARAM_WXSTRING
@ PARAM_INT
@ PARAM_DOUBLE
@ PARAM_BOOL
static wxString paramValueString(const PARAM_CFG &aParam)
static void writeParam(PARAM_CFG &aParam, const wxString &aValue)
static wxString paramDefaultString(const PARAM_CFG &aParam)
#define _(s)