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