Rework JSON integration to speed up build

This commit is contained in:
Jon Evans 2021-06-03 23:52:50 -04:00
parent 42394b16a3
commit c9a660a80c
28 changed files with 680 additions and 439 deletions

View File

@ -240,7 +240,7 @@ bool EDA_3D_VIEWER_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
if( aCfg->Read( k_r, &color.r ) &&
aCfg->Read( k_g, &color.g ) && aCfg->Read( k_b, &color.b ) )
{
( *this )[PointerFromString( destKey )] = color;
Set( destKey, color );
}
};

View File

@ -457,6 +457,7 @@ set( COMMON_SRCS
settings/common_settings.cpp
settings/json_settings.cpp
settings/nested_settings.cpp
settings/parameters.cpp
settings/settings_manager.cpp
project/board_project_settings.cpp

View File

@ -18,6 +18,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <nlohmann/json.hpp>
#include <project/net_settings.h>
#include <settings/parameters.h>
#include <settings/settings_manager.h>

View File

@ -21,6 +21,7 @@
#include <config_params.h>
#include <project.h>
#include <project/net_settings.h>
#include <settings/json_settings_internals.h>
#include <project/project_file.h>
#include <settings/common_settings.h>
#include <settings/parameters.h>
@ -142,7 +143,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
libKey << ++libIndex;
}
( *this )[PointerFromString( aDest )] = libs;
Set( aDest, libs );
};
aCfg->SetPath( wxT( "/LibeditFrame" ) );
@ -168,7 +169,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
eqKey << ++eqIdx;
}
( *this )[PointerFromString( "cvpcb.equivalence_files" )] = eqs;
Set( "cvpcb.equivalence_files", eqs );
}
// All CvPcb params that we want to keep have been migrated above
@ -194,7 +195,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
libKey << ++libIdx;
}
( *this )[PointerFromString( "schematic.legacy_lib_list" )] = libs;
Set( "schematic.legacy_lib_list", libs );
}
group_blacklist.insert( wxT( "/eeschema" ) );
@ -219,7 +220,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
txtKey << ++txtIdx;
}
( *this )[PointerFromString( "text_variables" )] = vars;
Set( "text_variables", vars );
}
group_blacklist.insert( wxT( "/text_variables" ) );
@ -273,7 +274,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
key << ++idx;
}
( *this )[PointerFromString( bp + "drc_exclusions" )] = exclusions;
Set( bp + "drc_exclusions", exclusions );
}
fromLegacy<bool>( aCfg, "AllowMicroVias", bp + "rules.allow_microvias" );
@ -372,7 +373,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
key << ++idx;
}
( *this )[PointerFromString( bp + "track_widths" )] = widths;
Set( bp + "track_widths", widths );
}
{
@ -398,7 +399,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
key << ++idx;
}
( *this )[PointerFromString( bp + "via_dimensions" )] = vias;
Set( bp + "via_dimensions", vias );
}
{
@ -428,7 +429,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
key << ++idx;
}
( *this )[PointerFromString( bp + "diff_pair_dimensions" )] = pairs;
Set( bp + "diff_pair_dimensions", pairs );
}
group_blacklist.insert( wxT( "/pcbnew" ) );
@ -461,7 +462,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
}
}
( *this )[PointerFromString( "sheets" )] = arr;
Set( "sheets", arr );
aCfg->SetPath( "/" );
@ -494,8 +495,7 @@ bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
try
{
nlohmann::json::json_pointer ptr( "/legacy" + aGroup + "/" + key );
( *this )[ptr] = val;
Set( "legacy." + aGroup + "." + key, val );
}
catch( ... )
{
@ -543,8 +543,7 @@ bool PROJECT_FILE::SaveToFile( const wxString& aDirectory, bool aForce )
{
wxASSERT( m_project );
( *this )[PointerFromString( "meta.filename" )] =
m_project->GetProjectName() + "." + ProjectFileExtension;
Set( "meta.filename", m_project->GetProjectName() + "." + ProjectFileExtension );
return JSON_SETTINGS::SaveToFile( aDirectory, aForce );
}

View File

@ -20,6 +20,7 @@
#include <project.h>
#include <project/project_local_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>
const int projectLocalSettingsVersion = 3;
@ -230,18 +231,18 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin
* LAYER_PADS and LAYER_ZONES added to visibility controls
*/
nlohmann::json::json_pointer ptr( "/board/visible_items"_json_pointer );
std::string ptr( "board.visible_items" );
if( contains( ptr ) )
if( Contains( ptr ) )
{
if( ( *this )[ptr].is_array() )
if( At( ptr ).is_array() )
{
( *this )[ptr].push_back( LAYER_PADS );
( *this )[ptr].push_back( LAYER_ZONES );
At( ptr ).push_back( LAYER_PADS );
At( ptr ).push_back( LAYER_ZONES );
}
else
{
at( "board" ).erase( "visible_items" );
At( "board" ).erase( "visible_items" );
}
}
@ -277,13 +278,13 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin
{ 40, 33 }, // LAYER_ZONES
};
nlohmann::json::json_pointer ptr( "/board/visible_items"_json_pointer );
std::string ptr( "board.visible_items" );
if( contains( ptr ) && at( ptr ).is_array() )
if( Contains( ptr ) && At( ptr ).is_array() )
{
nlohmann::json visible = nlohmann::json::array();
for( const nlohmann::json& val : at( ptr ) )
for( const nlohmann::json& val : At( ptr ) )
{
try
{
@ -300,7 +301,7 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin
}
}
at( "board" )["visible_items"] = visible;
At( "board" )["visible_items"] = visible;
}
return true;
@ -323,8 +324,7 @@ bool PROJECT_LOCAL_SETTINGS::SaveToFile( const wxString& aDirectory, bool aForce
{
wxASSERT( m_project );
( *this )[PointerFromString( "meta.filename" )] =
m_project->GetProjectName() + "." + ProjectLocalSettingsFileExtension;
Set( "meta.filename", m_project->GetProjectName() + "." + ProjectLocalSettingsFileExtension );
return JSON_SETTINGS::SaveToFile( aDirectory, aForce );
}

View File

@ -23,6 +23,7 @@
#include <layers_id_colors_and_visibility.h>
#include <pgm_base.h>
#include <settings/app_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/common_settings.h>
#include <settings/parameters.h>
#include <base_units.h>
@ -175,7 +176,7 @@ bool APP_SETTINGS_BASE::MigrateFromLegacy( wxConfigBase* aCfg )
js.push_back( i );
}
( *this )[PointerFromString( "printing.layers" ) ] = js;
Set( "printing.layers", js );
}
ret &= fromLegacy<bool>( aCfg, f + "FirstRunShown", "system.first_run_shown" );
@ -196,7 +197,7 @@ bool APP_SETTINGS_BASE::MigrateFromLegacy( wxConfigBase* aCfg )
js.push_back( file.ToStdString() );
}
( *this )[PointerFromString( "system.file_history" )] = js;
Set( "system.file_history", js );
}
ret &= migrateWindowConfig( aCfg, f, "window" );
@ -224,8 +225,8 @@ void APP_SETTINGS_BASE::migrateFindReplace( wxConfigBase* aCfg )
replace_history.push_back( tmp.ToStdString() );
}
( *this )[PointerFromString( "find_replace.find_history" )] = find_history;
( *this )[PointerFromString( "find_replace.replace_history" )] = replace_history;
Set( "find_replace.find_history", find_history );
Set( "find_replace.replace_history", replace_history );
}

View File

