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