844 lines
30 KiB
C++
844 lines
30 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
|
|
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation, either version 3 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <set>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
#include <paths.h>
|
|
#include <search_stack.h>
|
|
#include <settings/settings_manager.h>
|
|
#include <settings/common_settings.h>
|
|
#include <settings/json_settings_internals.h>
|
|
#include <settings/parameters.h>
|
|
#include <systemdirsappend.h>
|
|
#include <trace_helpers.h>
|
|
#include <wx/config.h>
|
|
#include <wx/log.h>
|
|
#include <wx/regex.h>
|
|
|
|
|
|
///! The following environment variables will never be migrated from a previous version
|
|
const std::set<wxString> envVarBlacklist =
|
|
{
|
|
wxT( "KICAD7_SYMBOL_DIR" ),
|
|
wxT( "KICAD7_FOOTPRINT_DIR" ),
|
|
wxT( "KICAD7_TEMPLATES_DIR" ),
|
|
wxT( "KICAD7_3DMODEL_DIR" )
|
|
};
|
|
|
|
|
|
///! Update the schema version whenever a migration is required
|
|
const int commonSchemaVersion = 3;
|
|
|
|
COMMON_SETTINGS::COMMON_SETTINGS() :
|
|
JSON_SETTINGS( "kicad_common", SETTINGS_LOC::USER, commonSchemaVersion ),
|
|
m_Appearance(),
|
|
m_Backup(),
|
|
m_Env(),
|
|
m_Input(),
|
|
m_Graphics(),
|
|
m_Session(),
|
|
m_System(),
|
|
m_DoNotShowAgain(),
|
|
m_NetclassPanel(),
|
|
m_PackageManager()
|
|
{
|
|
/*
|
|
* Automatic dark mode detection works fine on Mac.
|
|
*/
|
|
#if defined( __WXGTK__ ) || defined( __WXMSW__ )
|
|
m_params.emplace_back( new PARAM_ENUM<ICON_THEME>( "appearance.icon_theme",
|
|
&m_Appearance.icon_theme, ICON_THEME::AUTO, ICON_THEME::LIGHT, ICON_THEME::AUTO ) );
|
|
#else
|
|
m_Appearance.icon_theme = ICON_THEME::AUTO;
|
|
#endif
|
|
|
|
/*
|
|
* Automatic icon scaling works fine on Mac. It works mostly fine on MSW, but perhaps not
|
|
* uniformly enough to exclude the explicit controls there.
|
|
*/
|
|
#if defined( __WXGTK__ ) || defined( __WXMSW__ )
|
|
m_params.emplace_back( new PARAM<int>( "appearance.icon_scale",
|
|
&m_Appearance.icon_scale, 0 ) );
|
|
#else
|
|
m_Appearance.icon_scale = 0.0;
|
|
#endif
|
|
|
|
/*
|
|
* Automatic canvas scaling works fine on all supported platforms, so it's no longer exposed as
|
|
* a configuration option.
|
|
*/
|
|
m_Appearance.canvas_scale = 0.0;
|
|
|
|
/*
|
|
* Menu icons are off by default on OSX and on for all other platforms.
|
|
*/
|
|
#ifdef __WXMAC__
|
|
m_params.emplace_back( new PARAM<bool>( "appearance.use_icons_in_menus",
|
|
&m_Appearance.use_icons_in_menus, false ) );
|
|
#else
|
|
m_params.emplace_back( new PARAM<bool>( "appearance.use_icons_in_menus",
|
|
&m_Appearance.use_icons_in_menus, true ) );
|
|
#endif
|
|
|
|
/*
|
|
* Font scaling hacks are only needed on GTK under wxWidgets 3.0.
|
|
*/
|
|
m_Appearance.apply_icon_scale_to_fonts = false;
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "appearance.show_scrollbars",
|
|
&m_Appearance.show_scrollbars, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<double>( "appearance.hicontrast_dimming_factor",
|
|
&m_Appearance.hicontrast_dimming_factor, 0.8f ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "appearance.text_editor_zoom",
|
|
&m_Appearance.text_editor_zoom, 0 ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "auto_backup.enabled", &m_Backup.enabled, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "auto_backup.backup_on_autosave",
|
|
&m_Backup.backup_on_autosave, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "auto_backup.limit_total_files",
|
|
&m_Backup.limit_total_files, 25 ) );
|
|
|
|
m_params.emplace_back( new PARAM<unsigned long long>( "auto_backup.limit_total_size",
|
|
&m_Backup.limit_total_size, 104857600 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "auto_backup.limit_daily_files",
|
|
&m_Backup.limit_daily_files, 5 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "auto_backup.min_interval",
|
|
&m_Backup.min_interval, 300 ) );
|
|
|
|
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "environment.vars",
|
|
[&]() -> nlohmann::json
|
|
{
|
|
nlohmann::json ret = {};
|
|
|
|
for( const std::pair<wxString, ENV_VAR_ITEM> entry : m_Env.vars )
|
|
{
|
|
const ENV_VAR_ITEM& var = entry.second;
|
|
|
|
wxASSERT( entry.first == var.GetKey() );
|
|
|
|
// Default values are never persisted
|
|
if( var.IsDefault() )
|
|
{
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "COMMON_SETTINGS: Env var %s skipping save (default)" ),
|
|
var.GetKey() );
|
|
continue;
|
|
}
|
|
|
|
wxString value = var.GetValue();
|
|
|
|
// Vars that existed in JSON are persisted, but if they were overridden
|
|
// externally, we persist the old value (i.e. the one that was loaded from JSON)
|
|
if( var.GetDefinedExternally() )
|
|
{
|
|
if( var.GetDefinedInSettings() )
|
|
{
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "COMMON_SETTINGS: Env var %s was overridden externally, " )
|
|
"saving previously-loaded value %s",
|
|
var.GetKey(), var.GetSettingsValue() );
|
|
value = var.GetSettingsValue();
|
|
}
|
|
else
|
|
{
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "COMMON_SETTINGS: Env var %s skipping save (external)" ),
|
|
var.GetKey() );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "COMMON_SETTINGS: Saving env var %s = %s" ),
|
|
var.GetKey(), value);
|
|
|
|
std::string key( var.GetKey().ToUTF8() );
|
|
ret[key] = value;
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
[&]( const nlohmann::json& aJson )
|
|
{
|
|
if( !aJson.is_object() )
|
|
return;
|
|
|
|
for( const auto& entry : aJson.items() )
|
|
{
|
|
wxString key = wxString( entry.key().c_str(), wxConvUTF8 );
|
|
wxString val = entry.value().get<wxString>();
|
|
|
|
if( m_Env.vars.count( key ) )
|
|
{
|
|
if( m_Env.vars[key].GetDefinedExternally() )
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "COMMON_SETTINGS: %s is defined externally" ),
|
|
key );
|
|
m_Env.vars[key].SetDefinedInSettings();
|
|
m_Env.vars[key].SetSettingsValue( val );
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "COMMON_SETTINGS: Updating %s: %s -> %s"),
|
|
key, m_Env.vars[key].GetValue(), val );
|
|
m_Env.vars[key].SetValue( val );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "COMMON_SETTINGS: Loaded new var: %s = %s" ),
|
|
key, val );
|
|
m_Env.vars[key] = ENV_VAR_ITEM( key, val );
|
|
}
|
|
|
|
m_Env.vars[key].SetDefinedInSettings();
|
|
m_Env.vars[key].SetSettingsValue( val );
|
|
}
|
|
},
|
|
{} ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.focus_follow_sch_pcb",
|
|
&m_Input.focus_follow_sch_pcb, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.auto_pan", &m_Input.auto_pan, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.auto_pan_acceleration",
|
|
&m_Input.auto_pan_acceleration, 5 ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.center_on_zoom",
|
|
&m_Input.center_on_zoom, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.immediate_actions",
|
|
&m_Input.immediate_actions, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.warp_mouse_on_move",
|
|
&m_Input.warp_mouse_on_move, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.horizontal_pan",
|
|
&m_Input.horizontal_pan, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.hotkey_feedback",
|
|
&m_Input.hotkey_feedback, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.zoom_acceleration",
|
|
&m_Input.zoom_acceleration, false ) );
|
|
|
|
#ifdef __WXMAC__
|
|
int default_zoom_speed = 5;
|
|
#else
|
|
int default_zoom_speed = 1;
|
|
#endif
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.zoom_speed",
|
|
&m_Input.zoom_speed, default_zoom_speed ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.zoom_speed_auto",
|
|
&m_Input.zoom_speed_auto, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_zoom",
|
|
&m_Input.scroll_modifier_zoom, 0 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_pan_h",
|
|
&m_Input.scroll_modifier_pan_h, WXK_CONTROL ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_pan_v",
|
|
&m_Input.scroll_modifier_pan_v, WXK_SHIFT ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "input.reverse_scroll_pan_h",
|
|
&m_Input.reverse_scroll_pan_h, false ) );
|
|
|
|
m_params.emplace_back( new PARAM_ENUM<MOUSE_DRAG_ACTION>( "input.mouse_left",
|
|
&m_Input.drag_left, MOUSE_DRAG_ACTION::DRAG_SELECTED, MOUSE_DRAG_ACTION::DRAG_ANY,
|
|
MOUSE_DRAG_ACTION::SELECT ) );
|
|
|
|
m_params.emplace_back( new PARAM_ENUM<MOUSE_DRAG_ACTION>( "input.mouse_middle",
|
|
&m_Input.drag_middle, MOUSE_DRAG_ACTION::PAN, MOUSE_DRAG_ACTION::SELECT,
|
|
MOUSE_DRAG_ACTION::NONE ) );
|
|
|
|
m_params.emplace_back( new PARAM_ENUM<MOUSE_DRAG_ACTION>( "input.mouse_right",
|
|
&m_Input.drag_right, MOUSE_DRAG_ACTION::PAN, MOUSE_DRAG_ACTION::SELECT,
|
|
MOUSE_DRAG_ACTION::NONE ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "graphics.opengl_antialiasing_mode",
|
|
&m_Graphics.opengl_aa_mode, 1, 0, 2 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "graphics.cairo_antialiasing_mode",
|
|
&m_Graphics.cairo_aa_mode, 0, 0, 2 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "system.autosave_interval",
|
|
&m_System.autosave_interval, 600 ) );
|
|
|
|
#ifdef __WXMAC__
|
|
m_params.emplace_back( new PARAM<wxString>( "system.text_editor",
|
|
&m_System.text_editor, wxS( "/usr/bin/open -e" ) ) );
|
|
#else
|
|
m_params.emplace_back( new PARAM<wxString>( "system.text_editor",
|
|
&m_System.text_editor, wxS( "" ) ) );
|
|
#endif
|
|
|
|
m_params.emplace_back( new PARAM<int>( "system.file_history_size",
|
|
&m_System.file_history_size, 9 ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "system.language",
|
|
&m_System.language, wxS( "Default" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "system.pdf_viewer_name",
|
|
&m_System.pdf_viewer_name, wxS( "" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "system.use_system_pdf_viewer",
|
|
&m_System.use_system_pdf_viewer, true ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "system.working_dir",
|
|
&m_System.working_dir, wxS( "" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "system.clear_3d_cache_interval",
|
|
&m_System.clear_3d_cache_interval, 30 ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.zone_fill_warning",
|
|
&m_DoNotShowAgain.zone_fill_warning, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.env_var_overwrite_warning",
|
|
&m_DoNotShowAgain.env_var_overwrite_warning, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.scaled_3d_models_warning",
|
|
&m_DoNotShowAgain.scaled_3d_models_warning, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.data_collection_prompt",
|
|
&m_DoNotShowAgain.data_collection_prompt, false ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "session.remember_open_files",
|
|
&m_Session.remember_open_files, false ) );
|
|
|
|
m_params.emplace_back( new PARAM_LIST<wxString>( "session.pinned_symbol_libs",
|
|
&m_Session.pinned_symbol_libs, {} ) );
|
|
|
|
m_params.emplace_back( new PARAM_LIST<wxString>( "session.pinned_fp_libs",
|
|
&m_Session.pinned_fp_libs, {} ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "netclass_panel.sash_pos",
|
|
&m_NetclassPanel.sash_pos, 160 ) );
|
|
|
|
m_params.emplace_back( new PARAM<int>( "package_manager.sash_pos",
|
|
&m_PackageManager.sash_pos, 380 ) );
|
|
|
|
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "git.repositories",
|
|
[&]() -> nlohmann::json
|
|
{
|
|
nlohmann::json ret = {};
|
|
|
|
for( const GIT_REPOSITORY& repo : m_Git.repositories )
|
|
{
|
|
nlohmann::json repoJson = {};
|
|
|
|
repoJson["name"] = repo.name;
|
|
repoJson["path"] = repo.path;
|
|
repoJson["authType"] = repo.authType;
|
|
repoJson["username"] = repo.username;
|
|
repoJson["ssh_path"] = repo.ssh_path;
|
|
repoJson["active"] = repo.active;
|
|
|
|
ret.push_back( repoJson );
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
[&]( const nlohmann::json& aJson )
|
|
{
|
|
if( !aJson.is_array() )
|
|
return;
|
|
|
|
m_Git.repositories.clear();
|
|
|
|
for( const auto& repoJson : aJson )
|
|
{
|
|
GIT_REPOSITORY repo;
|
|
|
|
repo.name = repoJson["name"].get<wxString>();
|
|
repo.path = repoJson["path"].get<wxString>();
|
|
repo.authType = repoJson["authType"].get<wxString>();
|
|
repo.username = repoJson["username"].get<wxString>();
|
|
repo.ssh_path = repoJson["ssh_path"].get<wxString>();
|
|
repo.active = repoJson["active"].get<bool>();
|
|
repo.checkValid = true;
|
|
|
|
m_Git.repositories.push_back( repo );
|
|
}
|
|
},
|
|
{} ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "git.authorName",
|
|
&m_Git.authorName, wxS( "" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<wxString>( "git.authorEmail",
|
|
&m_Git.authorEmail, wxS( "" ) ) );
|
|
|
|
m_params.emplace_back( new PARAM<bool>( "git.useDefaultAuthor",
|
|
&m_Git.useDefaultAuthor, true ) );
|
|
|
|
|
|
|
|
registerMigration( 0, 1, std::bind( &COMMON_SETTINGS::migrateSchema0to1, this ) );
|
|
registerMigration( 1, 2, std::bind( &COMMON_SETTINGS::migrateSchema1to2, this ) );
|
|
registerMigration( 2, 3, std::bind( &COMMON_SETTINGS::migrateSchema2to3, this ) );
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::migrateSchema0to1()
|
|
{
|
|
/**
|
|
* Schema version 0 to 1:
|
|
*
|
|
* mousewheel_pan is replaced by explicit settings for scroll wheel behavior
|
|
*/
|
|
|
|
nlohmann::json::json_pointer mwp_pointer( "/input/mousewheel_pan"_json_pointer );
|
|
|
|
bool mwp = false;
|
|
|
|
try
|
|
{
|
|
mwp = m_internals->at( mwp_pointer );
|
|
m_internals->At( "input" ).erase( "mousewheel_pan" );
|
|
}
|
|
catch( ... )
|
|
{
|
|
wxLogTrace( traceSettings, wxT( "COMMON_SETTINGS::Migrate 0->1: mousewheel_pan not found" ) );
|
|
}
|
|
|
|
if( mwp )
|
|
{
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = true;
|
|
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_h" )] = WXK_SHIFT;
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_v" )] = 0;
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_zoom" )] = WXK_CONTROL;
|
|
}
|
|
else
|
|
{
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = false;
|
|
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_h" )] = WXK_CONTROL;
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_v" )] = WXK_SHIFT;
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/scroll_modifier_zoom" )] = 0;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::migrateSchema1to2()
|
|
{
|
|
nlohmann::json::json_pointer v1_pointer( "/input/prefer_select_to_drag"_json_pointer );
|
|
|
|
bool prefer_selection = false;
|
|
|
|
try
|
|
{
|
|
prefer_selection = m_internals->at( v1_pointer );
|
|
m_internals->at( nlohmann::json::json_pointer( "/input"_json_pointer ) ).erase( "prefer_select_to_drag" );
|
|
}
|
|
catch( ... )
|
|
{
|
|
wxLogTrace( traceSettings, wxT( "COMMON_SETTINGS::Migrate 1->2: prefer_select_to_drag not found" ) );
|
|
}
|
|
|
|
if( prefer_selection )
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::SELECT;
|
|
else
|
|
( *m_internals )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::DRAG_ANY;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::migrateSchema2to3()
|
|
{
|
|
wxFileName cfgpath;
|
|
cfgpath.AssignDir( PATHS::GetUserSettingsPath() );
|
|
cfgpath.AppendDir( wxT( "3d" ) );
|
|
cfgpath.SetFullName( wxS( "3Dresolver.cfg" ) );
|
|
cfgpath.MakeAbsolute();
|
|
|
|
std::vector<LEGACY_3D_SEARCH_PATH> legacyPaths;
|
|
readLegacy3DResolverCfg( cfgpath.GetFullPath(), legacyPaths );
|
|
|
|
// env variables have a limited allowed character set for names
|
|
wxRegEx nonValidCharsRegex( wxS( "[^A-Z0-9_]+" ), wxRE_ADVANCED );
|
|
|
|
for( const LEGACY_3D_SEARCH_PATH& path : legacyPaths )
|
|
{
|
|
wxString key = path.m_Alias;
|
|
const wxString& val = path.m_Pathvar;
|
|
|
|
// The 3d alias config didnt use the same naming restrictions as real env variables
|
|
// We need to sanitize them
|
|
|
|
// upper case only
|
|
key.MakeUpper();
|
|
// logically swap - with _
|
|
key.Replace( wxS( "-" ), wxS( "_" ) );
|
|
|
|
// remove any other chars
|
|
nonValidCharsRegex.Replace( &key, wxEmptyString );
|
|
|
|
if( !m_Env.vars.count( key ) )
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "COMMON_SETTINGS: Loaded new var: %s = %s" ), key, val );
|
|
m_Env.vars[key] = ENV_VAR_ITEM( key, val );
|
|
}
|
|
}
|
|
|
|
if( cfgpath.FileExists() )
|
|
{
|
|
wxRemoveFile( cfgpath.GetFullPath() );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
|
|
{
|
|
bool ret = true;
|
|
|
|
ret &= fromLegacy<double>( aCfg, "CanvasScale", "appearance.canvas_scale" );
|
|
ret &= fromLegacy<int>( aCfg, "IconScale", "appearance.icon_scale" );
|
|
ret &= fromLegacy<bool>( aCfg, "UseIconsInMenus", "appearance.use_icons_in_menus" );
|
|
ret &= fromLegacy<bool>( aCfg, "ShowEnvVarWarningDialog", "environment.show_warning_dialog" );
|
|
|
|
auto load_env_vars =
|
|
[&]()
|
|
{
|
|
wxString key, value;
|
|
long index = 0;
|
|
nlohmann::json::json_pointer ptr = m_internals->PointerFromString( "environment.vars" );
|
|
|
|
aCfg->SetPath( "EnvironmentVariables" );
|
|
( *m_internals )[ptr] = nlohmann::json( {} );
|
|
|
|
while( aCfg->GetNextEntry( key, index ) )
|
|
{
|
|
if( envVarBlacklist.count( key ) )
|
|
{
|
|
wxLogTrace( traceSettings, wxT( "Migrate Env: %s is blacklisted; skipping." ), key );
|
|
continue;
|
|
}
|
|
|
|
value = aCfg->Read( key, wxEmptyString );
|
|
|
|
if( !value.IsEmpty() )
|
|
{
|
|
ptr.push_back( key.ToStdString() );
|
|
|
|
wxLogTrace( traceSettings, wxT( "Migrate Env: %s=%s" ), ptr.to_string(), value );
|
|
( *m_internals )[ptr] = value.ToUTF8();
|
|
|
|
ptr.pop_back();
|
|
}
|
|
}
|
|
|
|
aCfg->SetPath( ".." );
|
|
};
|
|
|
|
load_env_vars();
|
|
|
|
bool mousewheel_pan = false;
|
|
|
|
if( aCfg->Read( "MousewheelPAN", &mousewheel_pan ) && mousewheel_pan )
|
|
{
|
|
Set( "input.horizontal_pan", true );
|
|
Set( "input.scroll_modifier_pan_h", static_cast<int>( WXK_SHIFT ) );
|
|
Set( "input.scroll_modifier_pan_v", 0 );
|
|
Set( "input.scroll_modifier_zoom", static_cast<int>( WXK_CONTROL ) );
|
|
}
|
|
|
|
ret &= fromLegacy<bool>( aCfg, "AutoPAN", "input.auto_pan" );
|
|
ret &= fromLegacy<bool>( aCfg, "ImmediateActions", "input.immediate_actions" );
|
|
ret &= fromLegacy<bool>( aCfg, "PreferSelectionToDragging", "input.prefer_select_to_drag" );
|
|
ret &= fromLegacy<bool>( aCfg, "MoveWarpsCursor", "input.warp_mouse_on_move" );
|
|
ret &= fromLegacy<bool>( aCfg, "ZoomNoCenter", "input.center_on_zoom" );
|
|
|
|
// This was stored inverted in legacy config
|
|
if( std::optional<bool> value = Get<bool>( "input.center_on_zoom" ) )
|
|
Set( "input.center_on_zoom", !( *value ) );
|
|
|
|
ret &= fromLegacy<int>( aCfg, "OpenGLAntialiasingMode", "graphics.opengl_antialiasing_mode" );
|
|
ret &= fromLegacy<int>( aCfg, "CairoAntialiasingMode", "graphics.cairo_antialiasing_mode" );
|
|
|
|
ret &= fromLegacy<int>( aCfg, "AutoSaveInterval", "system.autosave_interval" );
|
|
ret &= fromLegacyString( aCfg, "Editor", "system.editor_name" );
|
|
ret &= fromLegacy<int>( aCfg, "FileHistorySize", "system.file_history_size" );
|
|
ret &= fromLegacyString( aCfg, "LanguageID", "system.language" );
|
|
ret &= fromLegacyString( aCfg, "PdfBrowserName", "system.pdf_viewer_name" );
|
|
ret &= fromLegacy<bool>( aCfg, "UseSystemBrowser", "system.use_system_pdf_viewer" );
|
|
ret &= fromLegacyString( aCfg, "WorkingDir", "system.working_dir" );
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void COMMON_SETTINGS::InitializeEnvironment()
|
|
{
|
|
auto addVar =
|
|
[&]( const wxString& aKey, const wxString& aDefault )
|
|
{
|
|
m_Env.vars[aKey] = ENV_VAR_ITEM( aKey, aDefault, aDefault );
|
|
|
|
wxString envValue;
|
|
|
|
if( wxGetEnv( aKey, &envValue ) == true && !envValue.IsEmpty() )
|
|
{
|
|
m_Env.vars[aKey].SetValue( envValue );
|
|
m_Env.vars[aKey].SetDefinedExternally();
|
|
wxLogTrace( traceEnvVars,
|
|
wxS( "InitializeEnvironment: Entry %s defined externally as %s" ), aKey,
|
|
envValue );
|
|
}
|
|
else
|
|
{
|
|
wxLogTrace( traceEnvVars, wxS( "InitializeEnvironment: Setting entry %s to default %s" ),
|
|
aKey, aDefault );
|
|
}
|
|
};
|
|
|
|
wxFileName basePath( PATHS::GetStockEDALibraryPath(), wxEmptyString );
|
|
|
|
wxFileName path( basePath );
|
|
path.AppendDir( wxT( "footprints" ) );
|
|
addVar( wxT( "KICAD7_FOOTPRINT_DIR" ), path.GetFullPath() );
|
|
|
|
path = basePath;
|
|
path.AppendDir( wxT( "3dmodels" ) );
|
|
addVar( wxT( "KICAD7_3DMODEL_DIR" ), path.GetFullPath() );
|
|
|
|
addVar( wxT( "KICAD7_TEMPLATE_DIR" ), PATHS::GetStockTemplatesPath() );
|
|
|
|
addVar( wxT( "KICAD_USER_TEMPLATE_DIR" ), PATHS::GetUserTemplatesPath() );
|
|
|
|
addVar( wxT( "KICAD7_3RD_PARTY" ), PATHS::GetDefault3rdPartyPath() );
|
|
|
|
path = basePath;
|
|
path.AppendDir( wxT( "symbols" ) );
|
|
addVar( wxT( "KICAD7_SYMBOL_DIR" ), path.GetFullPath() );
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::readLegacy3DResolverCfg( const wxString& path,
|
|
std::vector<LEGACY_3D_SEARCH_PATH>& aSearchPaths )
|
|
{
|
|
wxFileName cfgpath( path );
|
|
|
|
// This should be the same as wxWidgets 3.0 wxPATH_NORM_ALL which is deprecated in 3.1.
|
|
// There are known issues with environment variable expansion so maybe we should be using
|
|
// our own ExpandEnvVarSubstitutions() here instead.
|
|
cfgpath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
|
|
wxString cfgname = cfgpath.GetFullPath();
|
|
|
|
std::ifstream cfgFile;
|
|
std::string cfgLine;
|
|
|
|
if( !wxFileName::Exists( cfgname ) )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = "no 3D configuration file";
|
|
ostr << " * " << errmsg.ToUTF8() << " '";
|
|
ostr << cfgname.ToUTF8() << "'";
|
|
wxLogTrace( traceSettings, "%s\n", ostr.str().c_str() );
|
|
return false;
|
|
}
|
|
|
|
cfgFile.open( cfgname.ToUTF8() );
|
|
|
|
if( !cfgFile.is_open() )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "Could not open configuration file" );
|
|
ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
return false;
|
|
}
|
|
|
|
int lineno = 0;
|
|
LEGACY_3D_SEARCH_PATH al;
|
|
size_t idx;
|
|
int vnum = 0; // version number
|
|
|
|
while( cfgFile.good() )
|
|
{
|
|
cfgLine.clear();
|
|
std::getline( cfgFile, cfgLine );
|
|
++lineno;
|
|
|
|
if( cfgLine.empty() )
|
|
{
|
|
if( cfgFile.eof() )
|
|
break;
|
|
|
|
continue;
|
|
}
|
|
|
|
if( 1 == lineno && cfgLine.compare( 0, 2, "#V" ) == 0 )
|
|
{
|
|
// extract the version number and parse accordingly
|
|
if( cfgLine.size() > 2 )
|
|
{
|
|
std::istringstream istr;
|
|
istr.str( cfgLine.substr( 2 ) );
|
|
istr >> vnum;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
idx = 0;
|
|
|
|
if( !getLegacy3DHollerith( cfgLine, idx, al.m_Alias ) )
|
|
continue;
|
|
|
|
// Don't add KICAD7_3DMODEL_DIR, one of its legacy equivalents, or KIPRJMOD from a
|
|
// config file. They're system variables are are defined at runtime.
|
|
if( al.m_Alias == wxS( "${KICAD7_3DMODEL_DIR}" ) || al.m_Alias == wxS( "${KIPRJMOD}" )
|
|
|| al.m_Alias == wxS( "$(KIPRJMOD)" ) || al.m_Alias == wxS( "${KISYS3DMOD}" )
|
|
|| al.m_Alias == wxS( "$(KISYS3DMOD)" ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( !getLegacy3DHollerith( cfgLine, idx, al.m_Pathvar ) )
|
|
continue;
|
|
|
|
if( !getLegacy3DHollerith( cfgLine, idx, al.m_Description ) )
|
|
continue;
|
|
|
|
aSearchPaths.push_back( al );
|
|
}
|
|
|
|
cfgFile.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool COMMON_SETTINGS::getLegacy3DHollerith( const std::string& aString, size_t& aIndex,
|
|
wxString& aResult )
|
|
{
|
|
aResult.clear();
|
|
|
|
if( aIndex >= aString.size() )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "bad Hollerith string on line" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
size_t i2 = aString.find( '"', aIndex );
|
|
|
|
if( std::string::npos == i2 )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "missing opening quote mark in config file" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
++i2;
|
|
|
|
if( i2 >= aString.size() )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "invalid entry (unexpected end of line)" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
std::string tnum;
|
|
|
|
while( aString[i2] >= '0' && aString[i2] <= '9' )
|
|
tnum.append( 1, aString[i2++] );
|
|
|
|
if( tnum.empty() || aString[i2++] != ':' )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "bad Hollerith string on line" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
std::istringstream istr;
|
|
istr.str( tnum );
|
|
size_t nchars;
|
|
istr >> nchars;
|
|
|
|
if( ( i2 + nchars ) >= aString.size() )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "invalid entry (unexpected end of line)" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
if( nchars > 0 )
|
|
{
|
|
aResult = wxString::FromUTF8( aString.substr( i2, nchars ).c_str() );
|
|
i2 += nchars;
|
|
}
|
|
|
|
if( i2 >= aString.size() || aString[i2] != '"' )
|
|
{
|
|
std::ostringstream ostr;
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
wxString errmsg = wxS( "missing closing quote mark in config file" );
|
|
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
wxLogTrace( traceSettings, wxS( "%s\n" ), ostr.str().c_str() );
|
|
|
|
return false;
|
|
}
|
|
|
|
aIndex = i2 + 1;
|
|
return true;
|
|
}
|