@ -21,6 +21,7 @@
#include <layers_id_colors_and_visibility.h>
#include <pgm_base.h>
#include <settings/color_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>
#include <settings/settings_manager.h>
#include <wx/log.h>
@ -223,7 +224,7 @@ COLOR_SETTINGS::COLOR_SETTINGS( wxString aFilename ) :
// Fix LAYER_VIA_HOLES color - before version 2, this setting had no effect
nlohmann::json::json_pointer ptr( "/board/via_hole");
( *this )[ptr] = COLOR4D( 0.5, 0.4, 0, 0.8 ).ToWxString( wxC2S_CSS_SYNTAX );
( *m_internals )[ptr] = COLOR4D( 0.5, 0.4, 0, 0.8 ).ToWxString( wxC2S_CSS_SYNTAX );
return true;
} );
@ -285,10 +286,7 @@ bool COLOR_SETTINGS::migrateSchema0to1()
return false;
}
nlohmann::json::json_pointer board( "/board" );
nlohmann::json::json_pointer fpedit( "/fpedit" );
if( !contains( fpedit ) )
if( !Contains( "fpedit" ) )
{
wxLogTrace( traceSettings, "migrateSchema0to1: %s doesn't have fpedit settings; skipping.",
m_filename );
@ -300,19 +298,18 @@ bool COLOR_SETTINGS::migrateSchema0to1()
COLOR_SETTINGS* fpsettings = m_manager->AddNewColorSettings( filename );
// Start out with a clone
nlohmann::json::json_pointer root( "" );
( *fpsettings )[root] = at( root );
fpsettings->Set( "", At( "" ) );
// Footprint editor now just looks at the "board" namespace
( *fpsettings )[board] = fpsettings->at( fpedit );
fpsettings->Set( "board", fpsettings->At( "fpedit" ) );
fpsettings->erase( "fpedit" );
fpsettings->Internals()->erase( "fpedit" );
fpsettings->Load();
fpsettings->SetName( fpsettings->GetName() + wxS( " " ) + _( "(Footprints)" ) );
m_manager->Save( fpsettings );
// Now we can get rid of our own copy
erase( "fpedit" );
m_internals->erase( "fpedit" );
return true;
}

View File

