32 #include <wx/config.h> 34 #include <wx/fileconf.h> 35 #include <wx/filename.h> 36 #include <wx/wfstream.h> 42 int aSchemaVersion,
bool aCreateIfMissing,
bool aCreateIfDefault,
45 m_filename( aFilename ),
46 m_legacy_filename(
"" ),
47 m_location( aLocation ),
48 m_createIfMissing( aCreateIfMissing ),
49 m_createIfDefault( aCreateIfDefault ),
50 m_writeFile( aWriteFile ),
51 m_deleteLegacyAfterMigration( true ),
52 m_resetParamsIfMissing( true ),
53 m_schemaVersion( aSchemaVersion ),
62 wxLogTrace(
traceSettings,
"Error: Could not create filename field for %s",
98 wxLogTrace(
traceSettings,
"param '%s' load err", param->GetJsonPath().c_str() );
111 bool migrated =
false;
112 bool legacy_migrated =
false;
116 auto migrateFromLegacy = [&] ( wxFileName& aPath ) {
118 bool backed_up =
false;
121 if( aPath.IsDirWritable() )
123 temp.AssignTempFileName( aPath.GetFullPath() );
125 if( !wxCopyFile( aPath.GetFullPath(), temp.GetFullPath() ) )
127 wxLogTrace(
traceSettings,
"%s: could not create temp file for migration",
134 wxConfigBase::DontCreateOnDemand();
135 auto cfg = std::make_unique<wxFileConfig>( wxT(
"" ), wxT(
"" ), aPath.GetFullPath() );
142 "%s: migrated; not all settings were found in legacy file",
154 if( !wxCopyFile( temp.GetFullPath(), aPath.GetFullPath() ) )
157 "migrate; copy temp file %s to %s failed",
158 temp.GetFullPath(), aPath.GetFullPath() );
161 if( !wxRemoveFile( temp.GetFullPath() ) )
164 "migrate; failed to remove temp file %s",
165 temp.GetFullPath() );
170 legacy_migrated =
true;
175 if( aDirectory.empty() )
182 wxString dir( aDirectory );
193 migrateFromLegacy( path );
201 migrateFromLegacy( path );
210 if( !path.IsFileWritable() )
215 FILE* fp = wxFopen( path.GetFullPath(), wxT(
"rt" ) );
232 wxLogTrace(
traceSettings,
"%s: file version could not be read!",
239 wxLogTrace(
traceSettings,
"%s: attempting migration from version %d to %d",
254 "%s: warning: file version %d is newer than latest (%d)",
260 wxLogTrace(
traceSettings,
"%s exists but can't be opened for read",
264 catch( nlohmann::json::parse_error& error )
266 wxLogTrace(
traceSettings,
"Json parse error reading %s: %s",
267 path.GetFullPath(), error.what() );
268 wxLogTrace(
traceSettings,
"Attempting migration in case file is in legacy format" );
269 migrateFromLegacy( path );
278 settings->LoadFromFile();
283 if( legacy_migrated || migrated )
287 wxLogTrace(
traceSettings,
"Warning: could not remove legacy file %s",
288 path.GetFullPath() );
301 bool modified =
false;
305 modified |= !param->MatchesFile(
this );
306 param->Store(
this );
331 if( aDirectory.empty() )
338 wxString dir( aDirectory );
345 "File for %s doesn't exist and m_createIfMissing == false; not saving",
351 if( !path.DirExists() && !path.Mkdir() )
353 wxLogTrace(
traceSettings,
"Warning: could not create path %s, can't save %s",
358 if( ( path.FileExists() && !path.IsFileWritable() ) ||
359 ( !path.FileExists() && !path.IsDirWritable() ) )
365 bool modified =
false;
368 modified |= settings->SaveToFile();
372 if( !modified && !aForce && path.FileExists() )
380 "%s contents still default and m_createIfDefault == false; not saving",
392 std::stringstream buffer;
393 buffer << std::setw( 2 ) << *
this << std::endl;
395 wxFFileOutputStream fileStream( path.GetFullPath(),
"wb" );
397 if( !fileStream.IsOk()
398 || !fileStream.WriteAll( buffer.str().c_str(), buffer.str().size() ) )
404 catch( nlohmann::json::exception& error )
406 wxLogTrace(
traceSettings,
"Catch error: could not save %s. Json error %s",
440 std::function<
bool()> aMigrator )
442 wxASSERT( aNewSchemaVersion > aOldSchemaVersion );
444 m_migrators[aOldSchemaVersion] = std::make_pair( aNewSchemaVersion, aMigrator );
456 wxLogTrace(
traceSettings,
"Migrator missing for %s version %d!",
457 typeid( *this ).name(), filever );
461 std::pair<int, std::function<bool()>> pair =
m_migrators.at( filever );
465 wxLogTrace(
traceSettings,
"Migrated %s from %d to %d",
typeid( *this ).name(),
466 filever, pair.first );
467 filever = pair.first;
472 wxLogTrace(
traceSettings,
"Migration failed for %s from %d to %d",
473 typeid( *this ).name(), filever, pair.first );
485 "MigrateFromLegacy() not implemented for %s",
typeid( *this ).name() );
492 std::replace( aPath.begin(), aPath.end(),
'.',
'/' );
493 aPath.insert( 0,
"/" );
495 nlohmann::json::json_pointer p;
499 p = nlohmann::json::json_pointer( aPath );
503 wxASSERT_MSG(
false, wxT(
"Invalid pointer path in PointerFromString!" ) );
515 if( aObj.contains( ptr ) && aObj.at( ptr ).is_string() )
517 aTarget = aObj.at( ptr ).get<wxString>();
530 if( aObj.contains( ptr ) && aObj.at( ptr ).is_boolean() )
532 aTarget = aObj.at( ptr ).get<
bool>();
545 if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_integer() )
547 aTarget = aObj.at( ptr ).get<
int>();
556 unsigned int& aTarget )
560 if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_unsigned() )
562 aTarget = aObj.at( ptr ).get<
unsigned int>();
570 template<
typename ValueType>
572 const std::string& aDest )
576 if( aConfig->Read( aKey, &val ) )
584 wxASSERT_MSG(
false, wxT(
"Could not write value in fromLegacy!" ) );
597 template bool JSON_SETTINGS::fromLegacy<int>( wxConfigBase*,
const std::string&,
598 const std::string& );
600 template bool JSON_SETTINGS::fromLegacy<double>( wxConfigBase*,
const std::string&,
601 const std::string& );
603 template bool JSON_SETTINGS::fromLegacy<bool>( wxConfigBase*,
const std::string&,
604 const std::string& );
608 const std::string& aDest )
612 if( aConfig->Read( aKey, &str ) )
620 wxASSERT_MSG(
false, wxT(
"Could not write value in fromLegacyString!" ) );
632 const std::string& aDest )
636 if( aConfig->Read( aKey, &str ) )
639 color.SetFromWxString( str );
648 wxASSERT_MSG(
false, wxT(
"Could not write value in fromLegacyColor!" ) );
673 return aPtr == aSettings;
678 wxLogTrace(
traceSettings,
"Flush and release %s", ( *it )->GetFilename() );
679 ( *it )->SaveToFile();
692 return wxString( opt_json->get<std::string>().c_str(), wxConvUTF8 );
698 template<>
void JSON_SETTINGS::Set<wxString>(
const std::string& aPath, wxString aVal )
707 aJson = aString.ToUTF8();
713 aString = wxString( aJson.get<std::string>().c_str(), wxConvUTF8 );
void ResetToDefaults()
Resets all parameters to default values.
virtual bool Store()
Stores the current parameters into the JSON document represented by this object Note: this doesn't do...
std::vector< PARAM_BASE * > m_params
The list of parameters (owned by this object)
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
bool m_createIfMissing
Whether or not the backing store file should be created it if doesn't exist.
wxString GetFilename() const
virtual wxString getLegacyFileExt() const
virtual bool LoadFromFile(const wxString &aDirectory="")
Loads the backing file from disk and then calls Load()
OPT< nlohmann::json > GetJson(const std::string &aPath) const
Fetches a JSON object that is a subset of this JSON_SETTINGS object, using a path of the form "key1....
wxString GetFullFilename() const
void from_json(const nlohmann::json &aJson, wxString &aString)
void AddNestedSettings(NESTED_SETTINGS *aSettings)
Transfers ownership of a given NESTED_SETTINGS to this object.
bool m_deleteLegacyAfterMigration
Whether or not to delete legacy file after migration.
OPT< ValueType > Get(const std::string &aPath) const
Fetches a value from within the JSON document.
std::map< int, std::pair< int, std::function< bool()> > > m_migrators
A map of starting schema version to a pair of <ending version, migrator function>
wxString m_filename
The filename (not including path) of this settings file (inicode)
bool Migrate()
Migrates the schema of this settings from the version in the file to the latest version.
NESTED_SETTINGS is a JSON_SETTINGS that lives inside a JSON_SETTINGS.
virtual bool SaveToFile(const wxString &aDirectory="", bool aForce=false)
wxString m_legacy_filename
The filename of the wxConfig legacy file (if different from m_filename)
void to_json(nlohmann::json &aJson, const wxString &aString)
static bool SetIfPresent(const nlohmann::json &aObj, const std::string &aPath, wxString &aTarget)
Sets the given string if the given key/path is present.
std::vector< NESTED_SETTINGS * > m_nested_settings
Nested settings files that live inside this one, if any.
JSON_SETTINGS(const wxString &aFilename, SETTINGS_LOC aLocation, int aSchemaVersion)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
bool fromLegacyString(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy wxConfig string value to a given JSON pointer value.
bool m_resetParamsIfMissing
Whether or not to set parameters to their default value if missing from JSON on Load()
bool fromLegacyColor(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy COLOR4D stored in a wxConfig string to a given JSON pointer value.
void registerMigration(int aOldSchemaVersion, int aNewSchemaVersion, std::function< bool(void)> aMigrator)
Registers a migration from one schema version to another.
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
bool fromLegacy(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy wxConfig value to a given JSON pointer value.
const wxChar *const traceSettings
Flag to enable debug output of settings operations and management.
bool m_createIfDefault
Whether or not the backing store file should be created if all parameters are still at their default ...
void ReleaseNestedSettings(NESTED_SETTINGS *aSettings)
Saves and frees a nested settings object, if it exists within this one.
virtual wxString getFileExt() const
static nlohmann::json::json_pointer PointerFromString(std::string aPath)
Builds a JSON pointer based on a given string.
virtual bool MigrateFromLegacy(wxConfigBase *aLegacyConfig)
Migrates from wxConfig to JSON-based configuration.
int m_schemaVersion
Version of this settings schema.
virtual void Load()
Updates the parameters of this object based on the current JSON document contents.
bool m_writeFile
Whether or not the backing store file should be written.
A color representation with 4 components: red, green, blue, alpha.
void SetParent(JSON_SETTINGS *aParent)