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