@ -23,6 +23,7 @@
#include <paths.h>
#include <search_stack.h>
#include <settings/common_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>
#include <systemdirsappend.h>
#include <trace_helpers.h>
@ -300,8 +301,8 @@ bool COMMON_SETTINGS::migrateSchema0to1()
try
{
mwp = at( mwp_pointer );
at( nlohmann::json::json_pointer( "/input"_json_pointer ) ).erase( "mousewheel_pan" );
mwp = m_internals->at( mwp_pointer );
m_internals->At( "input" ).erase( "mousewheel_pan" );
}
catch( ... )
{
@ -310,19 +311,19 @@ bool COMMON_SETTINGS::migrateSchema0to1()
if( mwp )
{
( *this )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = true;
( *m_internals )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = true;
( *this )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_h" )] = WXK_SHIFT;
( *this )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_v" )] = 0;
( *this )[nlohmann::json::json_pointer( "/input/scroll_modifier_zoom" )] = WXK_CONTROL;
( *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
{
( *this )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = false;
( *m_internals )[nlohmann::json::json_pointer( "/input/horizontal_pan" )] = false;
( *this )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_h" )] = WXK_CONTROL;
( *this )[nlohmann::json::json_pointer( "/input/scroll_modifier_pan_v" )] = WXK_SHIFT;
( *this )[nlohmann::json::json_pointer( "/input/scroll_modifier_zoom" )] = 0;
( *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;
@ -337,8 +338,8 @@ bool COMMON_SETTINGS::migrateSchema1to2()
try
{
prefer_selection = at( v1_pointer );
at( nlohmann::json::json_pointer( "/input"_json_pointer ) ).erase( "prefer_select_to_drag" );
prefer_selection = m_internals->at( v1_pointer );
m_internals->at( nlohmann::json::json_pointer( "/input"_json_pointer ) ).erase( "prefer_select_to_drag" );
}
catch( ... )
{
@ -346,9 +347,9 @@ bool COMMON_SETTINGS::migrateSchema1to2()
}
if( prefer_selection )
( *this )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::SELECT;
( *m_internals )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::SELECT;
else
( *this )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::DRAG_ANY;
( *m_internals )[nlohmann::json::json_pointer( "/input/mouse_left" )] = MOUSE_DRAG_ACTION::DRAG_ANY;
return true;
}
@ -374,10 +375,10 @@ bool COMMON_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
auto load_env_vars = [&] () {
wxString key, value;
long index = 0;
nlohmann::json::json_pointer ptr = PointerFromString( "environment.vars" );
nlohmann::json::json_pointer ptr = m_internals->PointerFromString( "environment.vars" );
aCfg->SetPath( "EnvironmentVariables" );
( *this )[ptr] = nlohmann::json( {} );
( *m_internals )[ptr] = nlohmann::json( {} );
while( aCfg->GetNextEntry( key, index ) )
{
@ -394,7 +395,7 @@ bool COMMON_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
ptr.push_back( key.ToStdString() );
wxLogTrace( traceSettings, "Migrate Env: %s=%s", ptr.to_string(), value );
( *this )[ptr] = value.ToUTF8();
( *m_internals )[ptr] = value.ToUTF8();
ptr.pop_back();
}
@ -409,11 +410,10 @@ bool COMMON_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
if( aCfg->Read( "MousewheelPAN", &mousewheel_pan ) && mousewheel_pan )
{
( *this )[PointerFromString( "input.horizontal_pan" )] = true;
( *this )[PointerFromString( "input.scroll_modifier_pan_h" )] = WXK_SHIFT;
( *this )[PointerFromString( "input.scroll_modifier_pan_v" )] = 0;
( *this )[PointerFromString( "input.scroll_modifier_zoom" )] = WXK_CONTROL;
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" );
@ -423,11 +423,8 @@ bool COMMON_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
ret &= fromLegacy<bool>( aCfg, "ZoomNoCenter", "input.center_on_zoom" );
// This was stored inverted in legacy config
if( ret )
{
auto p = PointerFromString( "input.center_on_zoom" );
( *this )[p] = !( *this )[p];
}
if( OPT<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" );

View File

@ -27,6 +27,7 @@
#include <locale_io.h>
#include <gal/color4d.h>
#include <settings/json_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/nested_settings.h>
#include <settings/parameters.h>
#include <wx/config.h>
@ -36,13 +37,32 @@
#include <wx/log.h>
#include <wx/wfstream.h>
const wxChar* const traceSettings = wxT( "KICAD_SETTINGS" );
nlohmann::json::json_pointer JSON_SETTINGS_INTERNALS::PointerFromString( std::string aPath )
{
std::replace( aPath.begin(), aPath.end(), '.', '/' );
aPath.insert( 0, "/" );
nlohmann::json::json_pointer p;
try
{
p = nlohmann::json::json_pointer( aPath );
}
catch( ... )
{
wxASSERT_MSG( false, wxT( "Invalid pointer path in PointerFromString!" ) );
}
return p;
}
JSON_SETTINGS::JSON_SETTINGS( const wxString& aFilename, SETTINGS_LOC aLocation,
int aSchemaVersion, bool aCreateIfMissing, bool aCreateIfDefault,
bool aWriteFile ) :
nlohmann::json(),
m_filename( aFilename ),
m_legacy_filename( "" ),
m_location( aLocation ),
@ -54,9 +74,11 @@ JSON_SETTINGS::JSON_SETTINGS( const wxString& aFilename, SETTINGS_LOC aLocation,
m_schemaVersion( aSchemaVersion ),
m_manager( nullptr )
{
m_internals = std::make_unique<JSON_SETTINGS_INTERNALS>();
try
{
( *this )[PointerFromString( "meta.filename" )] = GetFullFilename();
m_internals->SetFromString( "meta.filename", GetFullFilename() );
}
catch( ... )
{
@ -85,6 +107,30 @@ wxString JSON_SETTINGS::GetFullFilename() const
}
nlohmann::json& JSON_SETTINGS::At( const std::string& aPath )
{
return m_internals->At( aPath );
}
bool JSON_SETTINGS::Contains( const std::string& aPath ) const
{
return m_internals->contains( JSON_SETTINGS_INTERNALS::PointerFromString( aPath ) );
}
size_t JSON_SETTINGS::Count( const std::string& aPath ) const
{
return m_internals->count( JSON_SETTINGS_INTERNALS::PointerFromString( aPath ) );
}
JSON_SETTINGS_INTERNALS* JSON_SETTINGS::Internals()
{
return m_internals.get();
}
void JSON_SETTINGS::Load()
{
for( auto param : m_params )
@ -105,7 +151,7 @@ void JSON_SETTINGS::Load()
bool JSON_SETTINGS::LoadFromFile( const wxString& aDirectory )
{
// First, load all params to default values
clear();
m_internals->clear();
Load();
bool success = true;
@ -220,16 +266,17 @@ bool JSON_SETTINGS::LoadFromFile( const wxString& aDirectory )
if( fp )
{
*static_cast<nlohmann::json*>( this ) = nlohmann::json::parse( fp, nullptr,
/* allow_exceptions = */ true,
/* ignore_comments = */ true );
*static_cast<nlohmann::json*>( m_internals.get() ) =
nlohmann::json::parse( fp, nullptr,
/* allow_exceptions = */ true,
/* ignore_comments = */ true );
// If parse succeeds, check if schema migration is required
int filever = -1;
try
{
filever = at( PointerFromString( "meta.version" ) ).get<int>();
filever = m_internals->Get<int>( "meta.version" );
}
catch( ... )
{
@ -407,7 +454,7 @@ bool JSON_SETTINGS::SaveToFile( const wxString& aDirectory, bool aForce )
try
{
std::stringstream buffer;
buffer << std::setw( 2 ) << *this << std::endl;
buffer << std::setw( 2 ) << *m_internals << std::endl;
wxFFileOutputStream fileStream( path.GetFullPath(), "wb" );
@ -436,13 +483,13 @@ bool JSON_SETTINGS::SaveToFile( const wxString& aDirectory, bool aForce )
OPT<nlohmann::json> JSON_SETTINGS::GetJson( const std::string& aPath ) const
{
nlohmann::json::json_pointer ptr = PointerFromString( aPath );
nlohmann::json::json_pointer ptr = m_internals->PointerFromString( aPath );
if( contains( ptr ) )
if( m_internals->contains( ptr ) )
{
try
{
return OPT<nlohmann::json>{ at( ptr ) };
return OPT<nlohmann::json>{ m_internals->at( ptr ) };
}
catch( ... )
{
@ -453,6 +500,55 @@ OPT<nlohmann::json> JSON_SETTINGS::GetJson( const std::string& aPath ) const
}
template<typename ValueType>
OPT<ValueType> JSON_SETTINGS::Get( const std::string& aPath ) const
{
if( OPT<nlohmann::json> ret = GetJson( aPath ) )
{
try
{
return ret->get<ValueType>();
}
catch( ... )
{
}
}
return NULLOPT;
}
// Instantiate all required templates here to allow reducing scope of json.hpp
template OPT<bool> JSON_SETTINGS::Get<bool>( const std::string& aPath ) const;
template OPT<double> JSON_SETTINGS::Get<double>( const std::string& aPath ) const;
template OPT<float> JSON_SETTINGS::Get<float>( const std::string& aPath ) const;
template OPT<unsigned int> JSON_SETTINGS::Get<unsigned int>( const std::string& aPath ) const;
template OPT<unsigned long long> JSON_SETTINGS::Get<unsigned long long>( const std::string& aPath ) const;
template OPT<std::string> JSON_SETTINGS::Get<std::string>( const std::string& aPath ) const;
template OPT<nlohmann::json> JSON_SETTINGS::Get<nlohmann::json>( const std::string& aPath ) const;
template OPT<KIGFX::COLOR4D> JSON_SETTINGS::Get<KIGFX::COLOR4D>( const std::string& aPath ) const;
template<typename ValueType>
void JSON_SETTINGS::Set( const std::string& aPath, ValueType aVal )
{
m_internals->SetFromString( aPath, aVal );
}
// Instantiate all required templates here to allow reducing scope of json.hpp
template void JSON_SETTINGS::Set<bool>( const std::string& aPath, bool aValue );
template void JSON_SETTINGS::Set<double>( const std::string& aPath, double aValue );
template void JSON_SETTINGS::Set<float>( const std::string& aPath, float aValue );
template void JSON_SETTINGS::Set<int>( const std::string& aPath, int aValue );
template void JSON_SETTINGS::Set<unsigned int>( const std::string& aPath, unsigned int aValue );
template void JSON_SETTINGS::Set<unsigned long long>( const std::string& aPath, unsigned long long aValue );
template void JSON_SETTINGS::Set<const char*>( const std::string& aPath, const char* aValue );
template void JSON_SETTINGS::Set<std::string>( const std::string& aPath, std::string aValue );
template void JSON_SETTINGS::Set<nlohmann::json>( const std::string& aPath, nlohmann::json aValue );
template void JSON_SETTINGS::Set<KIGFX::COLOR4D>( const std::string& aPath, KIGFX::COLOR4D aValue );
void JSON_SETTINGS::registerMigration( int aOldSchemaVersion, int aNewSchemaVersion,
std::function<bool()> aMigrator )
{
@ -464,7 +560,7 @@ void JSON_SETTINGS::registerMigration( int aOldSchemaVersion, int aNewSchemaVers
bool JSON_SETTINGS::Migrate()
{
int filever = at( PointerFromString( "meta.version" ) ).get<int>();
int filever = m_internals->Get<int>( "meta.version" );
while( filever < m_schemaVersion )
{
@ -482,7 +578,7 @@ bool JSON_SETTINGS::Migrate()
wxLogTrace( traceSettings, "Migrated %s from %d to %d", typeid( *this ).name(),
filever, pair.first );
filever = pair.first;
( *this )[PointerFromString( "meta.version" )] = filever;
m_internals->At( "meta.version" ) = filever;
}
else
{
@ -504,30 +600,10 @@ bool JSON_SETTINGS::MigrateFromLegacy( wxConfigBase* aLegacyConfig )
}
nlohmann::json::json_pointer JSON_SETTINGS::PointerFromString( std::string aPath )
{
std::replace( aPath.begin(), aPath.end(), '.', '/' );
aPath.insert( 0, "/" );
nlohmann::json::json_pointer p;
try
{
p = nlohmann::json::json_pointer( aPath );
}
catch( ... )
{
wxASSERT_MSG( false, wxT( "Invalid pointer path in PointerFromString!" ) );
}
return p;
}
bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
wxString& aTarget )
{
nlohmann::json::json_pointer ptr = PointerFromString( aPath );
nlohmann::json::json_pointer ptr = JSON_SETTINGS_INTERNALS::PointerFromString( aPath );
if( aObj.contains( ptr ) && aObj.at( ptr ).is_string() )
{
@ -542,7 +618,7 @@ bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string&
bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
bool& aTarget )
{
nlohmann::json::json_pointer ptr = PointerFromString( aPath );
nlohmann::json::json_pointer ptr = JSON_SETTINGS_INTERNALS::PointerFromString( aPath );
if( aObj.contains( ptr ) && aObj.at( ptr ).is_boolean() )
{
@ -557,7 +633,7 @@ bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string&
bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
int& aTarget )
{
nlohmann::json::json_pointer ptr = PointerFromString( aPath );
nlohmann::json::json_pointer ptr = JSON_SETTINGS_INTERNALS::PointerFromString( aPath );
if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_integer() )
{
@ -572,7 +648,7 @@ bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string&
bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
unsigned int& aTarget )
{
nlohmann::json::json_pointer ptr = PointerFromString( aPath );
nlohmann::json::json_pointer ptr = JSON_SETTINGS_INTERNALS::PointerFromString( aPath );
if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_unsigned() )
{
@ -594,7 +670,7 @@ bool JSON_SETTINGS::fromLegacy( wxConfigBase* aConfig, const std::string& aKey,
{
try
{
( *this )[PointerFromString( aDest )] = val;
( *m_internals )[aDest] = val;
}
catch( ... )
{
@ -630,7 +706,7 @@ bool JSON_SETTINGS::fromLegacyString( wxConfigBase* aConfig, const std::string&
{
try
{
( *this )[PointerFromString( aDest )] = str.ToUTF8();
( *m_internals )[aDest] = str.ToUTF8();
}
catch( ... )
{
@ -658,7 +734,7 @@ bool JSON_SETTINGS::fromLegacyColor( wxConfigBase* aConfig, const std::string& a
try
{
nlohmann::json js = nlohmann::json::array( { color.r, color.g, color.b, color.a } );
( *this )[PointerFromString( aDest )] = js;
( *m_internals )[aDest] = js;
}
catch( ... )
{
@ -714,7 +790,7 @@ template<> OPT<wxString> JSON_SETTINGS::Get( const std::string& aPath ) const
template<> void JSON_SETTINGS::Set<wxString>( const std::string& aPath, wxString aVal )
{
( *this )[PointerFromString( std::move( aPath ) ) ] = aVal.ToUTF8();
( *m_internals )[aPath] = aVal.ToUTF8();
}
// Specializations to allow directly reading/writing wxStrings from JSON

View File

@ -20,6 +20,7 @@
#include <wx/log.h>
#include <settings/json_settings_internals.h>
#include <settings/nested_settings.h>
NESTED_SETTINGS::NESTED_SETTINGS( const std::string& aName, int aVersion, JSON_SETTINGS* aParent,
@ -40,18 +41,18 @@ NESTED_SETTINGS::~NESTED_SETTINGS()
bool NESTED_SETTINGS::LoadFromFile( const wxString& aDirectory )
{
clear();
m_internals->clear();
bool success = false;
if( m_parent )
{
nlohmann::json::json_pointer ptr = PointerFromString( m_path );
nlohmann::json::json_pointer ptr = m_internals->PointerFromString( m_path );
if( m_parent->contains( ptr ) )
if( m_parent->m_internals->contains( ptr ) )
{
try
{
update( ( *m_parent )[ptr] );
m_internals->update( ( *m_parent->m_internals )[ptr] );
wxLogTrace( traceSettings, "Loaded NESTED_SETTINGS %s", GetFilename() );
@ -71,7 +72,7 @@ bool NESTED_SETTINGS::LoadFromFile( const wxString& aDirectory )
try
{
filever = at( PointerFromString( "meta.version" ) ).get<int>();
filever = m_internals->Get<int>( "meta.version" );
}
catch( ... )
{
@ -118,8 +119,9 @@ bool NESTED_SETTINGS::SaveToFile( const wxString& aDirectory, bool aForce )
try
{
nlohmann::json patch =
nlohmann::json::diff( *this, ( *m_parent )[PointerFromString( m_path )] );
nlohmann::json patch = nlohmann::json::diff( *m_internals,
m_parent->m_internals->Get<nlohmann::json>( m_path ) );
modified |= !patch.empty();
}
catch( ... )
@ -132,7 +134,7 @@ bool NESTED_SETTINGS::SaveToFile( const wxString& aDirectory, bool aForce )
try
{
( *m_parent )[PointerFromString( m_path ) ].update( *this );
m_parent->m_internals->At( m_path ).update( *m_internals );
wxLogTrace( traceSettings, "Stored NESTED_SETTINGS %s with schema %d",
GetFilename(), m_schemaVersion );

View File

@ -0,0 +1,290 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 Jon Evans <jon@craftyjon.com>
* 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 <http://www.gnu.org/licenses/>.
*/
#include <wx/string.h>
#include <nlohmann/json.hpp>
#include <gal/color4d.h>
#include <project/project_file.h>
#include <settings/parameters.h>
template <typename ValueType>
void PARAM_LAMBDA<ValueType>::Load( JSON_SETTINGS* aSettings, bool aResetIfMissing ) const
{
if( m_readOnly )
return;
if( std::is_same<ValueType, nlohmann::json>::value )
{
if( OPT<nlohmann::json> optval = aSettings->GetJson( m_path ) )
m_setter( *optval );
else
m_setter( m_default );
}
else
{
if( OPT<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
m_setter( *optval );
else
m_setter( m_default );
}
}
template <typename ValueType>
bool PARAM_LAMBDA<ValueType>::MatchesFile( JSON_SETTINGS* aSettings ) const
{
if( std::is_same<ValueType, nlohmann::json>::value )
{
if( OPT<nlohmann::json> optval = aSettings->GetJson( m_path ) )
return *optval == m_getter();
}
else
{
if( OPT<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
return *optval == m_getter();
}
// Not in file
return false;
}
// Instantiate all required templates here to allow reducing scope of json.hpp
template class PARAM_LAMBDA<bool>;
template class PARAM_LAMBDA<int>;
template class PARAM_LAMBDA<nlohmann::json>;
template class PARAM_LAMBDA<std::string>;
template <typename ValueType>
void PARAM_LIST<ValueType>::Load( JSON_SETTINGS* aSettings, bool aResetIfMissing ) const
{
if( m_readOnly )
return;
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
std::vector<ValueType> val;
if( js->is_array() )
{
for( const auto& el : js->items() )
val.push_back( el.value().get<ValueType>() );
}
*m_ptr = val;
}
else if( aResetIfMissing )
*m_ptr = m_default;
}
template <typename ValueType>
void PARAM_LIST<ValueType>::Store( JSON_SETTINGS* aSettings ) const
{
nlohmann::json js = nlohmann::json::array();
for( const auto& el : *m_ptr )
js.push_back( el );
aSettings->Set<nlohmann::json>( m_path, js );
}
template <typename ValueType>
bool PARAM_LIST<ValueType>::MatchesFile( JSON_SETTINGS* aSettings ) const
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_array() )
{
std::vector<ValueType> val;
for( const auto& el : js->items() )
val.emplace_back( el.value().get<ValueType>() );
return val == *m_ptr;
}
}
return false;
}
template class PARAM_LIST<int>;
template class PARAM_LIST<double>;
template class PARAM_LIST<wxString>;
template class PARAM_LIST<KIGFX::COLOR4D>;
template class PARAM_LIST<FILE_INFO_PAIR>;
void PARAM_PATH_LIST::Store( JSON_SETTINGS* aSettings ) const
{
nlohmann::json js = nlohmann::json::array();
for( const auto& el : *m_ptr )
js.push_back( toFileFormat( el ) );
aSettings->Set<nlohmann::json>( m_path, js );
}
bool PARAM_PATH_LIST::MatchesFile( JSON_SETTINGS* aSettings ) const
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_array() )
{
std::vector<wxString> val;
for( const auto& el : js->items() )
val.emplace_back( fromFileFormat( el.value().get<wxString>() ) );
return val == *m_ptr;
}
}
return false;
}
template <typename Value>
void PARAM_MAP<Value>::Load( JSON_SETTINGS* aSettings, bool aResetIfMissing ) const
{
if( m_readOnly )
return;
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_object() )
{
m_ptr->clear();
for( const auto& el : js->items() )
( *m_ptr )[el.key()] = el.value().get<Value>();
}
}
else if( aResetIfMissing )
*m_ptr = m_default;
}
template <typename Value>
void PARAM_MAP<Value>::Store( JSON_SETTINGS* aSettings ) const
{
nlohmann::json js( {} );
for( const auto& el : *m_ptr )
js[el.first] = el.second;
aSettings->Set<nlohmann::json>( m_path, js );
}
template <typename Value>
bool PARAM_MAP<Value>::MatchesFile( JSON_SETTINGS* aSettings ) const
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_object() )
{
if( m_ptr->size() != js->size() )
return false;
std::map<std::string, Value> val;
for( const auto& el : js->items() )
val[el.key()] = el.value().get<Value>();
return val == *m_ptr;
}
}
return false;
}
template class PARAM_MAP<int>;
template class PARAM_MAP<double>;
template class PARAM_MAP<bool>;
void PARAM_WXSTRING_MAP::Load( JSON_SETTINGS* aSettings, bool aResetIfMissing ) const
{
if( m_readOnly )
return;
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_object() )
{
m_ptr->clear();
for( const auto& el : js->items() )
{
( *m_ptr )[wxString( el.key().c_str(), wxConvUTF8 )] = el.value().get<wxString>();
}
}
}
else if( aResetIfMissing )
*m_ptr = m_default;
}
void PARAM_WXSTRING_MAP::Store( JSON_SETTINGS* aSettings ) const
{
nlohmann::json js( {} );
for( const auto& el : *m_ptr )
{
std::string key( el.first.ToUTF8() );
js[key] = el.second;
}
aSettings->Set<nlohmann::json>( m_path, js );
}
bool PARAM_WXSTRING_MAP::MatchesFile( JSON_SETTINGS* aSettings ) const
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_object() )
{
if( m_ptr->size() != js->size() )
return false;
std::map<wxString, wxString> val;
for( const auto& el : js->items() )
{
wxString key( el.key().c_str(), wxConvUTF8 );
val[key] = el.value().get<wxString>();
}
return val == *m_ptr;
}
}
return false;
}

View File

@ -41,6 +41,7 @@
#include <project/project_local_settings.h>
#include <settings/color_settings.h>
#include <settings/common_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/settings_manager.h>
#include <wildcards_and_files_ext.h>
@ -325,7 +326,8 @@ void SETTINGS_MANAGER::SaveColorSettings( COLOR_SETTINGS* aSettings, const std::
}
) != m_color_settings.end() );
nlohmann::json::json_pointer ptr = JSON_SETTINGS::PointerFromString( aNamespace );
if( aSettings->IsReadOnly() )
return;
if( !aSettings->Store() )
{
@ -334,17 +336,17 @@ void SETTINGS_MANAGER::SaveColorSettings( COLOR_SETTINGS* aSettings, const std::
return;
}
wxASSERT( aSettings->contains( ptr ) );
wxASSERT( aSettings->Contains( aNamespace ) );
wxLogTrace( traceSettings, "Saving color scheme %s, preserving %s", aSettings->GetFilename(),
aNamespace );
aNamespace );
nlohmann::json backup = aSettings->at( ptr );
nlohmann::json backup = aSettings->At( aNamespace );
wxString path = GetColorSettingsPath();
aSettings->LoadFromFile( path );
( *aSettings )[ptr].update( backup );
( *aSettings->Internals() )[aNamespace].update( backup );
aSettings->Load();
aSettings->SaveToFile( path, true );

View File

@ -30,6 +30,7 @@
#include <macros.h>
#include <pgm_base.h>
#include <settings/common_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>
#include <settings/settings_manager.h>
#include <wx/config.h>
@ -405,16 +406,16 @@ bool EESCHEMA_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
// Now modify the loaded grid selection, because in earlier versions the grids index was shared
// between all applications and started at 1000 mils. There is a 4-position offset between
// this index and the possible eeschema grids list that we have to subtract.
nlohmann::json::json_pointer gridSizePtr = PointerFromString( "window.grid.last_size" );
std::string gridSizePtr = "window.grid.last_size";
try
if( OPT<int> currentSize = Get<int>( gridSizePtr ) )
{
( *this )[gridSizePtr] = ( *this )[gridSizePtr].get<int>() - 4;
Set( gridSizePtr, *currentSize - 4 );
}
catch( ... )
else
{
// Otherwise, default grid size should be 50 mils; index 1
( *this )[gridSizePtr] = 1;
Set( gridSizePtr, 1 );
}
ret &= fromLegacy<bool>( aCfg, "FootprintPreview", "appearance.footprint_preview" );
@ -497,8 +498,8 @@ bool EESCHEMA_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
}
}
( *this )[PointerFromString( "netlist.custom_command_titles" )] = js_title;
( *this )[PointerFromString( "netlist.custom_command_paths" )] = js_cmd;
Set( "netlist.custom_command_titles", js_title );
Set( "netlist.custom_command_paths", js_cmd );
}
{
@ -518,11 +519,11 @@ bool EESCHEMA_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
if( aCfg->Read( key, &value ) )
{
std::string key_utf( key.ToUTF8() );
js[PointerFromString( key_utf )] = value;
js[JSON_SETTINGS_INTERNALS::PointerFromString( key_utf )] = value;
}
}
( *this )[PointerFromString( "field_editor.fields_show" ) ] = js;
Set( "field_editor.fields_show", js );
aCfg->SetPath( "../GroupBy" );
@ -531,11 +532,11 @@ bool EESCHEMA_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
if( aCfg->Read( key, &value ) )
{
std::string key_utf( key.ToUTF8() );
js[PointerFromString( key_utf )] = value;
js[JSON_SETTINGS_INTERNALS::PointerFromString( key_utf )] = value;
}
}
( *this )[PointerFromString( "field_editor.fields_group_by" ) ] = js;
Set( "field_editor.fields_group_by", js );
aCfg->SetPath( "../.." );
}
@ -628,7 +629,7 @@ bool EESCHEMA_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
Pgm().GetSettingsManager().SaveColorSettings( cs, "schematic" );
( *this )[PointerFromString( "appearance.color_theme" )] = cs->GetFilename();
Set( "appearance.color_theme", cs->GetFilename() );
// LibEdit settings were stored with eeschema. If eeschema is the first app to run,
// we need to migrate the LibEdit settings here
@ -668,12 +669,10 @@ std::vector<EESCHEMA_SETTINGS::BOM_PLUGIN_SETTINGS> EESCHEMA_SETTINGS::DefaultBo
bool EESCHEMA_SETTINGS::migrateBomSettings()
{
nlohmann::json::json_pointer ptr = PointerFromString( "bom.plugins" );
if( !contains( ptr ) )
if( !Contains( "bom.plugins" ) )
return false;
wxString list = at( ptr ).get<wxString>();
wxString list = Get<wxString>( "bom.plugins" ).value();
BOM_CFG_PARSER cfg_parser( &m_BomPanel.plugins, TO_UTF8( list ), wxT( "plugins" ) );
@ -687,7 +686,7 @@ bool EESCHEMA_SETTINGS::migrateBomSettings()
}
// Parser will have loaded up our array, let's dump it out to JSON
at( ptr ) = bomSettingsToJson();
At( "bom.plugins" ) = bomSettingsToJson();
return true;
}

View File

@ -23,6 +23,7 @@
#include <schematic.h>
#include <sch_marker.h>
#include <sch_screen.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>

View File

@ -28,6 +28,7 @@
#include <kiface_i.h>
#include <macros.h>
#include <schematic_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>
#include <sim/spice_settings.h>

View File

@ -92,16 +92,16 @@ bool SYMBOL_EDITOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
// Now modify the loaded grid selection, because in earlier versions the grids index was shared
// between all applications and started at 1000 mils. There is a 4-position offset between
// this index and the possible eeschema grids list that we have to subtract.
nlohmann::json::json_pointer gridSizePtr = PointerFromString( "window.grid.last_size" );
std::string gridSizePtr = "window.grid.last_size";
try
if( OPT<int> currentSize = Get<int>( gridSizePtr ) )
{
( *this )[gridSizePtr] = ( *this )[gridSizePtr].get<int>() - 4;
Set( gridSizePtr, *currentSize - 4 );
}
catch( ... )
else
{
// Otherwise, default grid size should be 50 mils; index 1
( *this )[gridSizePtr] = 1;
Set( gridSizePtr, 1 );
}
ret &= fromLegacy<int>( aCfg, "DefaultWireWidth", "defaults.line_width" );

View File

@ -25,6 +25,7 @@
#include <layers_id_colors_and_visibility.h>
#include <pgm_base.h>
#include <settings/common_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>
#include <settings/settings_manager.h>
#include <wx/config.h>
@ -99,7 +100,7 @@ bool GERBVIEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
aCfg->SetPath( ".." );
( *this )[PointerFromString( aDest )] = js;
Set( aDest, js );
};
migrate_files( "drl_files", "system.drill_file_history" );
@ -109,15 +110,14 @@ bool GERBVIEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
{
wxString key;
int value = 0;
nlohmann::json::json_pointer ptr = PointerFromString( "gerber_to_pcb_layers" );
( *this )[ptr] = nlohmann::json::array();
At( "gerber_to_pcb_layers" ) = nlohmann::json::array();
for( int i = 0; i < GERBER_DRAWLAYERS_COUNT; i++ )
{
key.Printf( "GbrLyr%dToPcb", i );
aCfg->Read( key, &value, UNSELECTED_LAYER );
( *this )[ptr].emplace_back( value );
At( "gerber_to_pcb_layers" ).emplace_back( value );
}
}
@ -147,7 +147,7 @@ bool GERBVIEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
Pgm().GetSettingsManager().SaveColorSettings( cs, "gerbview" );
( *this )[PointerFromString( "appearance.color_theme" )] = cs->GetFilename();
Set( "appearance.color_theme", cs->GetFilename() );
return ret;
}

View File

@ -24,6 +24,9 @@
#include <layers_id_colors_and_visibility.h>
#include <settings/parameters.h>
// Can be removed by refactoring PARAM_LAYER_PRESET
#include <nlohmann/json.hpp>
/**
* This file contains data structures that are saved in the project file or project local settings
* file that are specific to PcbNew. This is done so that these structures are available in common.

View File

@ -21,6 +21,8 @@
#ifndef _COLOR_SETTINGS_H
#define _COLOR_SETTINGS_H
#include <unordered_map>
#include <gal/color4d.h>
#include <settings/json_settings.h>
#include <settings/parameters.h>

View File

@ -23,11 +23,11 @@
#include <core/wx_stl_compat.h>
#include <nlohmann/json.hpp>
#include <utility>
#include <wx/string.h>
#include <core/optional.h>
#include <nlohmann/json_fwd.hpp>
class wxConfigBase;
class NESTED_SETTINGS;
@ -52,9 +52,14 @@ enum class SETTINGS_LOC {
};
class JSON_SETTINGS : public nlohmann::json
/// pimpl to allow hiding json.hpp
class JSON_SETTINGS_INTERNALS;
class JSON_SETTINGS
{
public:
friend class NESTED_SETTINGS;
JSON_SETTINGS( const wxString& aFilename, SETTINGS_LOC aLocation, int aSchemaVersion ) :
JSON_SETTINGS( aFilename, aLocation, aSchemaVersion, true, true, true ) {}
@ -76,6 +81,17 @@ public:
bool IsReadOnly() const { return !m_writeFile; }
void SetReadOnly( bool aReadOnly ) { m_writeFile = !aReadOnly; }
/**
* Wrappers for the underlying JSON API so that most consumers don't need json.hpp
* All of these functions take a string that is passed to PointerFromString internally.
*/
nlohmann::json& At( const std::string& aPath );
bool Contains( const std::string& aPath ) const;
size_t Count( const std::string& aPath ) const;
JSON_SETTINGS_INTERNALS* Internals();
/**
* Updates the parameters of this object based on the current JSON document contents
*/
@ -130,21 +146,7 @@ c * @return true if the file was saved
* @return a value from within this document
*/
template<typename ValueType>
OPT<ValueType> Get( const std::string& aPath ) const
{
if( OPT<nlohmann::json> ret = GetJson( aPath ) )
{
try
{
return ret->get<ValueType>();
}
catch( ... )
{
}
}
return NULLOPT;
}
OPT<ValueType> Get( const std::string& aPath ) const;
/**
* Stores a value into the JSON document
@ -154,10 +156,7 @@ c * @return true if the file was saved
* @param aVal is the value to store
*/
template<typename ValueType>
void Set( const std::string& aPath, ValueType aVal )
{
( *this )[PointerFromString( aPath ) ] = aVal;
}
void Set( const std::string& aPath, ValueType aVal );
/**
* Migrates the schema of this settings from the version in the file to the latest version
@ -199,13 +198,6 @@ c * @return true if the file was saved
m_manager = aManager;
}
/**
* Builds a JSON pointer based on a given string
* @param aPath is the path in the form "key1.key2.key3"
* @return a JSON pointer that can be used to index into a JSON object
*/
static nlohmann::json::json_pointer PointerFromString( std::string aPath );
/**
* Sets the given string if the given key/path is present
* @param aObj is the source object
@ -329,11 +321,10 @@ protected:
/// A pointer to the settings manager managing this file (may be null)
SETTINGS_MANAGER* m_manager;
/// A list of JSON pointers that are preserved during a read-update-write to disk
std::vector<nlohmann::json::json_pointer> m_preserved_paths;
/// A map of starting schema version to a pair of <ending version, migrator function>
std::map<int, std::pair<int, std::function<bool()>>> m_migrators;
std::unique_ptr<JSON_SETTINGS_INTERNALS> m_internals;
};
// Specializations to allow conversion between wxString and std::string via JSON_SETTINGS API

View File

@ -0,0 +1,67 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 Jon Evans <jon@craftyjon.com>
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KICAD_JSON_SETTINGS_INTERNALS_H
#define KICAD_JSON_SETTINGS_INTERNALS_H
// This is a pretty heavy file. Try to use json_fwd.hpp most places.
#include <nlohmann/json.hpp>
class JSON_SETTINGS_INTERNALS : public nlohmann::json
{
friend class JSON_SETTINGS;
public:
JSON_SETTINGS_INTERNALS() :
nlohmann::json()
{}
/**
* Builds a JSON pointer based on a given string
* @param aPath is the path in the form "key1.key2.key3"
* @return a JSON pointer that can be used to index into a JSON object
*/
static nlohmann::json::json_pointer PointerFromString( std::string aPath );
template<typename ValueType>
void SetFromString( const std::string& aPath, ValueType aVal )
{
// Calls the overload below, which will convert from dotted string to JSON pointer
( *this )[aPath] = aVal;
}
template<typename ValueType>
ValueType Get( const std::string& aPath ) const
{
return at( PointerFromString( aPath ) ).get<ValueType>();
}
nlohmann::json& At( const std::string& aPath )
{
return at( PointerFromString( aPath ) );
}
nlohmann::json& operator[]( const std::string& aPath )
{
return nlohmann::json::operator[]( PointerFromString( aPath ) );
}
};
#endif // KICAD_JSON_SETTINGS_INTERNALS_H

View File

@ -305,26 +305,7 @@ public:
m_setter( aSetter )
{ }
void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override
{
if( m_readOnly )
return;
if( std::is_same<ValueType, nlohmann::json>::value )
{
if( OPT<nlohmann::json> optval = aSettings->GetJson( m_path ) )
m_setter( *optval );
else
m_setter( m_default );
}
else
{
if( OPT<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
m_setter( *optval );
else
m_setter( m_default );
}
}
void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override;
void Store( JSON_SETTINGS* aSettings ) const override
{
@ -352,22 +333,7 @@ public:
return m_getter() == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( std::is_same<ValueType, nlohmann::json>::value )
{
if( OPT<nlohmann::json> optval = aSettings->GetJson( m_path ) )
return *optval == m_getter();
}
else
{
if( OPT<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
return *optval == m_getter();
}
// Not in file
return false;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override;
private:
ValueType m_default;
@ -488,36 +454,9 @@ public:
m_default( aDefault )
{ }
void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override
{
if( m_readOnly )
return;
void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override;
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
std::vector<Type> val;
if( js->is_array() )
{
for( const auto& el : js->items() )
val.push_back( el.value().get<Type>() );
}
*m_ptr = val;
}
else if( aResetIfMissing )
*m_ptr = m_default;
}
void Store( JSON_SETTINGS* aSettings) const override
{
nlohmann::json js = nlohmann::json::array();
for( const auto& el : *m_ptr )
js.push_back( el );
aSettings->Set<nlohmann::json>( m_path, js );
}
void Store( JSON_SETTINGS* aSettings) const override;
void SetDefault() override
{
@ -529,23 +468,7 @@ public:
return *m_ptr == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_array() )
{
std::vector<Type> val;
for( const auto& el : js->items() )
val.emplace_back( el.value().get<Type>() );
return val == *m_ptr;
}
}
return false;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override;
protected:
std::vector<Type>* m_ptr;
@ -581,33 +504,9 @@ public:
( *m_ptr )[i] = fromFileFormat( ( *m_ptr )[i] );
}
void Store( JSON_SETTINGS* aSettings) const override
{
nlohmann::json js = nlohmann::json::array();
void Store( JSON_SETTINGS* aSettings) const override;
for( const auto& el : *m_ptr )
js.push_back( toFileFormat( el ) );
aSettings->Set<nlohmann::json>( m_path, js );
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_array() )
{
std::vector<wxString> val;
for( const auto& el : js->items() )
val.emplace_back( fromFileFormat( el.value().get<wxString>() ) );
return val == *m_ptr;
}
}
return false;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override;
private:
wxString toFileFormat( const wxString& aString ) const
@ -651,34 +550,9 @@ public:
m_default( aDefault )
{ }
void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override
{
if( m_readOnly )
return;
void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override;
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_object() )
{
m_ptr->clear();
for( const auto& el : js->items() )
( *m_ptr )[ el.key() ] = el.value().get<Value>();
}
}
else if( aResetIfMissing )
*m_ptr = m_default;
}
void Store( JSON_SETTINGS* aSettings) const override
{
nlohmann::json js( {} );
for( const auto& el : *m_ptr )
js[ el.first ] = el.second;
aSettings->Set<nlohmann::json>( m_path, js );
}
void Store( JSON_SETTINGS* aSettings) const override;
virtual void SetDefault() override
{
@ -690,26 +564,7 @@ public:
return *m_ptr == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_object() )
{
if( m_ptr->size() != js->size() )
return false;
std::map<std::string, Value> val;
for( const auto& el : js->items() )
val[ el.key() ] = el.value().get<Value>();
return val == *m_ptr;
}
}
return false;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override;
private:
std::map<std::string, Value>* m_ptr;
@ -732,40 +587,9 @@ public:
m_default( aDefault )
{ }
void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override
{
if( m_readOnly )
return;
void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override;
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_object() )
{
m_ptr->clear();
for( const auto& el : js->items() )
{
( *m_ptr )[wxString( el.key().c_str(), wxConvUTF8 )] =
el.value().get<wxString>();
}
}
}
else if( aResetIfMissing )
*m_ptr = m_default;
}
void Store( JSON_SETTINGS* aSettings) const override
{
nlohmann::json js( {} );
for( const auto& el : *m_ptr )
{
std::string key( el.first.ToUTF8() );
js[ key ] = el.second;
}
aSettings->Set<nlohmann::json>( m_path, js );
}
void Store( JSON_SETTINGS* aSettings) const override;
virtual void SetDefault() override
{
@ -777,29 +601,7 @@ public:
return *m_ptr == m_default;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override
{
if( OPT<nlohmann::json> js = aSettings->GetJson( m_path ) )
{
if( js->is_object() )
{
if( m_ptr->size() != js->size() )
return false;
std::map<wxString, wxString> val;
for( const auto& el : js->items() )
{
wxString key( el.key().c_str(), wxConvUTF8 );
val[key] = el.value().get<wxString>();
}
return val == *m_ptr;
}
}
return false;
}
bool MatchesFile( JSON_SETTINGS* aSettings ) const override;
private:
std::map<wxString, wxString>* m_ptr;

View File

@ -21,6 +21,7 @@
#ifndef _SETTINGS_MANAGER_H
#define _SETTINGS_MANAGER_H
#include <algorithm>
#include <typeinfo>
#include <core/wx_stl_compat.h> // for wxString hash
#include <settings/color_settings.h>

View File

@ -24,6 +24,7 @@
#include <array>
#include <pcb_calculator_settings.h>
#include <settings/common_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>
#include <wx/config.h>
@ -214,7 +215,9 @@ bool PCB_CALCULATOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
ret &= fromLegacy<int>( aCfg, "Att_selection", "attenuators.type" );
{
nlohmann::json::json_pointer ptr = PointerFromString( "attenuators" );
nlohmann::json::json_pointer ptr =
JSON_SETTINGS_INTERNALS::PointerFromString( "attenuators" );
const std::array<std::string, 4> att_names = { "att_pi", "att_tee",
"att_bridge", "att_splitter" };
double val = 0;
@ -225,13 +228,13 @@ bool PCB_CALCULATOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
ptr.push_back( att );
if( aCfg->Read( "Attenuation", &val ) )
( *this )[ptr]["attenuation"] = val;
( *m_internals )[ptr]["attenuation"] = val;
if( aCfg->Read( "Zin", &val ) )
( *this )[ptr]["zin"] = val;
( *m_internals )[ptr]["zin"] = val;
if( aCfg->Read( "Zout", &val ) )
( *this )[ptr]["zout"] = val;
( *m_internals )[ptr]["zout"] = val;
ptr.pop_back();
aCfg->SetPath( "../.." );
@ -269,7 +272,9 @@ bool PCB_CALCULATOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
ret &= fromLegacy<int>( aCfg, "Transline_selection", "trans_line.selection" );
{
nlohmann::json::json_pointer ptr = PointerFromString( "trans_line" );
nlohmann::json::json_pointer ptr =
JSON_SETTINGS_INTERNALS::PointerFromString( "trans_line" );
wxString key;
double value = 0;
int units = 0;
@ -295,7 +300,7 @@ bool PCB_CALCULATOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
aCfg->Read( key, &units );
ptr.push_back( "units" );
( *this )[ptr].push_back( { { dest.ToStdString(), units } } );
( *m_internals )[ptr].push_back( { { dest.ToStdString(), units } } );
ptr.pop_back();
}
@ -304,7 +309,7 @@ bool PCB_CALCULATOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
aCfg->Read( key, &value );
ptr.push_back( "values" );
( *this )[ptr].push_back( { { dest.ToStdString(), value } } );
( *m_internals )[ptr].push_back( { { dest.ToStdString(), value } } );
ptr.pop_back();
}

View File

@ -25,6 +25,7 @@
#define _PCB_CALCULATOR_SETTINGS_H
#include <array>
#include <unordered_map>
#include <settings/app_settings.h>
class PCB_CALCULATOR_SETTINGS : public APP_SETTINGS_BASE

View File

@ -28,6 +28,7 @@
#include <board_design_settings.h>
#include <drc/drc_item.h>
#include <drc/drc_engine.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>
#include <project/project_file.h>
#include <advanced_config.h>
@ -622,10 +623,10 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std:
try
{
at( "rules" ).erase( "solder_mask_clearance" );
at( "rules" ).erase( "solder_mask_min_width" );
at( "rules" ).erase( "solder_paste_clearance" );
at( "rules" ).erase( "solder_paste_margin_ratio" );
At( "rules" ).erase( "solder_mask_clearance" );
At( "rules" ).erase( "solder_mask_min_width" );
At( "rules" ).erase( "solder_paste_clearance" );
At( "rules" ).erase( "solder_paste_margin_ratio" );
}
catch( ... )
{}
@ -765,19 +766,19 @@ bool BOARD_DESIGN_SETTINGS::migrateSchema0to1()
* 1: Mils
* 2: Millimetres
*/
nlohmann::json::json_pointer units_ptr( "/defaults/dimension_units" );
nlohmann::json::json_pointer precision_ptr( "/defaults/dimension_precision" );
std::string units_ptr( "defaults.dimension_units" );
std::string precision_ptr( "defaults.dimension_precision" );
if( !( contains( units_ptr ) && contains( precision_ptr ) &&
at( units_ptr ).is_number_integer() &&
at( precision_ptr ).is_number_integer() ) )
if( !( Contains( units_ptr ) && Contains( precision_ptr ) &&
At( units_ptr ).is_number_integer() &&
At( precision_ptr ).is_number_integer() ) )
{
// if either is missing or invalid, migration doesn't make sense
return true;
}
int units = at( units_ptr ).get<int>();
int precision = at( precision_ptr ).get<int>();
int units = Get<int>( units_ptr ).value();
int precision = Get<int>( precision_ptr ).value();
// The enum maps directly to precision if the units is mils
int extraDigits = 0;
@ -791,7 +792,7 @@ bool BOARD_DESIGN_SETTINGS::migrateSchema0to1()
precision += extraDigits;
( *this )[precision_ptr] = precision;
Set( precision_ptr, precision );
return true;
}
@ -823,36 +824,35 @@ bool BOARD_DESIGN_SETTINGS::LoadFromFile( const wxString& aDirectory )
std::string bp = "board.design_settings.rule_severities.";
std::string rs = "rule_severities.";
if( OPT<bool> v =
project->Get<bool>( PointerFromString( bp + "legacy_no_courtyard_defined" ) ) )
if( OPT<bool> v = project->Get<bool>( bp + "legacy_no_courtyard_defined" ) )
{
if( *v )
( *this )[PointerFromString( rs + drcName( DRCE_MISSING_COURTYARD ) )] = "error";
Set( rs + drcName( DRCE_MISSING_COURTYARD ), "error" );
else
( *this )[PointerFromString( rs + drcName( DRCE_MISSING_COURTYARD ) )] = "ignore";
Set( rs + drcName( DRCE_MISSING_COURTYARD ), "ignore" );
project->erase( PointerFromString( bp + "legacy_no_courtyard_defined" ) );
project->Internals()->erase( m_internals->PointerFromString( bp + "legacy_no_courtyard_defined" ) );
migrated = true;
}
if( OPT<bool> v = project->Get<bool>( PointerFromString( bp + "legacy_courtyards_overlap" ) ) )
if( OPT<bool> v = project->Get<bool>( bp + "legacy_courtyards_overlap" ) )
{
if( *v )
( *this )[PointerFromString( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ) )] = "error";
Set( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ), "error" );
else
( *this )[PointerFromString( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ) )] = "ignore";
Set( rs + drcName( DRCE_OVERLAPPING_FOOTPRINTS ), "ignore" );
project->erase( PointerFromString( bp + "legacy_courtyards_overlap" ) );
project->Internals()->erase( JSON_SETTINGS_INTERNALS::PointerFromString( bp + "legacy_courtyards_overlap" ) );
migrated = true;
}
if( project->contains( "legacy" ) )
if( Contains( "legacy" ) )
{
// This defaults to false for new boards, but version 5.1.x and prior kept the fillets
// so we do the same for legacy boards.
m_ZoneKeepExternalFillets = true;
project->at( "legacy" ).erase( "pcbnew" );
project->At( "legacy" ).erase( "pcbnew" );
}
// Now that we have everything, we need to load again

View File

@ -23,6 +23,7 @@
#include <layers_id_colors_and_visibility.h>
#include <pgm_base.h>
#include <settings/common_settings.h>
#include <settings/json_settings_internals.h>
#include <settings/parameters.h>
#include <settings/settings_manager.h>
#include <wx/config.h>
@ -317,7 +318,7 @@ bool FOOTPRINT_EDITOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
{ "", true, F_Fab }
} );
( *this )[PointerFromString( "design_settings.default_footprint_text_items" )] = textItems;
Set( "design_settings.default_footprint_text_items", textItems );
ret &= fromLegacyString( aCfg, "FpEditorRefDefaultText", "design_settings.default_footprint_text_items.0.0" );
ret &= fromLegacy<bool>( aCfg, "FpEditorRefDefaultVisibility", "design_settings.default_footprint_text_items.0.1" );
@ -371,7 +372,7 @@ bool FOOTPRINT_EDITOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
manager.SaveColorSettings( cs, "board" );
( *this )[PointerFromString( "appearance.color_theme" )] = "user_footprints";
( *m_internals )[m_internals->PointerFromString( "appearance.color_theme" )] = "user_footprints";
double x, y;
f = "ModEditFrame";
@ -385,8 +386,8 @@ bool FOOTPRINT_EDITOR_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
x = From_User_Unit( u, x );
y = From_User_Unit( u, y );
( *this )[PointerFromString( "window.grid.user_grid_x" )] = StringFromValue( u, x );
( *this )[PointerFromString( "window.grid.user_grid_y" )] = StringFromValue( u, y );
Set( "window.grid.user_grid_x", StringFromValue( u, x ) );
Set( "window.grid.user_grid_y", StringFromValue( u, y ) );
}
return ret;
@ -409,12 +410,12 @@ bool FOOTPRINT_EDITOR_SETTINGS::migrateSchema0to1()
return false;
}
nlohmann::json::json_pointer theme_ptr( "/appearance/color_theme" );
std::string theme_ptr( "appearance.color_theme" );
if( !count( theme_ptr ) )
if( !Count( theme_ptr ) )
return true;
wxString selected = at( theme_ptr ).get<wxString>();
wxString selected = At( theme_ptr ).get<wxString>();
wxString search = selected + wxT( "_footprints" );
for( COLOR_SETTINGS* settings : Pgm().GetSettingsManager().GetColorSettingsList() )
@ -423,7 +424,7 @@ bool FOOTPRINT_EDITOR_SETTINGS::migrateSchema0to1()
{
wxLogTrace( traceSettings, "Updating footprint editor theme from %s to %s",
selected, search );
( *this )[theme_ptr] = search;
Set( theme_ptr, search );
return true;
}
}

