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>
32 #include <settings/parameters.h>
33 #include <wx/config.h>
34 #include <wx/debug.h>
35 #include <wx/fileconf.h>
36 #include <wx/filename.h>
37 #include <wx/log.h>
38 #include <wx/stdstream.h>
39 #include <wx/wfstream.h>
40 
41 const wxChar* const traceSettings = wxT( "KICAD_SETTINGS" );
42 
43 
44 nlohmann::json::json_pointer JSON_SETTINGS_INTERNALS::PointerFromString( std::string aPath )
45 {
46  std::replace( aPath.begin(), aPath.end(), '.', '/' );
47  aPath.insert( 0, "/" );
48 
49  nlohmann::json::json_pointer p;
50 
51  try
52  {
53  p = nlohmann::json::json_pointer( aPath );
54  }
55  catch( ... )
56  {
57  wxASSERT_MSG( false, wxT( "Invalid pointer path in PointerFromString!" ) );
58  }
59 
60  return p;
61 }
62 
63 
64 JSON_SETTINGS::JSON_SETTINGS( const wxString& aFilename, SETTINGS_LOC aLocation,
65  int aSchemaVersion, bool aCreateIfMissing, bool aCreateIfDefault,
66  bool aWriteFile ) :
67  m_filename( aFilename ),
68  m_legacy_filename( "" ),
69  m_location( aLocation ),
70  m_createIfMissing( aCreateIfMissing ),
71  m_createIfDefault( aCreateIfDefault ),
72  m_writeFile( aWriteFile ),
73  m_deleteLegacyAfterMigration( true ),
74  m_resetParamsIfMissing( true ),
75  m_schemaVersion( aSchemaVersion ),
76  m_manager( nullptr )
77 {
78  m_internals = std::make_unique<JSON_SETTINGS_INTERNALS>();
79 
80  try
81  {
82  m_internals->SetFromString( "meta.filename", GetFullFilename() );
83  }
84  catch( ... )
85  {
86  wxLogTrace( traceSettings, "Error: Could not create filename field for %s",
87  GetFullFilename() );
88  }
89 
90 
91  m_params.emplace_back(
92  new PARAM<int>( "meta.version", &m_schemaVersion, m_schemaVersion, true ) );
93 }
94 
95 
97 {
98  for( auto param: m_params )
99  delete param;
100 
101  m_params.clear();
102 }
103 
104 
106 {
107  return wxString( m_filename + "." + getFileExt() );
108 }
109 
110 
111 nlohmann::json& JSON_SETTINGS::At( const std::string& aPath )
112 {
113  return m_internals->At( aPath );
114 }
115 
116 
117 bool JSON_SETTINGS::Contains( const std::string& aPath ) const
118 {
119  return m_internals->contains( JSON_SETTINGS_INTERNALS::PointerFromString( aPath ) );
120 }
121 
122 
123 size_t JSON_SETTINGS::Count( const std::string& aPath ) const
124 {
126 }
127 
128 
130 {
131  return m_internals.get();
132 }
133 
134 
136 {
137  for( auto param : m_params )
138  {
139  try
140  {
141  param->Load( this, m_resetParamsIfMissing );
142  }
143  catch( ... )
144  {
145  // Skip unreadable parameters in file
146  wxLogTrace( traceSettings, "param '%s' load err", param->GetJsonPath().c_str() );
147  }
148  }
149 }
150 
151 
152 bool JSON_SETTINGS::LoadFromFile( const wxString& aDirectory )
153 {
154  // First, load all params to default values
155  m_internals->clear();
156  Load();
157 
158  bool success = true;
159  bool migrated = false;
160  bool legacy_migrated = false;
161 
162  LOCALE_IO locale;
163 
164  auto migrateFromLegacy = [&] ( wxFileName& aPath ) {
165  // Backup and restore during migration so that the original can be mutated if convenient
166  bool backed_up = false;
167  wxFileName temp;
168 
169  if( aPath.IsDirWritable() )
170  {
171  temp.AssignTempFileName( aPath.GetFullPath() );
172 
173  if( !wxCopyFile( aPath.GetFullPath(), temp.GetFullPath() ) )
174  {
175  wxLogTrace( traceSettings, "%s: could not create temp file for migration",
176  GetFullFilename() );
177  }
178  else
179  backed_up = true;
180  }
181 
182  // Silence popups if legacy file is read-only
183  wxLogNull doNotLog;
184 
185  wxConfigBase::DontCreateOnDemand();
186  auto cfg = std::make_unique<wxFileConfig>( wxT( "" ), wxT( "" ), aPath.GetFullPath() );
187 
188  // If migrate fails or is not implemented, fall back to built-in defaults that were
189  // already loaded above
190  if( !MigrateFromLegacy( cfg.get() ) )
191  {
192  wxLogTrace( traceSettings,
193  "%s: migrated; not all settings were found in legacy file",
194  GetFullFilename() );
195  }
196  else
197  {
198  wxLogTrace( traceSettings, "%s: migrated from legacy format", GetFullFilename() );
199  }
200 
201  if( backed_up )
202  {
203  cfg.reset();
204 
205  if( !wxCopyFile( temp.GetFullPath(), aPath.GetFullPath() ) )
206  {
207  wxLogTrace( traceSettings,
208  "migrate; copy temp file %s to %s failed",
209  temp.GetFullPath(), aPath.GetFullPath() );
210  }
211 
212  if( !wxRemoveFile( temp.GetFullPath() ) )
213  {
214  wxLogTrace( traceSettings,
215  "migrate; failed to remove temp file %s",
216  temp.GetFullPath() );
217  }
218  }
219 
220  // Either way, we want to clean up the old file afterwards
221  legacy_migrated = true;
222  };
223 
224  wxFileName path;
225 
226  if( aDirectory.empty() )
227  {
228  path.Assign( m_filename );
229  path.SetExt( getFileExt() );
230  }
231  else
232  {
233  wxString dir( aDirectory );
234  path.Assign( dir, m_filename, getFileExt() );
235  }
236 
237  if( !path.Exists() )
238  {
239  // Case 1: legacy migration, no .json extension yet
240  path.SetExt( getLegacyFileExt() );
241 
242  if( path.Exists() )
243  {
244  migrateFromLegacy( path );
245  }
246  // Case 2: legacy filename is different from new one
247  else if( !m_legacy_filename.empty() )
248  {
249  path.SetName( m_legacy_filename );
250 
251  if( path.Exists() )
252  migrateFromLegacy( path );
253  }
254  else
255  {
256  success = false;
257  }
258  }
259  else
260  {
261  if( !path.IsFileWritable() )
262  m_writeFile = false;
263 
264  try
265  {
266  wxFFileInputStream fp( path.GetFullPath(), wxT( "rt" ) );
267  wxStdInputStream fstream( fp );
268 
269  if( fp.IsOk() )
270  {
271  *static_cast<nlohmann::json*>( m_internals.get() ) =
272  nlohmann::json::parse( fstream, nullptr,
273  /* allow_exceptions = */ true,
274  /* ignore_comments = */ true );
275 
276  // If parse succeeds, check if schema migration is required
277  int filever = -1;
278 
279  try
280  {
281  filever = m_internals->Get<int>( "meta.version" );
282  }
283  catch( ... )
284  {
285  wxLogTrace( traceSettings, "%s: file version could not be read!",
286  GetFullFilename() );
287  success = false;
288  }
289 
290  if( filever >= 0 && filever < m_schemaVersion )
291  {
292  wxLogTrace( traceSettings, "%s: attempting migration from version %d to %d",
293  GetFullFilename(), filever, m_schemaVersion );
294 
295  if( Migrate() )
296  {
297  migrated = true;
298  }
299  else
300  {
301  wxLogTrace( traceSettings, "%s: migration failed!", GetFullFilename() );
302  }
303  }
304  else if( filever > m_schemaVersion )
305  {
306  wxLogTrace( traceSettings,
307  "%s: warning: file version %d is newer than latest (%d)",
308  GetFullFilename(), filever, m_schemaVersion );
309  }
310  }
311  else
312  {
313  wxLogTrace( traceSettings, "%s exists but can't be opened for read",
314  GetFullFilename() );
315  }
316  }
317  catch( nlohmann::json::parse_error& error )
318  {
319  wxLogTrace( traceSettings, "Json parse error reading %s: %s",
320  path.GetFullPath(), error.what() );
321  wxLogTrace( traceSettings, "Attempting migration in case file is in legacy format" );
322  migrateFromLegacy( path );
323  }
324  }
325 
326  // Now that we have new data in the JSON structure, load the params again
327  Load();
328 
329  // And finally load any nested settings
330  for( auto settings : m_nested_settings )
331  settings->LoadFromFile();
332 
333  wxLogTrace( traceSettings, "Loaded <%s> with schema %d", GetFullFilename(), m_schemaVersion );
334 
335  // If we migrated, clean up the legacy file (with no extension)
336  if( legacy_migrated || migrated )
337  {
338  if( legacy_migrated && m_deleteLegacyAfterMigration && !wxRemoveFile( path.GetFullPath() ) )
339  {
340  wxLogTrace( traceSettings, "Warning: could not remove legacy file %s",
341  path.GetFullPath() );
342  }
343 
344  // And write-out immediately so that we don't lose data if the program later crashes.
346  SaveToFile( aDirectory, true );
347  }
348 
349  return success;
350 }
351 
352 
354 {
355  bool modified = false;
356 
357  for( auto param : m_params )
358  {
359  modified |= !param->MatchesFile( this );
360  param->Store( this );
361  }
362 
363  return modified;
364 }
365 
366 
368 {
369  for( auto param : m_params )
370  param->SetDefault();
371 }
372 
373 
374 bool JSON_SETTINGS::SaveToFile( const wxString& aDirectory, bool aForce )
375 {
376  if( !m_writeFile )
377  return false;
378 
379  // Default PROJECT won't have a filename set
380  if( m_filename.IsEmpty() )
381  return false;
382 
383  wxFileName path;
384 
385  if( aDirectory.empty() )
386  {
387  path.Assign( m_filename );
388  path.SetExt( getFileExt() );
389  }
390  else
391  {
392  wxString dir( aDirectory );
393  path.Assign( dir, m_filename, getFileExt() );
394  }
395 
396  if( !m_createIfMissing && !path.FileExists() )
397  {
398  wxLogTrace( traceSettings,
399  "File for %s doesn't exist and m_createIfMissing == false; not saving",
400  GetFullFilename() );
401  return false;
402  }
403 
404  // Ensure the path exists, and create it if not.
405  if( !path.DirExists() && !path.Mkdir() )
406  {
407  wxLogTrace( traceSettings, "Warning: could not create path %s, can't save %s",
408  path.GetPath(), GetFullFilename() );
409  return false;
410  }
411 
412  if( ( path.FileExists() && !path.IsFileWritable() ) ||
413  ( !path.FileExists() && !path.IsDirWritable() ) )
414  {
415  wxLogTrace( traceSettings, "File for %s is read-only; not saving", GetFullFilename() );
416  return false;
417  }
418 
419  bool modified = false;
420 
421  for( auto settings : m_nested_settings )
422  modified |= settings->SaveToFile();
423 
424  modified |= Store();
425 
426  if( !modified && !aForce && path.FileExists() )
427  {
428  wxLogTrace( traceSettings, "%s contents not modified, skipping save", GetFullFilename() );
429  return false;
430  }
431  else if( !modified && !aForce && !m_createIfDefault )
432  {
433  wxLogTrace( traceSettings,
434  "%s contents still default and m_createIfDefault == false; not saving",
435  GetFullFilename() );
436  return false;
437  }
438 
439  wxLogTrace( traceSettings, "Saving %s", GetFullFilename() );
440 
442  bool success = true;
443 
444  try
445  {
446  std::stringstream buffer;
447  buffer << std::setw( 2 ) << *m_internals << std::endl;
448 
449  wxFFileOutputStream fileStream( path.GetFullPath(), "wb" );
450 
451  if( !fileStream.IsOk()
452  || !fileStream.WriteAll( buffer.str().c_str(), buffer.str().size() ) )
453  {
454  wxLogTrace( traceSettings, "Warning: could not save %s", GetFullFilename() );
455  success = false;
456  }
457  }
458  catch( nlohmann::json::exception& error )
459  {
460  wxLogTrace( traceSettings, "Catch error: could not save %s. Json error %s",
461  GetFullFilename(), error.what() );
462  success = false;
463  }
464  catch( ... )
465  {
466  wxLogTrace( traceSettings, "Error: could not save %s." );
467  success = false;
468  }
469 
470  return success;
471 }
472 
473 
474 OPT<nlohmann::json> JSON_SETTINGS::GetJson( const std::string& aPath ) const
475 {
476  nlohmann::json::json_pointer ptr = m_internals->PointerFromString( aPath );
477 
478  if( m_internals->contains( ptr ) )
479  {
480  try
481  {
482  return OPT<nlohmann::json>{ m_internals->at( ptr ) };
483  }
484  catch( ... )
485  {
486  }
487  }
488 
489  return OPT<nlohmann::json>{};
490 }
491 
492 
493 template<typename ValueType>
494 OPT<ValueType> JSON_SETTINGS::Get( const std::string& aPath ) const
495 {
496  if( OPT<nlohmann::json> ret = GetJson( aPath ) )
497  {
498  try
499  {
500  return ret->get<ValueType>();
501  }
502  catch( ... )
503  {
504  }
505  }
506 
507  return NULLOPT;
508 }
509 
510 
511 // Instantiate all required templates here to allow reducing scope of json.hpp
512 template OPT<bool> JSON_SETTINGS::Get<bool>( const std::string& aPath ) const;
513 template OPT<double> JSON_SETTINGS::Get<double>( const std::string& aPath ) const;
514 template OPT<float> JSON_SETTINGS::Get<float>( const std::string& aPath ) const;
515 template OPT<int> JSON_SETTINGS::Get<int>( const std::string& aPath ) const;
516 template OPT<unsigned int> JSON_SETTINGS::Get<unsigned int>( const std::string& aPath ) const;
517 template OPT<unsigned long long> JSON_SETTINGS::Get<unsigned long long>( const std::string& aPath ) const;
518 template OPT<std::string> JSON_SETTINGS::Get<std::string>( const std::string& aPath ) const;
519 template OPT<nlohmann::json> JSON_SETTINGS::Get<nlohmann::json>( const std::string& aPath ) const;
520 template OPT<KIGFX::COLOR4D> JSON_SETTINGS::Get<KIGFX::COLOR4D>( const std::string& aPath ) const;
521 
522 
523 template<typename ValueType>
524 void JSON_SETTINGS::Set( const std::string& aPath, ValueType aVal )
525 {
526  m_internals->SetFromString( aPath, aVal );
527 }
528 
529 
530 // Instantiate all required templates here to allow reducing scope of json.hpp
531 template void JSON_SETTINGS::Set<bool>( const std::string& aPath, bool aValue );
532 template void JSON_SETTINGS::Set<double>( const std::string& aPath, double aValue );
533 template void JSON_SETTINGS::Set<float>( const std::string& aPath, float aValue );
534 template void JSON_SETTINGS::Set<int>( const std::string& aPath, int aValue );
535 template void JSON_SETTINGS::Set<unsigned int>( const std::string& aPath, unsigned int aValue );
536 template void JSON_SETTINGS::Set<unsigned long long>( const std::string& aPath, unsigned long long aValue );
537 template void JSON_SETTINGS::Set<const char*>( const std::string& aPath, const char* aValue );
538 template void JSON_SETTINGS::Set<std::string>( const std::string& aPath, std::string aValue );
539 template void JSON_SETTINGS::Set<nlohmann::json>( const std::string& aPath, nlohmann::json aValue );
540 template void JSON_SETTINGS::Set<KIGFX::COLOR4D>( const std::string& aPath, KIGFX::COLOR4D aValue );
541 
542 
543 void JSON_SETTINGS::registerMigration( int aOldSchemaVersion, int aNewSchemaVersion,
544  std::function<bool()> aMigrator )
545 {
546  wxASSERT( aNewSchemaVersion > aOldSchemaVersion );
547  wxASSERT( aNewSchemaVersion <= m_schemaVersion );
548  m_migrators[aOldSchemaVersion] = std::make_pair( aNewSchemaVersion, aMigrator );
549 }
550 
551 
553 {
554  int filever = m_internals->Get<int>( "meta.version" );
555 
556  while( filever < m_schemaVersion )
557  {
558  if( !m_migrators.count( filever ) )
559  {
560  wxLogTrace( traceSettings, "Migrator missing for %s version %d!",
561  typeid( *this ).name(), filever );
562  return false;
563  }
564 
565  std::pair<int, std::function<bool()>> pair = m_migrators.at( filever );
566 
567  if( pair.second() )
568  {
569  wxLogTrace( traceSettings, "Migrated %s from %d to %d", typeid( *this ).name(),
570  filever, pair.first );
571  filever = pair.first;
572  m_internals->At( "meta.version" ) = filever;
573  }
574  else
575  {
576  wxLogTrace( traceSettings, "Migration failed for %s from %d to %d",
577  typeid( *this ).name(), filever, pair.first );
578  return false;
579  }
580  }
581 
582  return true;
583 }
584 
585 
586 bool JSON_SETTINGS::MigrateFromLegacy( wxConfigBase* aLegacyConfig )
587 {
588  wxLogTrace( traceSettings,
589  "MigrateFromLegacy() not implemented for %s", typeid( *this ).name() );
590  return false;
591 }
592 
593 
594 bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
595  wxString& aTarget )
596 {
597  nlohmann::json::json_pointer ptr = JSON_SETTINGS_INTERNALS::PointerFromString( aPath );
598 
599  if( aObj.contains( ptr ) && aObj.at( ptr ).is_string() )
600  {
601  aTarget = aObj.at( ptr ).get<wxString>();
602  return true;
603  }
604 
605  return false;
606 }
607 
608 
609 bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
610  bool& aTarget )
611 {
612  nlohmann::json::json_pointer ptr = JSON_SETTINGS_INTERNALS::PointerFromString( aPath );
613 
614  if( aObj.contains( ptr ) && aObj.at( ptr ).is_boolean() )
615  {
616  aTarget = aObj.at( ptr ).get<bool>();
617  return true;
618  }
619 
620  return false;
621 }
622 
623 
624 bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
625  int& aTarget )
626 {
627  nlohmann::json::json_pointer ptr = JSON_SETTINGS_INTERNALS::PointerFromString( aPath );
628 
629  if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_integer() )
630  {
631  aTarget = aObj.at( ptr ).get<int>();
632  return true;
633  }
634 
635  return false;
636 }
637 
638 
639 bool JSON_SETTINGS::SetIfPresent( const nlohmann::json& aObj, const std::string& aPath,
640  unsigned int& aTarget )
641 {
642  nlohmann::json::json_pointer ptr = JSON_SETTINGS_INTERNALS::PointerFromString( aPath );
643 
644  if( aObj.contains( ptr ) && aObj.at( ptr ).is_number_unsigned() )
645  {
646  aTarget = aObj.at( ptr ).get<unsigned int>();
647  return true;
648  }
649 
650  return false;
651 }
652 
653 
654 template<typename ValueType>
655 bool JSON_SETTINGS::fromLegacy( wxConfigBase* aConfig, const std::string& aKey,
656  const std::string& aDest )
657 {
658  ValueType val;
659 
660  if( aConfig->Read( aKey, &val ) )
661  {
662  try
663  {
664  ( *m_internals )[aDest] = val;
665  }
666  catch( ... )
667  {
668  wxASSERT_MSG( false, wxT( "Could not write value in fromLegacy!" ) );
669  return false;
670  }
671 
672  return true;
673  }
674 
675  return false;
676 }
677 
678 
679 // Explicitly declare these because we only support a few types anyway, and it means we can keep
680 // wxConfig detail out of the header file
681 template bool JSON_SETTINGS::fromLegacy<int>( wxConfigBase*, const std::string&,
682  const std::string& );
683 
684 template bool JSON_SETTINGS::fromLegacy<double>( wxConfigBase*, const std::string&,
685  const std::string& );
686 
687 template bool JSON_SETTINGS::fromLegacy<bool>( wxConfigBase*, const std::string&,
688  const std::string& );
689 
690 
691 bool JSON_SETTINGS::fromLegacyString( wxConfigBase* aConfig, const std::string& aKey,
692  const std::string& aDest )
693 {
694  wxString str;
695 
696  if( aConfig->Read( aKey, &str ) )
697  {
698  try
699  {
700  ( *m_internals )[aDest] = str.ToUTF8();
701  }
702  catch( ... )
703  {
704  wxASSERT_MSG( false, wxT( "Could not write value in fromLegacyString!" ) );
705  return false;
706  }
707 
708  return true;
709  }
710 
711  return false;
712 }
713 
714 
715 bool JSON_SETTINGS::fromLegacyColor( wxConfigBase* aConfig, const std::string& aKey,
716  const std::string& aDest )
717 {
718  wxString str;
719 
720  if( aConfig->Read( aKey, &str ) )
721  {
723  color.SetFromWxString( str );
724 
725  try
726  {
727  nlohmann::json js = nlohmann::json::array( { color.r, color.g, color.b, color.a } );
728  ( *m_internals )[aDest] = js;
729  }
730  catch( ... )
731  {
732  wxASSERT_MSG( false, wxT( "Could not write value in fromLegacyColor!" ) );
733  return false;
734  }
735 
736  return true;
737  }
738 
739  return false;
740 }
741 
742 
744 {
745  wxLogTrace( traceSettings, "AddNestedSettings %s", aSettings->GetFilename() );
746  m_nested_settings.push_back( aSettings );
747 }
748 
749 
751 {
752  if( !aSettings )
753  return;
754 
755  auto it = std::find_if( m_nested_settings.begin(), m_nested_settings.end(),
756  [&aSettings]( const JSON_SETTINGS* aPtr ) {
757  return aPtr == aSettings;
758  } );
759 
760  if( it != m_nested_settings.end() )
761  {
762  wxLogTrace( traceSettings, "Flush and release %s", ( *it )->GetFilename() );
763  ( *it )->SaveToFile();
764  m_nested_settings.erase( it );
765  }
766 
767  aSettings->SetParent( nullptr );
768 }
769 
770 
771 // Specializations to allow conversion between wxString and std::string via JSON_SETTINGS API
772 
773 template<> OPT<wxString> JSON_SETTINGS::Get( const std::string& aPath ) const
774 {
775  if( OPT<nlohmann::json> opt_json = GetJson( aPath ) )
776  return wxString( opt_json->get<std::string>().c_str(), wxConvUTF8 );
777 
778  return NULLOPT;
779 }
780 
781 
782 template<> void JSON_SETTINGS::Set<wxString>( const std::string& aPath, wxString aVal )
783 {
784  ( *m_internals )[aPath] = aVal.ToUTF8();
785 }
786 
787 // Specializations to allow directly reading/writing wxStrings from JSON
788 
789 void to_json( nlohmann::json& aJson, const wxString& aString )
790 {
791  aJson = aString.ToUTF8();
792 }
793 
794 
795 void from_json( const nlohmann::json& aJson, wxString& aString )
796 {
797  aString = wxString( aJson.get<std::string>().c_str(), wxConvUTF8 );
798 }
void SetParent(JSON_SETTINGS *aParent, bool aLoadFromFile=true)
void ResetToDefaults()
Resets all parameters to default values.
void Set(const std::string &aPath, ValueType aVal)
Stores a value into the JSON document Will throw an exception if ValueType isn't something that the l...
virtual bool Store()
Stores the current parameters into the JSON document represented by this object Note: this doesn't do...
JSON_SETTINGS_INTERNALS * Internals()
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:72
int color
Definition: DXF_plotter.cpp:57
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()
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
static nlohmann::json::json_pointer PointerFromString(std::string aPath)
Builds a JSON pointer based on a given string.
nlohmann::json json
Definition: gerbview.cpp:41
nlohmann::json & At(const std::string &aPath)
Wrappers for the underlying JSON API so that most consumers don't need json.hpp All of these function...
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.
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>
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
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)
std::unique_ptr< JSON_SETTINGS_INTERNALS > m_internals
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:63
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.
OPT< ValueType > Get(const std::string &aPath) const
Fetches a value from within the JSON document.
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.
bool Contains(const std::string &aPath) const
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
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.
size_t Count(const std::string &aPath) const
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:103