KiCad PCB EDA Suite
json_settings.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
5  * Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <algorithm>
22 #include <fstream>
23 #include <iomanip>
24 #include <utility>
25 #include <sstream>
26 
27 #include <locale_io.h>
28 #include <gal/color4d.h>
29 #include <settings/json_settings.h>
31 #include <settings/parameters.h>
32 #include <wx/config.h>
33 #include <wx/debug.h>
34 #include <wx/fileconf.h>
35 #include <wx/filename.h>
36 #include <wx/wfstream.h>
37 
38 
39 const wxChar* const traceSettings = wxT( "KICAD_SETTINGS" );
40 
41 JSON_SETTINGS::JSON_SETTINGS( const wxString& aFilename, SETTINGS_LOC aLocation,
42  int aSchemaVersion, bool aCreateIfMissing, bool aCreateIfDefault,
43  bool aWriteFile ) :
44  nlohmann::json(),
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 ),
54  m_manager( nullptr )
55 {
56  try
57  {
58  ( *this )[PointerFromString( "meta.filename" )] = GetFullFilename();
59  }
60  catch( ... )
61  {
62  wxLogTrace( traceSettings, "Error: Could not create filename field for %s",
63  GetFullFilename() );
64  }
65 
66 
67  m_params.emplace_back(
68  new PARAM<int>( "meta.version", &m_schemaVersion, m_schemaVersion, true ) );
69 }
70 
71 
73 {
74  for( auto param: m_params )
75  delete param;
76 
77  m_params.clear();
78 }
79 
80 
82 {
83  return wxString( m_filename + "." + getFileExt() );
84 }
85 
86 
88 {
89  for( auto param : m_params )
90  {
91  try
92  {
93  param->Load( this, m_resetParamsIfMissing );
94  }
95  catch( ... )
96  {
97  // Skip unreadable parameters in file
98  wxLogTrace( traceSettings, "param '%s' load err", param->GetJsonPath().c_str() );
99  }
100  }
101 }
102 
103 
104 bool JSON_SETTINGS::LoadFromFile( const wxString& aDirectory )
105 {
106  // First, load all params to default values
107  clear();
108  Load();
109 
110  bool success = true;
111  bool migrated = false;
112  bool legacy_migrated = false;
113 
114  LOCALE_IO locale;
115 
116  auto migrateFromLegacy = [&] ( wxFileName& aPath ) {
117  // Backup and restore during migration so that the original can be mutated if convenient
118  bool backed_up = false;
119  wxFileName temp;
120 
121  if( aPath.IsDirWritable() )
122  {
123  temp.AssignTempFileName( aPath.GetFullPath() );
124 
125  if( !wxCopyFile( aPath.GetFullPath(), temp.GetFullPath() ) )
126  {
127  wxLogTrace( traceSettings, "%s: could not create temp file for migration",
128  GetFullFilename() );
129  }
130  else
131  backed_up = true;
132  }
133 
134  // Silence popups if legacy file is read-only
135  wxLogNull doNotLog;
136 
137  wxConfigBase::DontCreateOnDemand();
138  auto cfg = std::make_unique<wxFileConfig>( wxT( "" ), wxT( "" ), aPath.GetFullPath() );
139 
140  // If migrate fails or is not implemented, fall back to built-in defaults that were
141  // already loaded above
142  if( !MigrateFromLegacy( cfg.get() ) )
143  {
144  wxLogTrace( traceSettings,
145  "%s: migrated; not all settings were found in legacy file",
146  GetFullFilename() );
147  }
148  else
149  {
150  wxLogTrace( traceSettings, "%s: migrated from legacy format", GetFullFilename() );
151  }
152 
153  if( backed_up )
154  {
155  cfg.reset();
156 
157  if( !wxCopyFile( temp.GetFullPath(), aPath.GetFullPath() ) )
158  {
159  wxLogTrace( traceSettings,
160  "migrate; copy temp file %s to %s failed",
161  temp.GetFullPath(), aPath.GetFullPath() );
162  }
163 
164  if( !wxRemoveFile( temp.GetFullPath() ) )
165  {
166  wxLogTrace( traceSettings,
167  "migrate; failed to remove temp file %s",
168  temp.GetFullPath() );
169  }
170  }
171 
172  // Either way, we want to clean up the old file afterwards
173  legacy_migrated = true;
174  };
175 
176  wxFileName path;
177 
178  if( aDirectory.empty() )
179  {
180  path.Assign( m_filename );
181  path.SetExt( getFileExt() );
182  }
183  else
184  {
185  wxString dir( aDirectory );
186  path.Assign( dir, m_filename, getFileExt() );
187  }
188 
189  if( !path.Exists() )
190  {
191  // Case 1: legacy migration, no .json extension yet
192  path.SetExt( getLegacyFileExt() );
193 
194  if( path.Exists() )
195  {
196  migrateFromLegacy( path );
197  }
198  // Case 2: legacy filename is different from new one
199  else if( !m_legacy_filename.empty() )
200  {
201  path.SetName( m_legacy_filename );
202 
203  if( path.Exists() )
204  migrateFromLegacy( path );
205  }
206  else
207  {
208  success = false;
209  }
210  }
211  else
212  {
213  if( !path.IsFileWritable() )
214  m_writeFile = false;
215 
216  try
217  {
218  FILE* fp = wxFopen( path.GetFullPath(), wxT( "rt" ) );
219 
220  if( fp )
221  {
222  *static_cast<nlohmann::json*>( this ) = nlohmann::json::parse( fp, nullptr,
223  /* allow_exceptions = */ true,
224  /* ignore_comments = */ true );
225 
226  // If parse succeeds, check if schema migration is required
227  int filever = -1;
228 
229  try
230  {
231  filever = at( PointerFromString( "meta.version" ) ).get<int>();
232  }
233  catch( ... )
234  {
235  wxLogTrace( traceSettings, "%s: file version could not be read!",
236  GetFullFilename() );
237  success = false;
238  }
239 
240  if( filever >= 0 && filever < m_schemaVersion )
241  {
242  wxLogTrace( traceSettings, "%s: attempting migration from version %d to %d",
243  GetFullFilename(), filever, m_schemaVersion );
244 
245  if( Migrate() )
246  {
247  migrated = true;
248  }
249  else
250  {
251  wxLogTrace( traceSettings, "%s: migration failed!", GetFullFilename() );
252  }
253  }
254  else if( filever > m_schemaVersion )
255  {
256  wxLogTrace( traceSettings,
257  "%s: warning: file version %d is newer than latest (%d)",
258  GetFullFilename(), filever, m_schemaVersion );
259  }
260  }
261  else
262  {
263  wxLogTrace( traceSettings, "%s exists but can't be opened for read",
264  GetFullFilename() );
265  }
266  }
267  catch( nlohmann::json::parse_error& error )
268  {
269  wxLogTrace( traceSettings, "Json parse error reading %s: %s",
270  path.GetFullPath(), error.what() );
271  wxLogTrace( traceSettings, "Attempting migration in case file is in legacy format" );
272  migrateFromLegacy( path );
273  }
274  }
275 
276  // Now that we have new data in the JSON structure, load the params again
277  Load();
278 
279  // And finally load any nested settings
280  for( auto settings : m_nested_settings )
281  settings->LoadFromFile();
282 
283  wxLogTrace( traceSettings, "Loaded <%s> with schema %d", GetFullFilename(), m_schemaVersion );
284 
285  // If we migrated, clean up the legacy file (with no extension)
286  if( legacy_migrated || migrated )
287  {
288  if( legacy_migrated && m_deleteLegacyAfterMigration && !wxRemoveFile( path.GetFullPath() ) )
289  {
290  wxLogTrace( traceSettings, "Warning: could not remove legacy file %s",
291  path.GetFullPath() );
292  }
293 
294  // And write-out immediately so that we don't lose data if the program later crashes.
296  SaveToFile( aDirectory, true );
297  }
298 
299  return success;
300 }
301 
302 
304 {
305  bool modified = false;
306 
307  for( auto param : m_params )
308  {
309  modified |= !param->MatchesFile( this );
310  param->Store( this );
311  }
312 
313  return modified;
314 }
315 
316 
318 {
319  for( auto param : m_params )
320  param->SetDefault();
321 }
322 
323 
324 bool JSON_SETTINGS::IsDefault( const std::string& aParamName )
325 {
326  for( const PARAM_BASE* param : m_params )
327  {
328  if( param->GetJsonPath() == aParamName )
329  return param->IsDefault();
330  }
331 
332  return false;
333 }
334 
335 
336 bool JSON_SETTINGS::SaveToFile( const wxString& aDirectory, bool aForce )
337 {
338  if( !m_writeFile )
339  return false;
340 
341  // Default PROJECT won't have a filename set
342  if( m_filename.IsEmpty() )
343  return false;
344 
345  wxFileName path;
346 
347  if( aDirectory.empty() )
348  {
349  path.Assign( m_filename );
350  path.SetExt( getFileExt() );
351  }
352  else
353  {
354  wxString dir( aDirectory );
355  path.Assign( dir, m_filename, getFileExt() );
356  }
357 
358  if( !m_createIfMissing && !path.FileExists() )
359  {
360  wxLogTrace( traceSettings,
361  "File for %s doesn't exist and m_createIfMissing == false; not saving",
362  GetFullFilename() );
363  return false;
364  }
365 
366  // Ensure the path exists, and create it if not.
367  if( !path.DirExists() && !path.Mkdir() )
368  {
369  wxLogTrace( traceSettings, "Warning: could not create path %s, can't save %s",
370  path.GetPath(), GetFullFilename() );
371  return false;
372  }
373 
374  if( ( path.FileExists() && !path.IsFileWritable() ) ||
375  ( !path.FileExists() && !path.IsDirWritable() ) )
376  {
377  wxLogTrace( traceSettings, "File for %s is read-only; not saving", GetFullFilename() );
378  return false;
379  }
380 
381  bool modified = false;
382 
383  for( auto settings : m_nested_settings )
384  modified |= settings->SaveToFile();
385 
386  modified |= Store();
387 
388  if( !modified && !aForce && path.FileExists() )
389  {
390  wxLogTrace( traceSettings, "%s contents not modified, skipping save", GetFullFilename() );
391  return false;
392  }
393  else if( !modified && !aForce && !m_createIfDefault )
394  {
395  wxLogTrace( traceSettings,
396  "%s contents still default and m_createIfDefault == false; not saving",
397  GetFullFilename() );
398  return false;
399  }
400 
401  wxLogTrace( traceSettings, "Saving %s", GetFullFilename() );
402 
404  bool success = true;
405 
406  try
407  {
408  std::stringstream buffer;
409  buffer << std::setw( 2 ) << *this << std::endl;
410 
411  wxFFileOutputStream fileStream( path.GetFullPath(), "wb" );
412 
413  if( !fileStream.IsOk()
414  || !fileStream.WriteAll( buffer.str().c_str(), buffer.str().size() ) )
415  {
416  wxLogTrace( traceSettings, "Warning: could not save %s", GetFullFilename() );
417  success = false;
418  }
419  }
420  catch( nlohmann::json::exception& error )
421  {
422  wxLogTrace( traceSettings, "Catch error: could not save %s. Json error %s",
423  GetFullFilename(), error.what() );
424  success = false;
425  }
426  catch( ... )
427  {
428  wxLogTrace( traceSettings, "Error: could not save %s." );
429  success = false;
430  }
431 
432  return success;
433 }
434 
435 
436 OPT<nlohmann::json> JSON_SETTINGS::GetJson( const std::string& aPath ) const
437 {
438  nlohmann::json::json_pointer ptr = PointerFromString( aPath );
439 
440  if( contains( ptr ) )
441  {
442  try
443  {
444  return OPT<nlohmann::json>{ at( ptr ) };
445  }
446  catch( ... )
447  {
448  }
449  }
450 
451  return OPT<nlohmann::json>{};
452 }
453 
454 
455 void JSON_SETTINGS::registerMigration( int aOldSchemaVersion, int aNewSchemaVersion,
456  std::function<bool()> aMigrator )
457 {
458  wxASSERT( aNewSchemaVersion > aOldSchemaVersion );
459  wxASSERT( aNewSchemaVersion <= m_schemaVersion );
460  m_migrators[aOldSchemaVersion] = std::make_pair( aNewSchemaVersion, aMigrator );
461 }
462 
463 
465 {
466  int filever = at( PointerFromString( "meta.version" ) ).get<int>();
467 
468  while( filever < m_schemaVersion )
469  {
470  if( !m_migrators.count( filever ) )
471  {
472  wxLogTrace( traceSettings, "Migrator missing for %s version %d!",
473  typeid( *this ).name(), filever );
474  return false;
475  }
476 
477  std::pair<int, std::function<bool()>> pair = m_migrators.at( filever );
478 
479  if( pair.second() )
480  {
481  wxLogTrace( traceSettings, "Migrated %s from %d to %d", typeid( *this ).name(),
482  filever, pair.first );
483  filever = pair.first;
484  ( *this )[PointerFromString( "meta.version" )] = filever;
485  }
486  else
487  {
488  wxLogTrace( traceSettings, "Migration failed for %s from %d to %d",
489  typeid( *this ).name(), filever, pair.first );
490  return false;
491  }
492  }
493 
494  return true;
495 }
496 
497 
498 bool JSON_SETTINGS::MigrateFromLegacy( wxConfigBase* aLegacyConfig )
499 {
500  wxLogTrace( traceSettings,
501  "MigrateFromLegacy() not implemented for %s", typeid( *this ).name() );
502  return false;
503 }
504 
505 
506 nlohmann::json::json_pointer JSON_SETTINGS::PointerFromString( std::string aPath )
507 {
508  std::replace( aPath.begin(), aPath.end(), '.', '/' );
509  aPath.insert( 0, "/" );
510 
511  nlohmann::json::json_pointer p;
512 
513  try
514  {
515  p = nlohmann::json::json_pointer( aPath );
516  }
517  catch( ... )
518  {
519  wxASSERT_MSG( false, wxT( "Invalid pointer path in PointerFromString!" ) );
520  }
521 
522  return p;
523 }
524 
525 
526 bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
527  wxString& aTarget )
528 {
529  nlohmann::json::json_pointer ptr = PointerFromString( aPath );
530 
531  if( aObj.contains( ptr ) && aObj.at( ptr ).is_string() )
532  {
533  aTarget = aObj.at( ptr ).get<wxString>();
534  return true;
535  }
536 
537  return false;
538 }
539 
540 
541 bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
542  bool& aTarget )
543 {
544  nlohmann::json::json_pointer ptr = PointerFromString( aPath );
545 
546  if( aObj.contains( ptr ) && aObj.at( ptr ).is_boolean() )
547  {
548  aTarget = aObj.at( ptr ).get<bool>();
549  return true;
550  }
551 
552  return false;
553 }
554 
555 
556 bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
557  int& aTarget )
558 {
559  nlohmann::json::json_pointer ptr = PointerFromString( aPath );
560 
561  if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_integer() )
562  {
563  aTarget = aObj.at( ptr ).get<int>();
564  return true;
565  }
566 
567  return false;
568 }
569 
570 
571 bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
572  unsigned int& aTarget )
573 {
574  nlohmann::json::json_pointer ptr = PointerFromString( aPath );
575 
576  if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_unsigned() )
577  {
578  aTarget = aObj.at( ptr ).get<unsigned int>();
579  return true;
580  }
581 
582  return false;
583 }
584 
585 
586 template<typename ValueType>
587 bool JSON_SETTINGS::fromLegacy( wxConfigBase* aConfig, const std::string& aKey,
588  const std::string& aDest )
589 {
590  ValueType val;
591 
592  if( aConfig->Read( aKey, &val ) )
593  {
594  try
595  {
596  ( *this )[PointerFromString( aDest )] = val;
597  }
598  catch( ... )
599  {
600  wxASSERT_MSG( false, wxT( "Could not write value in fromLegacy!" ) );
601  return false;
602  }
603 
604  return true;
605  }
606 
607  return false;
608 }
609 
610 
611 // Explicitly declare these because we only support a few types anyway, and it means we can keep
612 // wxConfig detail out of the header file
613 template bool JSON_SETTINGS::fromLegacy<int>( wxConfigBase*, const std::string&,
614  const std::string& );
615 
616 template bool JSON_SETTINGS::fromLegacy<double>( wxConfigBase*, const std::string&,
617  const std::string& );
618 
619 template bool JSON_SETTINGS::fromLegacy<bool>( wxConfigBase*, const std::string&,
620  const std::string& );
621 
622 
623 bool JSON_SETTINGS::fromLegacyString( wxConfigBase* aConfig, const std::string& aKey,
624  const std::string& aDest )
625 {
626  wxString str;
627 
628  if( aConfig->Read( aKey, &str ) )
629  {
630  try
631  {
632  ( *this )[PointerFromString( aDest )] = str.ToUTF8();
633  }
634  catch( ... )
635  {
636  wxASSERT_MSG( false, wxT( "Could not write value in fromLegacyString!" ) );
637  return false;
638  }
639 
640  return true;
641  }
642 
643  return false;
644 }
645 
646 
647 bool JSON_SETTINGS::fromLegacyColor( wxConfigBase* aConfig, const std::string& aKey,
648  const std::string& aDest )
649 {
650  wxString str;
651 
652  if( aConfig->Read( aKey, &str ) )
653  {
655  color.SetFromWxString( str );
656 
657  try
658  {
659  nlohmann::json js = nlohmann::json::array( { color.r, color.g, color.b, color.a } );
660  ( *this )[PointerFromString( aDest )] = js;
661  }
662  catch( ... )
663  {
664  wxASSERT_MSG( false, wxT( "Could not write value in fromLegacyColor!" ) );
665  return false;
666  }
667 
668  return true;
669  }
670 
671  return false;
672 }
673 
674 
676 {
677  wxLogTrace( traceSettings, "AddNestedSettings %s", aSettings->GetFilename() );
678  m_nested_settings.push_back( aSettings );
679 }
680 
681 
683 {
684  if( !aSettings )
685  return;
686 
687  auto it = std::find_if( m_nested_settings.begin(), m_nested_settings.end(),
688  [&aSettings]( const JSON_SETTINGS* aPtr ) {
689  return aPtr == aSettings;
690  } );
691 
692  if( it != m_nested_settings.end() )
693  {
694  wxLogTrace( traceSettings, "Flush and release %s", ( *it )->GetFilename() );
695  ( *it )->SaveToFile();
696  m_nested_settings.erase( it );
697  }
698 
699  aSettings->SetParent( nullptr );
700 }
701 
702 
703 // Specializations to allow conversion between wxString and std::string via JSON_SETTINGS API
704 
705 template<> OPT<wxString> JSON_SETTINGS::Get( const std::string& aPath ) const
706 {
707  if( OPT<nlohmann::json> opt_json = GetJson( aPath ) )
708  return wxString( opt_json->get<std::string>().c_str(), wxConvUTF8 );
709 
710  return NULLOPT;
711 }
712 
713 
714 template<> void JSON_SETTINGS::Set<wxString>( const std::string& aPath, wxString aVal )
715 {
716  ( *this )[PointerFromString( std::move( aPath ) ) ] = aVal.ToUTF8();
717 }
718 
719 // Specializations to allow directly reading/writing wxStrings from JSON
720 
721 void to_json( nlohmann::json& aJson, const wxString& aString )
722 {
723  aJson = aString.ToUTF8();
724 }
725 
726 
727 void from_json( const nlohmann::json& aJson, wxString& aString )
728 {
729  aString = wxString( aJson.get<std::string>().c_str(), wxConvUTF8 );
730 }
void SetParent(JSON_SETTINGS *aParent, bool aLoadFromFile=true)
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.
Definition: locale_io.h:40
bool m_createIfMissing
Whether or not the backing store file should be created it if doesn't exist.
wxString GetFilename() const
Definition: json_settings.h:66
int color
Definition: DXF_plotter.cpp:60
virtual wxString getLegacyFileExt() const
bool parse(std::istream &aStream, bool aVerbose)
Parse a PCB or footprint file from the given input stream.
SETTINGS_LOC
Definition: json_settings.h:46
virtual bool LoadFromFile(const wxString &aDirectory="")
Loads the backing file from disk and then calls Load()
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Definition: sch_symbol.cpp:69
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
nlohmann::json json
Definition: gerbview.cpp:41
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)
const auto NULLOPT
Definition: optional.h:9
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)
Definition: json_settings.h:58
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:81
bool IsDefault(const std::string &aParamName)
Checks if the current state of a parameter matches its default 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.
boost::optional< T > OPT
Definition: optional.h:7
bool fromLegacy(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy wxConfig value to a given JSON pointer value.
virtual ~JSON_SETTINGS()
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.
Definition: color4d.h:98