View File

@ -608,7 +608,7 @@ bool PCBNEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
js.push_back( i );
}
( *this )[PointerFromString( "export_svg.layers" ) ] = js;
Set( "export_svg.layers", js );
}
{
@ -639,7 +639,7 @@ bool PCBNEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
}
}
( *this )[PointerFromString( "action_plugins" ) ] = js;
Set( "action_plugins", js );
}
//
@ -706,10 +706,10 @@ bool PCBNEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
const std::string p = "pcbnew.InteractiveRouter.";
( *this )[PointerFromString( "tools.pns.meta" )] = nlohmann::json( {
{ "filename", "pns" },
{ "version", 0 }
} );
Set( "tools.pns.meta", nlohmann::json( {
{ "filename", "pns" },
{ "version", 0 }
} ) );
ret &= fromLegacy<int>( aCfg, p + "Mode", "tools.pns.mode" );
ret &= fromLegacy<int>( aCfg, p + "OptimizerEffort", "tools.pns.effort" );
@ -728,7 +728,7 @@ bool PCBNEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
ret &= fromLegacy<bool>( aCfg, p + "InlineDragEnabled", "tools.pns.inline_drag" );
// Initialize some new PNS settings to legacy behaviors if coming from legacy
( *this )[PointerFromString( "tools.pns.fix_all_segments" )] = false;
Set( "tools.pns.fix_all_segments", false );
// Migrate color settings that were stored in the pcbnew config file
@ -766,7 +766,7 @@ bool PCBNEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
Pgm().GetSettingsManager().SaveColorSettings( cs, "board" );
( *this )[PointerFromString( "appearance.color_theme" )] = cs->GetFilename();
Set( "appearance.color_theme", cs->GetFilename() );
double x, y;
@ -779,8 +779,8 @@ bool PCBNEW_SETTINGS::MigrateFromLegacy( wxConfigBase* aCfg )
x = From_User_Unit( u, x );
y = From_User_Unit( u, y );
( *this )[PointerFromString( "window.grid.user_grid_x" )] = StringFromValue( u, x );
( *this )[PointerFromString( "window.grid.user_grid_y" )] = StringFromValue( u, y );
Set( "window.grid.user_grid_x", StringFromValue( u, x ) );
Set( "window.grid.user_grid_y", StringFromValue( u, y ) );
}
// Footprint editor settings were stored in pcbnew config file. Migrate them here.