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