diff --git a/common/dialogs/dialog_configure_paths.cpp b/common/dialogs/dialog_configure_paths.cpp index a70389196b..9058140bfd 100644 --- a/common/dialogs/dialog_configure_paths.cpp +++ b/common/dialogs/dialog_configure_paths.cpp @@ -229,19 +229,17 @@ bool DIALOG_CONFIGURE_PATHS::TransferDataFromWindow() // Environment variables - ENV_VAR_MAP envVarMap; + ENV_VAR_MAP& envVarMap = Pgm().GetLocalEnvVariables(); for( int row = 0; row < m_EnvVars->GetNumberRows(); ++row ) { - wxString name = m_EnvVars->GetCellValue( row, TV_NAME_COL ); - wxString path = m_EnvVars->GetCellValue( row, TV_VALUE_COL ); - wxString external = m_EnvVars->GetCellValue( row, TV_FLAG_COL ); - ENV_VAR_ITEM var( path ); + wxString name = m_EnvVars->GetCellValue( row, TV_NAME_COL ); + wxString path = m_EnvVars->GetCellValue( row, TV_VALUE_COL ); + bool external = !m_EnvVars->GetCellValue( row, TV_FLAG_COL ).IsEmpty(); - if( external.Length() ) + if( external ) { // Don't check for consistency on external variables, just use them as-is - var.SetDefinedExternally( true ); } else if( name.IsEmpty() ) { @@ -260,10 +258,13 @@ bool DIALOG_CONFIGURE_PATHS::TransferDataFromWindow() return false; } - envVarMap[ name ] = var; + if( envVarMap.count( name ) ) + envVarMap.at( name ).SetValue( path ); + else + envVarMap[ name ] = ENV_VAR_ITEM( name, path ); } - Pgm().SetLocalEnvVariables( envVarMap ); + Pgm().SetLocalEnvVariables(); // 3D search paths diff --git a/common/pgm_base.cpp b/common/pgm_base.cpp index 049c38abc6..9e8978f48d 100644 --- a/common/pgm_base.cpp +++ b/common/pgm_base.cpp @@ -278,148 +278,10 @@ bool PGM_BASE::InitPgm() if( !m_settings_manager->IsOK() ) return false; - wxFileName baseSharePath; - baseSharePath.AssignDir( PATHS::GetStockEDALibraryPath() ); - - // KICAD6_FOOTPRINT_DIR - wxString envVarName = wxT( "KICAD6_FOOTPRINT_DIR" ); - ENV_VAR_ITEM envVarItem; - wxString envValue; - wxFileName tmpFileName; - - if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) - { - tmpFileName.AssignDir( envValue ); - envVarItem.SetDefinedExternally( true ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Found entry %s externally", envVarName ); - } - else - { - tmpFileName = baseSharePath; - tmpFileName.AppendDir( "modules" ); - envVarItem.SetDefinedExternally( false ); - } - - envVarItem.SetValue( tmpFileName.GetPath() ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Setting entry %s = %s", - envVarName, envVarItem.GetValue() ); - m_local_env_vars[ envVarName ] = envVarItem; - - // KICAD6_3DMODEL_DIR - envVarName = wxT( "KICAD6_3DMODEL_DIR" ); - - if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) - { - tmpFileName.AssignDir( envValue ); - envVarItem.SetDefinedExternally( true ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Found entry %s externally", envVarName ); - } - else - { - tmpFileName = baseSharePath; - tmpFileName.AppendDir( "3dmodels" ); - envVarItem.SetDefinedExternally( false ); - } - - envVarItem.SetValue( tmpFileName.GetFullPath() ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Setting entry %s = %s", - envVarName, envVarItem.GetValue() ); - m_local_env_vars[ envVarName ] = envVarItem; - - // KICAD6_TEMPLATE_DIR - envVarName = "KICAD6_TEMPLATE_DIR"; - - if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) - { - tmpFileName.AssignDir( envValue ); - envVarItem.SetDefinedExternally( true ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Found entry %s externally", envVarName ); - } - else - { - // Attempt to find the best default template path. - SEARCH_STACK bases; - SEARCH_STACK templatePaths; - - SystemDirsAppend( &bases ); - - for( unsigned i = 0; i < bases.GetCount(); ++i ) - { - wxFileName fn( bases[i], wxEmptyString ); - - // Add KiCad template file path to search path list. - fn.AppendDir( "template" ); - - // Only add path if exists and can be read by the user. - if( fn.DirExists() && fn.IsDirReadable() ) - { - wxLogTrace( tracePathsAndFiles, "Checking template path '%s' exists", - fn.GetPath() ); - templatePaths.AddPaths( fn.GetPath() ); - } - } - - if( templatePaths.IsEmpty() ) - { - tmpFileName = baseSharePath; - tmpFileName.AppendDir( "template" ); - } - else - { - // Take the first one. There may be more but this will likely be the best option. - tmpFileName.AssignDir( templatePaths[0] ); - } - - envVarItem.SetDefinedExternally( false ); - } - - envVarItem.SetValue( tmpFileName.GetPath() ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Setting entry %s = %s", envVarName, - envVarItem.GetValue() ); - m_local_env_vars[ envVarName ] = envVarItem; - - // KICAD_USER_TEMPLATE_DIR - envVarName = "KICAD_USER_TEMPLATE_DIR"; - - if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) - { - tmpFileName.AssignDir( envValue ); - envVarItem.SetDefinedExternally( true ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Found entry %s externally", envVarName ); - } - else - { - // Default user template path. - tmpFileName.AssignDir( PATHS::GetUserTemplatesPath() ); - envVarItem.SetDefinedExternally( false ); - } - - envVarItem.SetValue( tmpFileName.GetPath() ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Setting entry %s = %s", - envVarName, envVarItem.GetValue() ); - m_local_env_vars[ envVarName ] = envVarItem; - - // KICAD_SYMBOLS - envVarName = wxT( "KICAD6_SYMBOL_DIR" ); - - if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) - { - tmpFileName.AssignDir( envValue ); - envVarItem.SetDefinedExternally( true ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Found entry %s externally", envVarName ); - } - else - { - tmpFileName = baseSharePath; - tmpFileName.AppendDir( "library" ); - envVarItem.SetDefinedExternally( false ); - } - - envVarItem.SetValue( tmpFileName.GetPath() ); - wxLogTrace( traceEnvVars, "PGM_BASE::InitPgm: Setting entry %s = %s", - envVarName, envVarItem.GetValue() ); - m_local_env_vars[ envVarName ] = envVarItem; + // Set up built-in environment variables (and override them from the system enviroment if set) + GetCommonSettings()->InitializeEnvironment(); + // Load common settings from disk after setting up env vars GetSettingsManager().Load( GetCommonSettings() ); // Init user language *before* calling loadCommonSettings, because @@ -499,28 +361,26 @@ void PGM_BASE::loadCommonSettings() m_show_env_var_dialog = GetCommonSettings()->m_Env.show_warning_dialog; m_editor_name = GetCommonSettings()->m_System.editor_name; - for( const auto& it : GetCommonSettings()->m_Env.vars ) + for( const std::pair it : GetCommonSettings()->m_Env.vars ) { - wxString key( it.first.c_str(), wxConvUTF8 ); wxLogTrace( traceEnvVars, "PGM_BASE::loadCommonSettings: Found entry %s = %s", - key, it.second ); + it.first, it.second.GetValue() ); // Do not store the env var PROJECT_VAR_NAME ("KIPRJMOD") definition if for some reason // it is found in config. (It is reserved and defined as project path) - if( key == PROJECT_VAR_NAME ) + if( it.first == PROJECT_VAR_NAME ) continue; - if( m_local_env_vars[ key ].GetDefinedExternally() ) + // Don't set bogus empty entries in the environment + if( it.first.IsEmpty() ) continue; - wxLogTrace( traceEnvVars, "PGM_BASE::loadCommonSettings: Updating entry %s = %s", - key, it.second ); + // Do not overwrite vars set by the system environment with values from the settings file + if( it.second.GetDefinedExternally() ) + continue; - m_local_env_vars[ key ] = ENV_VAR_ITEM( it.second, wxGetEnv( it.first, nullptr ) ); + SetLocalEnvVariable( it.first, it.second.GetValue() ); } - - for( auto& m_local_env_var : m_local_env_vars ) - SetLocalEnvVariable( m_local_env_var.first, m_local_env_var.second.GetValue() ); } @@ -532,36 +392,6 @@ void PGM_BASE::SaveCommonSettings() { GetCommonSettings()->m_System.working_dir = wxGetCwd(); GetCommonSettings()->m_Env.show_warning_dialog = m_show_env_var_dialog; - - // remove only the old env vars that do not exist in list. - // We do not clear the full list because some are defined externally, - // and we cannot modify or delete them - std::map& curr_vars = GetCommonSettings()->m_Env.vars; - - for( auto it = curr_vars.begin(); it != curr_vars.end(); ) - { - const std::string& key = it->first; - - if( m_local_env_vars.find( key ) == m_local_env_vars.end() ) - it = curr_vars.erase( it ); // This entry no longer exists in new list - else - it++; - } - - // Save the local environment variables. - for( auto& m_local_env_var : m_local_env_vars ) - { - if( m_local_env_var.second.GetDefinedExternally() ) - continue; - - wxLogTrace( traceEnvVars, - "PGM_BASE::SaveCommonSettings: Saving environment variable config " - "entry %s as %s", - m_local_env_var.first, m_local_env_var.second.GetValue() ); - - std::string key( m_local_env_var.first.ToUTF8() ); - GetCommonSettings()->m_Env.vars[ key ] = m_local_env_var.second.GetValue(); - } } } @@ -780,6 +610,14 @@ bool PGM_BASE::SetLocalEnvVariable( const wxString& aName, const wxString& aValu { wxString env; + if( aName.IsEmpty() ) + { + wxLogTrace( traceEnvVars, + "PGM_BASE::SetLocalEnvVariable: Attempt to set empty variable to value %s", + aValue ); + return false; + } + // Check to see if the environment variable is already set. if( wxGetEnv( aName, &env ) ) { @@ -797,16 +635,11 @@ bool PGM_BASE::SetLocalEnvVariable( const wxString& aName, const wxString& aValu } -void PGM_BASE::SetLocalEnvVariables( const ENV_VAR_MAP& aEnvVarMap ) +void PGM_BASE::SetLocalEnvVariables() { - m_local_env_vars.clear(); - m_local_env_vars = aEnvVarMap; - - SaveCommonSettings(); - // Overwrites externally defined environment variable until the next time the application // is run. - for( auto& m_local_env_var : m_local_env_vars ) + for( const std::pair m_local_env_var : GetCommonSettings()->m_Env.vars ) { wxLogTrace( traceEnvVars, "PGM_BASE::SetLocalEnvVariables: Setting local environment variable %s to %s", @@ -815,3 +648,9 @@ void PGM_BASE::SetLocalEnvVariables( const ENV_VAR_MAP& aEnvVarMap ) wxSetEnv( m_local_env_var.first, m_local_env_var.second.GetValue() ); } } + + +ENV_VAR_MAP& PGM_BASE::GetLocalEnvVariables() const +{ + return GetCommonSettings()->m_Env.vars; +} diff --git a/common/settings/common_settings.cpp b/common/settings/common_settings.cpp index abe7a56d46..dc5d48a6c7 100644 --- a/common/settings/common_settings.cpp +++ b/common/settings/common_settings.cpp @@ -19,8 +19,13 @@ */ #include + +#include +#include #include #include +#include +#include #include #include @@ -94,7 +99,98 @@ COMMON_SETTINGS::COMMON_SETTINGS() : m_params.emplace_back( new PARAM( "environment.show_warning_dialog", &m_Env.show_warning_dialog, false ) ); - m_params.emplace_back( new PARAM_MAP( "environment.vars", &m_Env.vars, {} ) ); + m_params.emplace_back( new PARAM_LAMBDA( "environment.vars", + [&]() -> nlohmann::json + { + nlohmann::json ret = {}; + + for( const std::pair 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, + "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, + "COMMON_SETTINGS: Env var %s was overridden externally, " + "saving previously-loaded value %s", + var.GetKey(), var.GetSettingsValue() ); + value = var.GetSettingsValue(); + } + else + { + wxLogTrace( traceEnvVars, + "COMMON_SETTINGS: Env var %s skipping save (external)", + var.GetKey() ); + continue; + } + } + + wxLogTrace( traceEnvVars, + "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(); + + if( m_Env.vars.count( key ) ) + { + if( m_Env.vars[key].GetDefinedExternally() ) + { + wxLogTrace( traceEnvVars, "COMMON_SETTINGS: %s is defined externally", + key ); + m_Env.vars[key].SetDefinedInSettings(); + m_Env.vars[key].SetSettingsValue( val ); + continue; + } + else + { + wxLogTrace( traceEnvVars, "COMMON_SETTINGS: Updating %s: %s -> %s", + key, m_Env.vars[key].GetValue(), val ); + m_Env.vars[key].SetValue( val ); + } + } + else + { + wxLogTrace( traceEnvVars, "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( "input.auto_pan", &m_Input.auto_pan, false ) ); @@ -346,3 +442,84 @@ bool COMMON_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg ) 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, + "InitializeEnvironment: Entry %s defined externally as %s", aKey, + envValue ); + } + else + { + wxLogTrace( traceEnvVars, "InitializeEnvironment: Setting entry %s to default %s", + aKey, aDefault ); + } + }; + + wxFileName basePath( PATHS::GetStockEDALibraryPath(), wxEmptyString ); + + wxFileName path( basePath ); + path.AppendDir( wxT( "modules" ) ); + addVar( wxT( "KICAD6_FOOTPRINT_DIR" ), path.GetFullPath() ); + + path = basePath; + path.AppendDir( wxT( "3dmodels" ) ); + addVar( wxT( "KICAD6_3DMODEL_DIR" ), path.GetFullPath() ); + + // We don't have just one default template path, so use this logic that originally was in + // PGM_BASE::InitPgm to determine the best default template path + { + // Attempt to find the best default template path. + SEARCH_STACK bases; + SEARCH_STACK templatePaths; + + SystemDirsAppend( &bases ); + + for( unsigned i = 0; i < bases.GetCount(); ++i ) + { + wxFileName fn( bases[i], wxEmptyString ); + + // Add KiCad template file path to search path list. + fn.AppendDir( "template" ); + + // Only add path if exists and can be read by the user. + if( fn.DirExists() && fn.IsDirReadable() ) + { + wxLogTrace( tracePathsAndFiles, "Checking template path '%s' exists", + fn.GetPath() ); + templatePaths.AddPaths( fn.GetPath() ); + } + } + + if( templatePaths.IsEmpty() ) + { + path = basePath; + path.AppendDir( "template" ); + } + else + { + // Take the first one. There may be more but this will likely be the best option. + path.AssignDir( templatePaths[0] ); + } + + addVar( wxT( "KICAD6_TEMPLATE_DIR" ), path.GetFullPath() ); + } + + addVar( wxT( "KICAD_USER_TEMPLATE_DIR" ), PATHS::GetUserTemplatesPath() ); + + path = basePath; + path.AppendDir( wxT( "library" ) ); + addVar( wxT( "KICAD6_SYMBOL_DIR" ), path.GetFullPath() ); +} diff --git a/include/paths.h b/include/paths.h index 4341461089..0b1560ff7e 100644 --- a/include/paths.h +++ b/include/paths.h @@ -20,6 +20,9 @@ #ifndef PATHS_H #define PATHS_H +#include +#include + /** * Helper class to centralize the paths used throughout kicad */ diff --git a/include/pgm_base.h b/include/pgm_base.h index b78c48f797..62f085b990 100644 --- a/include/pgm_base.h +++ b/include/pgm_base.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -74,46 +75,6 @@ struct LANGUAGE_DESCR */ extern LANGUAGE_DESCR LanguagesList[]; - -/** - * A simple helper class to store environment variable values and the status of whether - * or not they were defined externally to the process created when any of the KiCad - * applications was launched. - */ -class ENV_VAR_ITEM -{ -public: - ENV_VAR_ITEM( const wxString& aValue = wxEmptyString, bool aIsDefinedExternally = false ) : - m_value( aValue ), - m_isDefinedExternally( aIsDefinedExternally ) - { - } - - ~ENV_VAR_ITEM() throw() {} // tell SWIG no exception - - bool GetDefinedExternally() const { return m_isDefinedExternally; } - void SetDefinedExternally( bool aIsDefinedExternally ) - { - m_isDefinedExternally = aIsDefinedExternally; - } - - const wxString& GetValue() const { return m_value; } - void SetValue( const wxString& aValue ) { m_value = aValue; } - -private: - /// The environment variable string value. - wxString m_value; - - /// Flag to indicate if the environment variable was defined externally to the process. - bool m_isDefinedExternally; -}; - - -typedef std::map ENV_VAR_MAP; -typedef std::map::iterator ENV_VAR_MAP_ITER; -typedef std::map::const_iterator ENV_VAR_MAP_CITER; - - /** * Container for data for KiCad programs. * @@ -278,18 +239,13 @@ public: virtual bool SetLocalEnvVariable( const wxString& aName, const wxString& aValue ); /** - * Set the internal local environment variable map to \a aEnvVarMap, updates the entries - * in the .kicad_common configuration file and sets the environment variable to the new - * settings. - * - * @param aEnvVarMap is a #ENV_VAR_MAP object containing the new environment variables. + * Updates the local environment with the contents of the current ENV_VAR_MAP stored in the + * COMMON_SETTINGS + * @see GetLocalEnvVariables() */ - virtual void SetLocalEnvVariables( const ENV_VAR_MAP& aEnvVarMap ); + virtual void SetLocalEnvVariables(); - virtual const ENV_VAR_MAP& GetLocalEnvVariables() const - { - return m_local_env_vars; - } + virtual ENV_VAR_MAP& GetLocalEnvVariables() const; /** * Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe. @@ -370,9 +326,6 @@ protected: wxString m_editor_name; wxSize m_help_size; - /// Local environment variable expansion settings such as KICAD6_FOOTPRINT_DIR, and KICAD6_3DMODEL_DIR. - ENV_VAR_MAP m_local_env_vars; - /// Flag to indicate if the environment variable overwrite warning dialog should be shown. bool m_show_env_var_dialog; }; diff --git a/include/settings/common_settings.h b/include/settings/common_settings.h index 8c5c8b9fa2..f05499abcb 100644 --- a/include/settings/common_settings.h +++ b/include/settings/common_settings.h @@ -21,6 +21,7 @@ #ifndef _COMMON_SETTINGS_H #define _COMMON_SETTINGS_H +#include #include @@ -69,7 +70,7 @@ public: struct ENVIRONMENT { bool show_warning_dialog; - std::map vars; + ENV_VAR_MAP vars; }; struct INPUT @@ -128,6 +129,11 @@ public: virtual bool MigrateFromLegacy( wxConfigBase* aLegacyConfig ) override; + /** + * Creates the built-in environment variables and sets their default values + */ + void InitializeEnvironment(); + private: bool migrateSchema0to1(); bool migrateSchema1to2(); diff --git a/include/settings/environment.h b/include/settings/environment.h new file mode 100644 index 0000000000..143239f813 --- /dev/null +++ b/include/settings/environment.h @@ -0,0 +1,139 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2021 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 . + */ + +#ifndef KICAD_ENVIRONMENT_H +#define KICAD_ENVIRONMENT_H + +#include +#include + +/** + * KiCad uses environment variables internally for determining the base paths for libraries, + * templates, and other assets that can be relocated by packagers or users. + * + * Because setting environment variables is not user-friendly on most platforms, KiCad supports two + * backing stores for these internal variables: the system environment, and the settings system. + * + * We also want to make it possible to change the names and values of environment variables over + * time with minimal impact to users. Since most users do not customize these variables beyond any + * customization provided by the packager for their platform, an easy way to get this possibility + * with minimal user impact is to just not store environment variables if they match the internal + * (compiled-in) default. + * + * The way environment variables are resolved is (highest to lowest priority): + * + * 1) Variables set at runtime via the Configure Paths dialog + * 2) Variables set in the system environment + * 3) Variables loaded from the settings system (stored in COMMON_SETTINGS) + * + * For all KiCad system variables, we allow users to change the values at runtime via the Configure + * Paths dialog. If these variables were set in the system environment, we do not persist any + * changes made at runtime (and warn the user about this). If the variables were not set in the + * environment (meaning they were either the default value, or loaded from the settings system), + * we persist the changes via the settings system. Any variables that match the internal default + * are not saved in the settings, so that the internal defaults can be changed and the change will + * not be overridden by an old value cached in the settings file. + */ + +/** + * A simple helper class to store environment variable definitions and values. This is used to + * initialize the environment variables that are built-in to KiCad, and also to store any variables + * created by the user. + */ +class ENV_VAR_ITEM +{ +public: + ENV_VAR_ITEM( const wxString& aValue = wxEmptyString, bool aIsDefinedExternally = false ) : + m_value( aValue ), + m_isDefinedExternally( aIsDefinedExternally ), + m_isDefinedInSettings( false ) + { + } + + ENV_VAR_ITEM( const wxString& aKey, const wxString& aValue, + const wxString& aDefaultValue = wxEmptyString ) : + m_key( aKey ), + m_value( aValue ), + m_defaultValue( aDefaultValue ), + m_isBuiltin( true ), + m_isDefinedExternally( false ), + m_isDefinedInSettings( false ) + { + } + + ~ENV_VAR_ITEM() throw() {} // tell SWIG no exception + + bool GetDefinedExternally() const { return m_isDefinedExternally; } + void SetDefinedExternally( bool aIsDefinedExternally = true ) + { + m_isDefinedExternally = aIsDefinedExternally; + } + + bool GetDefinedInSettings() const { return m_isDefinedInSettings; } + void SetDefinedInSettings( bool aDefined = true ) { m_isDefinedInSettings = aDefined; } + + wxString GetKey() const { return m_key; } + + const wxString& GetValue() const { return m_value; } + void SetValue( const wxString& aValue ) { m_value = aValue; } + + wxString GetDefault() const { return m_defaultValue; } + + wxString GetSettingsValue() const { return m_settingsValue; } + void SetSettingsValue( const wxString& aValue ) { m_settingsValue = aValue; } + + bool GetBuiltin() const { return m_isBuiltin; } + + /** + * Checks if the variable matches its default value (always false for non-built-in vars) + * @return true if a built-in variable matches its default + */ + bool IsDefault() const + { + return m_isBuiltin && m_value == m_defaultValue; + } + +private: + /// The environment variable string key. + wxString m_key; + + /// The environment variable string value. + wxString m_value; + + /// The default value, for built-in variables that are always defined. + wxString m_defaultValue; + + /// The value that was originally loaded from JSON + wxString m_settingsValue; + + /// Set to true for KiCad built-in variables that are always defined one way or another. + bool m_isBuiltin; + + /// Flag to indicate if the environment variable was defined externally to the process. + bool m_isDefinedExternally; + + /// Flag to indicate if the environment variable was defined in the settings file. + bool m_isDefinedInSettings; +}; + +typedef std::map ENV_VAR_MAP; +typedef std::map::iterator ENV_VAR_MAP_ITER; +typedef std::map::const_iterator ENV_VAR_MAP_CITER; + +#endif // KICAD_ENVIRONMENT_H