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