KiCad PCB EDA Suite
Loading...
Searching...
No Matches
common_settings.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 (C) 2020 Jon Evans <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <set>
22#include <fstream>
23#include <sstream>
24
26#include <env_vars.h>
27#include <paths.h>
28#include <search_stack.h>
32#include <settings/parameters.h>
33#include <systemdirsappend.h>
34#include <trace_helpers.h>
35#include <wx/config.h>
36#include <wx/log.h>
37#include <wx/regex.h>
38#include <wx/tokenzr.h>
39
40
42const wxRegEx versionedEnvVarRegex( wxS( "KICAD[0-9]+_[A-Z0-9_]+(_DIR)?" ) );
43
45const int commonSchemaVersion = 4;
46
50 m_Backup(),
51 m_Env(),
52 m_Input(),
54 m_Graphics(),
55 m_Session(),
56 m_System(),
60 m_Api()
61{
62 /*
63 * Automatic dark mode detection works fine on Mac.
64 */
65#if defined( __WXGTK__ ) || defined( __WXMSW__ )
66 m_params.emplace_back( new PARAM_ENUM<ICON_THEME>( "appearance.icon_theme",
68#else
69 m_Appearance.icon_theme = ICON_THEME::AUTO;
70#endif
71
72 /*
73 * Automatic canvas scaling works fine on all supported platforms, so it's no longer exposed as
74 * a configuration option.
75 */
76 m_Appearance.canvas_scale = 0.0;
77
78 /*
79 * Menu icons are off by default on OSX and on for all other platforms.
80 */
81#ifdef __WXMAC__
82 m_params.emplace_back( new PARAM<bool>( "appearance.use_icons_in_menus",
83 &m_Appearance.use_icons_in_menus, false ) );
84#else
85 m_params.emplace_back( new PARAM<bool>( "appearance.use_icons_in_menus",
86 &m_Appearance.use_icons_in_menus, true ) );
87#endif
88
89 /*
90 * Font scaling hacks are only needed on GTK under wxWidgets 3.0.
91 */
92 m_Appearance.apply_icon_scale_to_fonts = false;
93
94 m_params.emplace_back( new PARAM<bool>( "appearance.show_scrollbars",
95 &m_Appearance.show_scrollbars, false ) );
96
97 m_params.emplace_back( new PARAM<double>( "appearance.hicontrast_dimming_factor",
98 &m_Appearance.hicontrast_dimming_factor, 0.8f ) );
99
100 m_params.emplace_back( new PARAM<int>( "appearance.text_editor_zoom",
101 &m_Appearance.text_editor_zoom, 0 ) );
102
103 m_params.emplace_back( new PARAM<int>( "appearance.toolbar_icon_size",
104 &m_Appearance.toolbar_icon_size, 24, 16, 64 ) );
105
106 m_params.emplace_back( new PARAM<bool>( "appearance.grid_striping",
107 &m_Appearance.grid_striping, false ) );
108
109 m_Appearance.zoom_correction_factor = 1.0;
110 m_params.emplace_back( new PARAM<double>( "appearance.zoom_correction_factor",
111 &m_Appearance.zoom_correction_factor, 1.0, 0.1, 10.0 ) );
112
113 m_params.emplace_back( new PARAM<bool>( "auto_backup.enabled", &m_Backup.enabled, true ) );
114
115 m_params.emplace_back( new PARAM<bool>( "auto_backup.backup_on_autosave",
116 &m_Backup.backup_on_autosave, false ) );
117
118 m_params.emplace_back( new PARAM<int>( "auto_backup.limit_total_files",
119 &m_Backup.limit_total_files, 25 ) );
120
121 m_params.emplace_back( new PARAM<unsigned long long>( "auto_backup.limit_total_size",
122 &m_Backup.limit_total_size, 104857600 ) );
123
124 m_params.emplace_back( new PARAM<int>( "auto_backup.limit_daily_files",
125 &m_Backup.limit_daily_files, 5 ) );
126
127 m_params.emplace_back( new PARAM<int>( "auto_backup.min_interval",
128 &m_Backup.min_interval, 300 ) );
129
130 auto envVarsParam = m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "environment.vars",
131 [&]() -> nlohmann::json
132 {
133 nlohmann::json ret = {};
134
135 for( const std::pair<wxString, ENV_VAR_ITEM> entry : m_Env.vars )
136 {
137 const ENV_VAR_ITEM& var = entry.second;
138
139 wxASSERT( entry.first == var.GetKey() );
140
141 // Default values are never persisted
142 if( var.IsDefault() )
143 {
144 wxLogTrace( traceEnvVars,
145 wxS( "COMMON_SETTINGS: Env var %s skipping save (default)" ),
146 var.GetKey() );
147 continue;
148 }
149
150 wxString value = var.GetValue();
151
152 value.Trim( true ).Trim( false ); // Trim from both sides
153
154 // Vars that existed in JSON are persisted, but if they were overridden
155 // externally, we persist the old value (i.e. the one that was loaded from JSON)
156 if( var.GetDefinedExternally() )
157 {
158 if( var.GetDefinedInSettings() )
159 {
160 wxLogTrace( traceEnvVars,
161 wxS( "COMMON_SETTINGS: Env var %s was overridden "
162 "externally, saving previously-loaded value %s" ),
163 var.GetKey(), var.GetSettingsValue() );
164 value = var.GetSettingsValue();
165 }
166 else
167 {
168 wxLogTrace( traceEnvVars,
169 wxS( "COMMON_SETTINGS: Env var %s skipping save "
170 "(external)" ),
171 var.GetKey() );
172 continue;
173 }
174 }
175
176 wxLogTrace( traceEnvVars,
177 wxS( "COMMON_SETTINGS: Saving env var %s = %s" ),
178 var.GetKey(), value);
179
180 std::string key( var.GetKey().Trim( true ).Trim( false ).ToUTF8() );
181 ret[ std::move( key ) ] = value;
182 }
183
184 return ret;
185 },
186 [&]( const nlohmann::json& aJson )
187 {
188 if( !aJson.is_object() )
189 return;
190
191 for( const auto& entry : aJson.items() )
192 {
193 wxString key = wxString( entry.key().c_str(), wxConvUTF8 ).Trim( true ).Trim( false );
194 wxString val = entry.value().get<wxString>().Trim( true ).Trim( false );
195
196 if( m_Env.vars.count( key ) )
197 {
198 if( m_Env.vars[key].GetDefinedExternally() )
199 {
200 wxLogTrace( traceEnvVars,
201 wxS( "COMMON_SETTINGS: %s is defined externally" ),
202 key );
203 m_Env.vars[key].SetDefinedInSettings();
204 m_Env.vars[key].SetSettingsValue( val );
205 continue;
206 }
207 else
208 {
209 wxLogTrace( traceEnvVars,
210 wxS( "COMMON_SETTINGS: Updating %s: %s -> %s"),
211 key, m_Env.vars[key].GetValue(), val );
212 m_Env.vars[key].SetValue( val );
213 }
214 }
215 else
216 {
217 wxLogTrace( traceEnvVars,
218 wxS( "COMMON_SETTINGS: Loaded new var: %s = %s" ),
219 key, val );
220 m_Env.vars[key] = ENV_VAR_ITEM( key, val );
221 }
222
223 m_Env.vars[key].SetDefinedInSettings();
224 m_Env.vars[key].SetSettingsValue( val );
225 }
226 },
227 {} ) );
228 envVarsParam->SetClearUnknownKeys();
229
230 m_params.emplace_back( new PARAM<bool>( "input.focus_follow_sch_pcb",
231 &m_Input.focus_follow_sch_pcb, false ) );
232
233 m_params.emplace_back( new PARAM<bool>( "input.auto_pan", &m_Input.auto_pan, false ) );
234
235 m_params.emplace_back( new PARAM<int>( "input.auto_pan_acceleration",
236 &m_Input.auto_pan_acceleration, 5 ) );
237
238 m_params.emplace_back( new PARAM<bool>( "input.center_on_zoom",
239 &m_Input.center_on_zoom, true ) );
240
241 m_params.emplace_back( new PARAM<bool>( "input.immediate_actions",
242 &m_Input.immediate_actions, true ) );
243
244 m_params.emplace_back( new PARAM<bool>( "input.warp_mouse_on_move",
245 &m_Input.warp_mouse_on_move, true ) );
246
247 m_params.emplace_back( new PARAM<bool>( "input.horizontal_pan",
248 &m_Input.horizontal_pan, false ) );
249
250 m_params.emplace_back( new PARAM<bool>( "input.hotkey_feedback",
251 &m_Input.hotkey_feedback, true ) );
252
253 m_params.emplace_back( new PARAM<bool>( "input.zoom_acceleration",
254 &m_Input.zoom_acceleration, false ) );
255
256#ifdef __WXMAC__
257 int default_zoom_speed = 5;
258#else
259 int default_zoom_speed = 1;
260#endif
261
262 m_params.emplace_back( new PARAM<int>( "input.zoom_speed",
263 &m_Input.zoom_speed, default_zoom_speed ) );
264
265 m_params.emplace_back( new PARAM<bool>( "input.zoom_speed_auto",
266 &m_Input.zoom_speed_auto, true ) );
267
268 m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_zoom",
269 &m_Input.scroll_modifier_zoom, 0 ) );
270
271 m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_pan_h",
272 &m_Input.scroll_modifier_pan_h, WXK_CONTROL ) );
273
274 m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_pan_v",
275 &m_Input.scroll_modifier_pan_v, WXK_SHIFT ) );
276
277 m_params.emplace_back( new PARAM<int>( "input.motion_pan_modifier",
278 &m_Input.motion_pan_modifier, 0 ) );
279
280 m_params.emplace_back( new PARAM<bool>( "input.reverse_scroll_zoom",
281 &m_Input.reverse_scroll_zoom, false ) );
282
283 m_params.emplace_back( new PARAM<bool>( "input.reverse_scroll_pan_h",
284 &m_Input.reverse_scroll_pan_h, false ) );
285
286 m_params.emplace_back( new PARAM_ENUM<MOUSE_DRAG_ACTION>( "input.mouse_left",
289
290 m_params.emplace_back( new PARAM_ENUM<MOUSE_DRAG_ACTION>( "input.mouse_middle",
293
294 m_params.emplace_back( new PARAM_ENUM<MOUSE_DRAG_ACTION>( "input.mouse_right",
297
298 m_params.emplace_back( new PARAM<int>( "spacemouse.rotate_speed",
299 &m_SpaceMouse.rotate_speed, 5, 1, 10 ) );
300
301 m_params.emplace_back( new PARAM<int>( "spacemouse.pan_speed",
302 &m_SpaceMouse.pan_speed, 5, 1, 10 ) );
303
304 m_params.emplace_back( new PARAM<bool>( "spacemouse.reverse_rotate",
305 &m_SpaceMouse.reverse_rotate, false ) );
306
307 m_params.emplace_back( new PARAM<bool>( "spacemouse.reverse_pan_x",
308 &m_SpaceMouse.reverse_pan_x, false ) );
309
310 m_params.emplace_back( new PARAM<bool>( "spacemouse.reverse_pan_y",
311 &m_SpaceMouse.reverse_pan_y, false ) );
312
313 m_params.emplace_back( new PARAM<bool>( "spacemouse.reverse_zoom",
314 &m_SpaceMouse.reverse_zoom, false ) );
315
316 m_params.emplace_back( new PARAM<int>( "graphics.canvas_type",
317 &m_Graphics.canvas_type, EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL ) );
318
319 m_params.emplace_back( new PARAM<int>( "graphics.antialiasing_mode",
320 &m_Graphics.aa_mode, 2, 0, 2 ) );
321
322 m_params.emplace_back( new PARAM<int>( "system.autosave_interval",
323 &m_System.autosave_interval, 600 ) );
324
325#ifdef __WXMAC__
326 m_params.emplace_back( new PARAM<wxString>( "system.text_editor",
327 &m_System.text_editor, wxS( "/usr/bin/open -e" ) ) );
328#else
329 m_params.emplace_back( new PARAM<wxString>( "system.text_editor",
330 &m_System.text_editor, wxS( "" ) ) );
331#endif
332
333#if defined( __WINDOWS__ )
334 m_params.emplace_back( new PARAM<wxString>( "system.file_explorer",
335 &m_System.file_explorer, wxS( "explorer.exe /n,/select,%F" ) ) );
336#else
337 m_params.emplace_back( new PARAM<wxString>( "system.file_explorer",
338 &m_System.file_explorer, wxS( "" ) ) );
339#endif
340
341 m_params.emplace_back( new PARAM<int>( "system.file_history_size",
342 &m_System.file_history_size, 9 ) );
343
344 m_params.emplace_back( new PARAM<wxString>( "system.language",
345 &m_System.language, wxS( "Default" ) ) );
346
347 m_params.emplace_back( new PARAM<wxString>( "system.pdf_viewer_name",
348 &m_System.pdf_viewer_name, wxS( "" ) ) );
349
350 m_params.emplace_back( new PARAM<bool>( "system.use_system_pdf_viewer",
351 &m_System.use_system_pdf_viewer, true ) );
352
353 m_params.emplace_back( new PARAM<wxString>( "system.working_dir",
354 &m_System.working_dir, wxS( "" ) ) );
355
356 m_params.emplace_back( new PARAM<int>( "system.clear_3d_cache_interval",
357 &m_System.clear_3d_cache_interval, 30 ) );
358
359 m_params.emplace_back( new PARAM<bool>( "do_not_show_again.zone_fill_warning",
360 &m_DoNotShowAgain.zone_fill_warning, false ) );
361
362 m_params.emplace_back( new PARAM<bool>( "do_not_show_again.env_var_overwrite_warning",
363 &m_DoNotShowAgain.env_var_overwrite_warning, false ) );
364
365 m_params.emplace_back( new PARAM<bool>( "do_not_show_again.scaled_3d_models_warning",
366 &m_DoNotShowAgain.scaled_3d_models_warning, false ) );
367
368 m_params.emplace_back( new PARAM<bool>( "do_not_show_again.data_collection_prompt",
369 &m_DoNotShowAgain.data_collection_prompt, false ) );
370
371 m_params.emplace_back( new PARAM<bool>( "do_not_show_again.update_check_prompt",
372 &m_DoNotShowAgain.update_check_prompt, false ) );
373
374 m_params.emplace_back( new PARAM<bool>( "session.remember_open_files",
375 &m_Session.remember_open_files, false ) );
376
377 m_params.emplace_back( new PARAM_LIST<wxString>( "session.pinned_symbol_libs",
378 &m_Session.pinned_symbol_libs, {} ) );
379
380 m_params.emplace_back( new PARAM_LIST<wxString>( "session.pinned_fp_libs",
381 &m_Session.pinned_fp_libs, {} ) );
382
383 m_params.emplace_back( new PARAM_LIST<wxString>( "session.pinned_design_block_libs",
384 &m_Session.pinned_design_block_libs, {} ) );
385
386 m_params.emplace_back( new PARAM<int>( "netclass_panel.sash_pos",
387 &m_NetclassPanel.sash_pos, 160 ) );
388
389 m_params.emplace_back( new PARAM<wxString>( "netclass_panel.eeschema_shown_columns",
390 &m_NetclassPanel.eeschema_visible_columns, "0 11 12 13 14" ) );
391
392 m_params.emplace_back( new PARAM<wxString>( "netclass_panel.pcbnew_shown_columns",
393 &m_NetclassPanel.pcbnew_visible_columns, "0 1 2 3 4 5 6 7 8 9 10" ) );
394
395 m_params.emplace_back( new PARAM<int>( "package_manager.sash_pos",
396 &m_PackageManager.sash_pos, 380 ) );
397
398 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "git.repositories",
399 [&]() -> nlohmann::json
400 {
401 nlohmann::json ret = {};
402
403 for( const GIT_REPOSITORY& repo : m_Git.repositories )
404 {
405 nlohmann::json repoJson = {};
406
407 repoJson["name"] = repo.name;
408 repoJson["path"] = repo.path;
409 repoJson["authType"] = repo.authType;
410 repoJson["username"] = repo.username;
411 repoJson["ssh_path"] = repo.ssh_path;
412 repoJson["active"] = repo.active;
413
414 ret.push_back( repoJson );
415 }
416
417 return ret;
418 },
419 [&]( const nlohmann::json& aJson )
420 {
421 if( !aJson.is_array() )
422 return;
423
424 m_Git.repositories.clear();
425
426 for( const auto& repoJson : aJson )
427 {
428 GIT_REPOSITORY repo;
429
430 repo.name = repoJson["name"].get<wxString>();
431 repo.path = repoJson["path"].get<wxString>();
432 repo.authType = repoJson["authType"].get<wxString>();
433 repo.username = repoJson["username"].get<wxString>();
434 repo.ssh_path = repoJson["ssh_path"].get<wxString>();
435 repo.active = repoJson["active"].get<bool>();
436 repo.checkValid = true;
437
438 m_Git.repositories.push_back( repo );
439 }
440 },
441 {} ) );
442
443 m_params.emplace_back( new PARAM<wxString>( "git.authorName",
444 &m_Git.authorName, wxS( "" ) ) );
445
446 m_params.emplace_back( new PARAM<wxString>( "git.authorEmail",
447 &m_Git.authorEmail, wxS( "" ) ) );
448
449 m_params.emplace_back( new PARAM<bool>( "git.useDefaultAuthor",
450 &m_Git.useDefaultAuthor, true ) );
451
452 m_params.emplace_back( new PARAM<bool>( "git.enableGit",
453 &m_Git.enableGit, true ) );
454
455 m_params.emplace_back( new PARAM<int>( "git.updatInterval",
456 &m_Git.updatInterval, 5 ) );
457
458 m_params.emplace_back( new PARAM<wxString>( "api.interpreter_path",
459 &m_Api.python_interpreter, wxS( "" ) ) );
460
461 m_params.emplace_back( new PARAM<bool>( "api.enable_server",
462 &m_Api.enable_server, false ) );
463
464 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "dialog.controls",
465 [&]() -> nlohmann::json
466 {
467 nlohmann::json ret = nlohmann::json::object();
468
469 for( const auto& dlg : m_dialogControlValues )
470 ret[ dlg.first ] = dlg.second;
471
472 return ret;
473 },
474 [&]( const nlohmann::json& aVal )
475 {
476 m_dialogControlValues.clear();
477
478 if( !aVal.is_object() )
479 return;
480
481 for( auto& [dlgKey, dlgVal] : aVal.items() )
482 {
483 if( !dlgVal.is_object() )
484 continue;
485
486 for( auto& [ctrlKey, ctrlVal] : dlgVal.items() )
487 m_dialogControlValues[ dlgKey ][ ctrlKey ] = ctrlVal;
488 }
489 },
490 nlohmann::json::object() ) );
491
492
493 registerMigration( 0, 1, std::bind( &COMMON_SETTINGS::migrateSchema0to1, this ) );
494 registerMigration( 1, 2, std::bind( &COMMON_SETTINGS::migrateSchema1to2, this ) );
495 registerMigration( 2, 3, std::bind( &COMMON_SETTINGS::migrateSchema2to3, this ) );
496 registerMigration( 3, 4, std::bind( &COMMON_SETTINGS::migrateSchema3to4, this ) );
497}
498
499
501{
507
508 nlohmann::json::json_pointer mwp_pointer( "/input/mousewheel_pan"_json_pointer );
509
510 bool mwp = false;
511
512 try
513 {
514 mwp = m_internals->at( mwp_pointer );
515 m_internals->At( "input" ).erase( "mousewheel_pan" );
516 }
517 catch( ... )
518 {
519 wxLogTrace( traceSettings,
520 wxT( "COMMON_SETTINGS::Migrate 0->1: mousewheel_pan not found" ) );
521 }
522
523 if( mwp )
524 {
525 ( *m_internals )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = true;
526 ( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_h" )] = WXK_SHIFT;
527 ( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_v" )] = 0;
528 ( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_zoom" )] = WXK_CONTROL;
529 }
530 else
531 {
532 ( *m_internals )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = false;
533 ( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_h" )] = WXK_CONTROL;
534 ( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_v" )] = WXK_SHIFT;
535 ( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_zoom" )] = 0;
536 }
537
538 return true;
539}
540
541
543{
544 nlohmann::json::json_pointer v1_pointer( "/input/prefer_select_to_drag"_json_pointer );
545
546 bool prefer_selection = false;
547
548 try
549 {
550 prefer_selection = m_internals->at( v1_pointer );
551 m_internals->at( nlohmann::json::json_pointer( "/input"_json_pointer ) )
552 .erase( "prefer_select_to_drag" );
553 }
554 catch( ... )
555 {
556 wxLogTrace( traceSettings,
557 wxT( "COMMON_SETTINGS::Migrate 1->2: prefer_select_to_drag not found" ) );
558 }
559
560 if( prefer_selection )
561 ( *m_internals )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::SELECT;
562 else
563 ( *m_internals )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::DRAG_ANY;
564
565 return true;
566}
567
568
570{
571 wxFileName cfgpath;
572 cfgpath.AssignDir( PATHS::GetUserSettingsPath() );
573 cfgpath.AppendDir( wxT( "3d" ) );
574 cfgpath.SetFullName( wxS( "3Dresolver.cfg" ) );
575 cfgpath.MakeAbsolute();
576
577 std::vector<LEGACY_3D_SEARCH_PATH> legacyPaths;
578 readLegacy3DResolverCfg( cfgpath.GetFullPath(), legacyPaths );
579
580 // env variables have a limited allowed character set for names
581 wxRegEx nonValidCharsRegex( wxS( "[^A-Z0-9_]+" ), wxRE_ADVANCED );
582
583 for( const LEGACY_3D_SEARCH_PATH& path : legacyPaths )
584 {
585 wxString key = path.m_Alias;
586 const wxString& val = path.m_Pathvar;
587
588 // The 3d alias config didn't use the same naming restrictions as real env variables
589 // We need to sanitize them
590
591 // upper case only
592 key.MakeUpper();
593
594 // logically swap - with _
595 key.Replace( wxS( "-" ), wxS( "_" ) );
596
597 // remove any other chars
598 nonValidCharsRegex.Replace( &key, wxEmptyString );
599
600 if( !m_Env.vars.count( key ) )
601 {
602 wxLogTrace( traceEnvVars, wxS( "COMMON_SETTINGS: Loaded new var: %s = %s" ), key, val );
603 m_Env.vars[key] = ENV_VAR_ITEM( key, val );
604 }
605 }
606
607 if( cfgpath.FileExists() )
608 {
609 wxRemoveFile( cfgpath.GetFullPath() );
610 }
611
612 return true;
613}
614
615
617{
618 // >= 10 = add 1
619 try
620 {
621 // Update netclass panel shown columns for eeschema
622 const nlohmann::json::json_pointer v3_pointer_eeschema( "/netclass_panel/eeschema_shown_columns"_json_pointer );
623 wxString eeSchemaColumnList_old = m_internals->at( v3_pointer_eeschema );
624
625 wxStringTokenizer eeSchemaShownTokens( eeSchemaColumnList_old, " \t\r\n" );
626 wxString eeSchemaColumnList_new;
627
628 while( eeSchemaShownTokens.HasMoreTokens() )
629 {
630 long colNumber;
631 eeSchemaShownTokens.GetNextToken().ToLong( &colNumber );
632
633 if( colNumber >= 10 )
634 ++colNumber;
635
636 eeSchemaColumnList_new += wxString::Format( wxT( "%ld " ), colNumber );
637 }
638
639 eeSchemaColumnList_new.Trim( true );
640 eeSchemaColumnList_new.Trim( false );
641
642 m_internals->at( v3_pointer_eeschema ) = eeSchemaColumnList_new.ToUTF8();
643
644 // Update netclass panel shown columns for pcbnew
645 const nlohmann::json::json_pointer v3_pointer_pcbnew( "/netclass_panel/pcbnew_shown_columns"_json_pointer );
646 wxString pcbnewColumnList_old = m_internals->at( v3_pointer_pcbnew );
647
648 wxStringTokenizer pcbnewShownTokens( pcbnewColumnList_old, " \t\r\n" );
649 wxString pcbnewColumnList_new;
650
651 while( pcbnewShownTokens.HasMoreTokens() )
652 {
653 long colNumber;
654 pcbnewShownTokens.GetNextToken().ToLong( &colNumber );
655
656 if( colNumber >= 10 )
657 ++colNumber;
658
659 pcbnewColumnList_new += wxString::Format( wxT( "%ld " ), colNumber );
660 }
661
662 pcbnewColumnList_new.Trim( true );
663 pcbnewColumnList_new.Trim( false );
664
665 m_internals->at( v3_pointer_pcbnew ) = pcbnewColumnList_new.ToUTF8();
666 }
667 catch( ... )
668 {
669 wxLogTrace( traceSettings, wxT( "COMMON_SETTINGS::Migrate 3->4: /netclass_panel/shown_columns not found" ) );
670 }
671
672 return true;
673}
674
675
676bool COMMON_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
677{
678 bool ret = true;
679
680 ret &= fromLegacy<double>( aCfg, "CanvasScale", "appearance.canvas_scale" );
681 ret &= fromLegacy<int>( aCfg, "IconScale", "appearance.icon_scale" );
682 ret &= fromLegacy<bool>( aCfg, "UseIconsInMenus", "appearance.use_icons_in_menus" );
683 ret &= fromLegacy<bool>( aCfg, "ShowEnvVarWarningDialog", "environment.show_warning_dialog" );
684
685 auto load_env_vars =
686 [&]()
687 {
688 wxString key, value;
689 long index = 0;
690 nlohmann::json::json_pointer ptr = m_internals->PointerFromString( "environment.vars" );
691
692 aCfg->SetPath( "EnvironmentVariables" );
693 ( *m_internals )[ptr] = nlohmann::json( {} );
694
695 while( aCfg->GetNextEntry( key, index ) )
696 {
697 if( versionedEnvVarRegex.Matches( key ) )
698 {
699 wxLogTrace( traceSettings,
700 wxT( "Migrate Env: %s is blacklisted; skipping." ), key );
701 continue;
702 }
703
704 value = aCfg->Read( key, wxEmptyString );
705
706 if( !value.IsEmpty() )
707 {
708 ptr.push_back( key.ToStdString() );
709
710 wxLogTrace( traceSettings, wxT( "Migrate Env: %s=%s" ),
711 ptr.to_string(), value );
712 ( *m_internals )[ptr] = value.ToUTF8();
713
714 ptr.pop_back();
715 }
716 }
717
718 aCfg->SetPath( ".." );
719 };
720
721 load_env_vars();
722
723 bool mousewheel_pan = false;
724
725 if( aCfg->Read( "MousewheelPAN", &mousewheel_pan ) && mousewheel_pan )
726 {
727 Set( "input.horizontal_pan", true );
728 Set( "input.scroll_modifier_pan_h", static_cast<int>( WXK_SHIFT ) );
729 Set( "input.scroll_modifier_pan_v", 0 );
730 Set( "input.scroll_modifier_zoom", static_cast<int>( WXK_CONTROL ) );
731 }
732
733 ret &= fromLegacy<bool>( aCfg, "AutoPAN", "input.auto_pan" );
734 ret &= fromLegacy<bool>( aCfg, "ImmediateActions", "input.immediate_actions" );
735 ret &= fromLegacy<bool>( aCfg, "PreferSelectionToDragging", "input.prefer_select_to_drag" );
736 ret &= fromLegacy<bool>( aCfg, "MoveWarpsCursor", "input.warp_mouse_on_move" );
737 ret &= fromLegacy<bool>( aCfg, "ZoomNoCenter", "input.center_on_zoom" );
738
739 // This was stored inverted in legacy config
740 if( std::optional<bool> value = Get<bool>( "input.center_on_zoom" ) )
741 Set( "input.center_on_zoom", !( *value ) );
742
743 ret &= fromLegacy<int>( aCfg, "OpenGLAntialiasingMode", "graphics.opengl_antialiasing_mode" );
744 ret &= fromLegacy<int>( aCfg, "CairoAntialiasingMode", "graphics.cairo_antialiasing_mode" );
745
746 ret &= fromLegacy<int>( aCfg, "AutoSaveInterval", "system.autosave_interval" );
747 ret &= fromLegacyString( aCfg, "Editor", "system.editor_name" );
748 ret &= fromLegacy<int>( aCfg, "FileHistorySize", "system.file_history_size" );
749 ret &= fromLegacyString( aCfg, "LanguageID", "system.language" );
750 ret &= fromLegacyString( aCfg, "PdfBrowserName", "system.pdf_viewer_name" );
751 ret &= fromLegacy<bool>( aCfg, "UseSystemBrowser", "system.use_system_pdf_viewer" );
752 ret &= fromLegacyString( aCfg, "WorkingDir", "system.working_dir" );
753
754 return ret;
755}
756
757
759{
760 auto addVar =
761 [&]( const wxString& aKey, const wxString& aDefault )
762 {
763 m_Env.vars[aKey] = ENV_VAR_ITEM( aKey, aDefault, aDefault );
764
765 wxString envValue;
766
767 if( wxGetEnv( aKey, &envValue ) == true && !envValue.IsEmpty() )
768 {
769 m_Env.vars[aKey].SetValue( envValue );
770 m_Env.vars[aKey].SetDefinedExternally();
771 wxLogTrace( traceEnvVars,
772 wxS( "InitializeEnvironment: Entry %s defined externally as %s" ), aKey,
773 envValue );
774 }
775 else
776 {
777 wxLogTrace( traceEnvVars, wxS( "InitializeEnvironment: Setting entry %s to "
778 "default %s" ),
779 aKey, aDefault );
780 }
781 };
782
783 wxFileName basePath( PATHS::GetStockEDALibraryPath(), wxEmptyString );
784
785 wxFileName path( basePath );
786 path.AppendDir( wxT( "footprints" ) );
787 addVar( ENV_VAR::GetVersionedEnvVarName( wxS( "FOOTPRINT_DIR" ) ), path.GetFullPath() );
788
789 path = basePath;
790 path.AppendDir( wxT( "3dmodels" ) );
791 addVar( ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ), path.GetFullPath() );
792
793 addVar( ENV_VAR::GetVersionedEnvVarName( wxS( "TEMPLATE_DIR" ) ),
795
796 addVar( wxT( "KICAD_USER_TEMPLATE_DIR" ), PATHS::GetUserTemplatesPath() );
797
798 addVar( ENV_VAR::GetVersionedEnvVarName( wxS( "3RD_PARTY" ) ),
800
801 path = basePath;
802 path.AppendDir( wxT( "symbols" ) );
803 addVar( ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) ), path.GetFullPath() );
804
805 path = basePath;
806 path.AppendDir( wxT( "blocks" ) );
807 addVar( ENV_VAR::GetVersionedEnvVarName( wxS( "DESIGN_BLOCK_DIR" ) ), path.GetFullPath() );
808}
809
810
812 std::vector<LEGACY_3D_SEARCH_PATH>& aSearchPaths )
813{
814 wxFileName cfgpath( path );
815
816 // This should be the same as wxWidgets 3.0 wxPATH_NORM_ALL which is deprecated in 3.1.
817 // There are known issues with environment variable expansion so maybe we should be using
818 // our own ExpandEnvVarSubstitutions() here instead.
819 cfgpath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
820 wxString cfgname = cfgpath.GetFullPath();
821
822 std::ifstream cfgFile;
823 std::string cfgLine;
824
825 if( !wxFileName::Exists( cfgname ) )
826 {
827 std::ostringstream ostr;
828 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
829 wxString errmsg = "no 3D configuration file";
830 ostr << " * " << errmsg.ToUTF8() << " '";
831 ostr << cfgname.ToUTF8() << "'";
832 wxLogTrace( traceSettings, "%s\n", ostr.str().c_str() );
833 return false;
834 }
835
836 cfgFile.open( cfgname.ToUTF8() );
837
838 if( !cfgFile.is_open() )
839 {
840 std::ostringstream ostr;
841 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
842 wxString errmsg = wxS( "Could not open configuration file" );
843 ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
844 wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
845 return false;
846 }
847
848 int lineno = 0;
850 size_t idx;
851 int vnum = 0; // version number
852
853 while( cfgFile.good() )
854 {
855 cfgLine.clear();
856 std::getline( cfgFile, cfgLine );
857 ++lineno;
858
859 if( cfgLine.empty() )
860 {
861 if( cfgFile.eof() )
862 break;
863
864 continue;
865 }
866
867 if( 1 == lineno && cfgLine.compare( 0, 2, "#V" ) == 0 )
868 {
869 // extract the version number and parse accordingly
870 if( cfgLine.size() > 2 )
871 {
872 std::istringstream istr;
873 istr.str( cfgLine.substr( 2 ) );
874 istr >> vnum;
875 }
876
877 continue;
878 }
879
880 idx = 0;
881
882 if( !getLegacy3DHollerith( cfgLine, idx, al.m_Alias ) )
883 continue;
884
885 // Don't add KICADn_3DMODEL_DIR, one of its legacy equivalents, or KIPRJMOD from a
886 // config file. They're system variables which are defined at runtime.
887 wxString versionedPath = wxString::Format( wxS( "${%s}" ),
888 ENV_VAR::GetVersionedEnvVarName( wxS( "3DMODEL_DIR" ) ) );
889
890 if( al.m_Alias == versionedPath || al.m_Alias == wxS( "${KIPRJMOD}" )
891 || al.m_Alias == wxS( "$(KIPRJMOD)" ) || al.m_Alias == wxS( "${KISYS3DMOD}" )
892 || al.m_Alias == wxS( "$(KISYS3DMOD)" ) )
893 {
894 continue;
895 }
896
897 if( !getLegacy3DHollerith( cfgLine, idx, al.m_Pathvar ) )
898 continue;
899
900 if( !getLegacy3DHollerith( cfgLine, idx, al.m_Description ) )
901 continue;
902
903 aSearchPaths.push_back( al );
904 }
905
906 cfgFile.close();
907
908 return true;
909}
910
911
912bool COMMON_SETTINGS::getLegacy3DHollerith( const std::string& aString, size_t& aIndex,
913 wxString& aResult )
914{
915 aResult.clear();
916
917 if( aIndex >= aString.size() )
918 {
919 std::ostringstream ostr;
920 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
921 wxString errmsg = wxS( "bad Hollerith string on line" );
922 ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
923 wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
924
925 return false;
926 }
927
928 size_t i2 = aString.find( '"', aIndex );
929
930 if( std::string::npos == i2 )
931 {
932 std::ostringstream ostr;
933 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
934 wxString errmsg = wxS( "missing opening quote mark in config file" );
935 ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
936 wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
937
938 return false;
939 }
940
941 ++i2;
942
943 if( i2 >= aString.size() )
944 {
945 std::ostringstream ostr;
946 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
947 wxString errmsg = wxS( "invalid entry (unexpected end of line)" );
948 ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
949 wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
950
951 return false;
952 }
953
954 std::string tnum;
955
956 while( aString[i2] >= '0' && aString[i2] <= '9' )
957 tnum.append( 1, aString[i2++] );
958
959 if( tnum.empty() || aString[i2++] != ':' )
960 {
961 std::ostringstream ostr;
962 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
963 wxString errmsg = wxS( "bad Hollerith string on line" );
964 ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
965 wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
966
967 return false;
968 }
969
970 std::istringstream istr;
971 istr.str( tnum );
972 size_t nchars;
973 istr >> nchars;
974
975 if( ( i2 + nchars ) >= aString.size() )
976 {
977 std::ostringstream ostr;
978 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
979 wxString errmsg = wxS( "invalid entry (unexpected end of line)" );
980 ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
981 wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
982
983 return false;
984 }
985
986 if( nchars > 0 )
987 {
988 aResult = wxString::FromUTF8( aString.substr( i2, nchars ).c_str() );
989 i2 += nchars;
990 }
991
992 if( i2 >= aString.size() || aString[i2] != '"' )
993 {
994 std::ostringstream ostr;
995 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
996 wxString errmsg = wxS( "missing closing quote mark in config file" );
997 ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
998 wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
999
1000 return false;
1001 }
1002
1003 aIndex = i2 + 1;
1004 return true;
1005}
NETCLASS_PANEL m_NetclassPanel
SPACEMOUSE m_SpaceMouse
APPEARANCE m_Appearance
static bool getLegacy3DHollerith(const std::string &aString, size_t &aIndex, wxString &aResult)
bool readLegacy3DResolverCfg(const wxString &aPath, std::vector< LEGACY_3D_SEARCH_PATH > &aSearchPaths)
PACKAGE_MANAGER m_PackageManager
void InitializeEnvironment()
Creates the built-in environment variables and sets their default values.
AUTO_BACKUP m_Backup
DO_NOT_SHOW_AGAIN m_DoNotShowAgain
virtual bool MigrateFromLegacy(wxConfigBase *aLegacyConfig) override
Migrates from wxConfig to JSON-based configuration.
@ GAL_TYPE_OPENGL
OpenGL implementation.
KiCad uses environment variables internally for determining the base paths for libraries,...
bool fromLegacyString(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy wxConfig string value to a given JSON pointer value.
bool fromLegacy(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy wxConfig value to a given JSON pointer value.
void Set(const std::string &aPath, ValueType aVal)
Stores a value into the JSON document Will throw an exception if ValueType isn't something that the l...
std::optional< ValueType > Get(const std::string &aPath) const
Fetches a value from within the JSON document.
std::vector< PARAM_BASE * > m_params
The list of parameters (owned by this object)
JSON_SETTINGS(const wxString &aFilename, SETTINGS_LOC aLocation, int aSchemaVersion)
std::unique_ptr< JSON_SETTINGS_INTERNALS > m_internals
Stores an enum as an integer.
Definition parameters.h:229
Like a normal param, but with custom getter and setter functions.
Definition parameters.h:296
static wxString GetUserTemplatesPath()
Gets the user path for custom templates.
Definition paths.cpp:70
static wxString GetStockEDALibraryPath()
Gets the stock (install) EDA library data path, which is the base path for templates,...
Definition paths.cpp:241
static wxString GetDefault3rdPartyPath()
Gets the default path for PCM packages.
Definition paths.cpp:125
static wxString GetStockTemplatesPath()
Gets the stock (install) templates path.
Definition paths.cpp:307
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
Definition paths.cpp:592
const int commonSchemaVersion
! Update the schema version whenever a migration is required
const wxRegEx versionedEnvVarRegex(wxS("KICAD[0-9]+_[A-Z0-9_]+(_DIR)?"))
! The following environment variables will never be migrated from a previous version
Functions related to environment variables, including help functions.
const wxChar *const traceEnvVars
Flag to enable debug output of environment variable operations.
SETTINGS_LOC
@ USER
The main config directory (e.g. ~/.config/kicad/)
#define traceSettings
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
Definition env_vars.cpp:77
System directories search utilities.
wxLogTrace helper definitions.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition wx_filename.h:39