KiCad PCB EDA Suite
Loading...
Searching...
No Matches
settings_manager.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 <[email protected]>
5 * Copyright (C) 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
22#include <regex>
23#include <wx/debug.h>
24#include <wx/dir.h>
25#include <wx/filename.h>
26#include <wx/snglinst.h>
27#include <wx/stdpaths.h>
28#include <wx/utils.h>
29
30#include <build_version.h>
31#include <confirm.h>
33#include <gestfich.h>
35#include <kiway.h>
36#include <lockfile.h>
37#include <macros.h>
38#include <pgm_base.h>
39#include <paths.h>
40#include <project.h>
49
50
52 m_headless( aHeadless ),
53 m_kiway( nullptr ),
54 m_common_settings( nullptr ),
55 m_migration_source(),
56 m_migrateLibraryTables( true )
57{
58 // Check if the settings directory already exists, and if not, perform a migration if possible
59 if( !MigrateIfNeeded() )
60 {
61 m_ok = false;
62 return;
63 }
64
65 m_ok = true;
66
67 // create the common settings shared by all applications. Not loaded immediately
69
70 // Create the built-in color settings
71 // Here to allow the Python API to access the built-in colors
73}
74
76{
77 for( std::unique_ptr<PROJECT>& project : m_projects_list )
78 project.reset();
79
80 m_projects.clear();
81
82 for( std::unique_ptr<JSON_SETTINGS>& settings : m_settings )
83 settings.reset();
84
85 m_settings.clear();
86
87 m_color_settings.clear();
88}
89
90
92{
93 std::unique_ptr<JSON_SETTINGS> ptr( aSettings );
94
95 ptr->SetManager( this );
96
97 wxLogTrace( traceSettings, wxT( "Registered new settings object <%s>" ), ptr->GetFullFilename() );
98
99 if( aLoadNow )
100 ptr->LoadFromFile( GetPathForSettingsFile( ptr.get() ) );
101
102 m_settings.push_back( std::move( ptr ) );
103 return m_settings.back().get();
104}
105
106
108{
109 // TODO(JE) We should check for dirty settings here and write them if so, because
110 // Load() could be called late in the application lifecycle
111
112 std::vector<JSON_SETTINGS*> toLoad;
113
114 // Cache a copy of raw pointers; m_settings may be modified during the load loop
115 std::transform( m_settings.begin(), m_settings.end(), std::back_inserter( toLoad ),
116 []( std::unique_ptr<JSON_SETTINGS>& aSettings )
117 {
118 return aSettings.get();
119 } );
120
121 for( JSON_SETTINGS* settings : toLoad )
122 settings->LoadFromFile( GetPathForSettingsFile( settings ) );
123}
124
125
127{
128 auto it = std::find_if( m_settings.begin(), m_settings.end(),
129 [&aSettings]( const std::unique_ptr<JSON_SETTINGS>& aPtr )
130 {
131 return aPtr.get() == aSettings;
132 } );
133
134 if( it != m_settings.end() )
135 ( *it )->LoadFromFile( GetPathForSettingsFile( it->get() ) );
136}
137
138
140{
141 for( auto&& settings : m_settings )
142 {
143 // Never automatically save color settings, caller should use SaveColorSettings
144 if( dynamic_cast<COLOR_SETTINGS*>( settings.get() ) )
145 continue;
146
147 settings->SaveToFile( GetPathForSettingsFile( settings.get() ) );
148 }
149}
150
151
153{
154 auto it = std::find_if( m_settings.begin(), m_settings.end(),
155 [&aSettings]( const std::unique_ptr<JSON_SETTINGS>& aPtr )
156 {
157 return aPtr.get() == aSettings;
158 } );
159
160 if( it != m_settings.end() )
161 {
162 wxLogTrace( traceSettings, wxT( "Saving %s" ), ( *it )->GetFullFilename() );
163 ( *it )->SaveToFile( GetPathForSettingsFile( it->get() ) );
164 }
165}
166
167
169{
170 auto it = std::find_if( m_settings.begin(), m_settings.end(),
171 [&aSettings]( const std::unique_ptr<JSON_SETTINGS>& aPtr )
172 {
173 return aPtr.get() == aSettings;
174 } );
175
176 if( it != m_settings.end() )
177 {
178 wxLogTrace( traceSettings, wxT( "Flush and release %s" ), ( *it )->GetFullFilename() );
179
180 if( aSave )
181 ( *it )->SaveToFile( GetPathForSettingsFile( it->get() ) );
182
183 size_t typeHash = typeid( *it->get() ).hash_code();
184
185 if( m_app_settings_cache.count( typeHash ) )
186 m_app_settings_cache.erase( typeHash );
187
188 m_settings.erase( it );
189 }
190}
191
192
194{
195 // Find settings the fast way
196 if( m_color_settings.count( aName ) )
197 return m_color_settings.at( aName );
198
199 // Maybe it's the display name (cli is one method of invoke)
200 auto it = std::find_if( m_color_settings.begin(), m_color_settings.end(),
201 [&aName]( const std::pair<wxString, COLOR_SETTINGS*>& p )
202 {
203 return p.second->GetName().Lower() == aName.Lower();
204 } );
205
206 if( it != m_color_settings.end() )
207 {
208 return it->second;
209 }
210
211 // No match? See if we can load it
212 if( !aName.empty() )
213 {
215
216 if( !ret )
217 {
218 ret = registerColorSettings( aName );
220 ret->SetFilename( wxT( "user" ) );
221 ret->SetReadOnly( false );
222 }
223
224 return ret;
225 }
226
227 // This had better work
229}
230
231
233{
234 wxLogTrace( traceSettings, wxT( "Attempting to load color theme %s" ), aName );
235
236 wxFileName fn( GetColorSettingsPath(), aName, wxS( "json" ) );
237
238 if( !fn.IsOk() || !fn.Exists() )
239 {
240 wxLogTrace( traceSettings, wxT( "Theme file %s.json not found, falling back to user" ), aName );
241 return nullptr;
242 }
243
244 COLOR_SETTINGS* settings = RegisterSettings( new COLOR_SETTINGS( aName ) );
245
246 if( settings->GetFilename() != aName.ToStdString() )
247 {
248 wxLogTrace( traceSettings, wxT( "Warning: stored filename is actually %s, " ),
249 settings->GetFilename() );
250 }
251
252 m_color_settings[aName] = settings;
253
254 return settings;
255}
256
257
258class JSON_DIR_TRAVERSER : public wxDirTraverser
259{
260private:
261 std::function<void( const wxFileName& )> m_action;
262
263public:
264 explicit JSON_DIR_TRAVERSER( std::function<void( const wxFileName& )> aAction )
265 : m_action( std::move( aAction ) )
266 {
267 }
268
269 wxDirTraverseResult OnFile( const wxString& aFilePath ) override
270 {
271 wxFileName file( aFilePath );
272
273 if( file.GetExt() == wxS( "json" ) )
274 m_action( file );
275
276 return wxDIR_CONTINUE;
277 }
278
279 wxDirTraverseResult OnDir( const wxString& dirPath ) override
280 {
281 return wxDIR_CONTINUE;
282 }
283};
284
285
286COLOR_SETTINGS* SETTINGS_MANAGER::registerColorSettings( const wxString& aName, bool aAbsolutePath )
287{
288 if( !m_color_settings.count( aName ) )
289 {
290 COLOR_SETTINGS* colorSettings = RegisterSettings( new COLOR_SETTINGS( aName,
291 aAbsolutePath ) );
292 m_color_settings[aName] = colorSettings;
293 }
294
295 return m_color_settings.at( aName );
296}
297
298
300{
301 if( aName.EndsWith( wxT( ".json" ) ) )
302 return registerColorSettings( aName.BeforeLast( '.' ) );
303 else
304 return registerColorSettings( aName );
305}
306
307
309{
310 if( !m_color_settings.count( "user" ) )
311 {
312 COLOR_SETTINGS* settings = registerColorSettings( wxT( "user" ) );
313 settings->SetName( wxT( "User" ) );
314 Save( settings );
315 }
316
317 return m_color_settings.at( "user" );
318}
319
320
322{
324 m_color_settings[settings->GetFilename()] = RegisterSettings( settings, false );
325}
326
327
329{
330 // Create the built-in color settings
332
333 wxFileName third_party_path;
334 const ENV_VAR_MAP& env = Pgm().GetLocalEnvVariables();
335 auto it = env.find( wxS( "KICAD7_3RD_PARTY" ) );
336
337 if( it != env.end() && !it->second.GetValue().IsEmpty() )
338 third_party_path.SetPath( it->second.GetValue() );
339 else
340 third_party_path.SetPath( PATHS::GetDefault3rdPartyPath() );
341
342 third_party_path.AppendDir( wxS( "colors" ) );
343
344 wxDir third_party_colors_dir( third_party_path.GetFullPath() );
345 wxString color_settings_path = GetColorSettingsPath();
346
347 // Search for and load any other settings
348 JSON_DIR_TRAVERSER loader( [&]( const wxFileName& aFilename )
349 {
350 registerColorSettings( aFilename.GetName() );
351 } );
352
353 JSON_DIR_TRAVERSER thirdPartyLoader(
354 [&]( const wxFileName& aFilename )
355 {
356 COLOR_SETTINGS* settings = registerColorSettings( aFilename.GetFullPath(), true );
357 settings->SetReadOnly( true );
358 } );
359
360 wxDir colors_dir( color_settings_path );
361
362 if( colors_dir.IsOpened() )
363 {
364 if( third_party_colors_dir.IsOpened() )
365 third_party_colors_dir.Traverse( thirdPartyLoader );
366
367 colors_dir.Traverse( loader );
368 }
369}
370
371
373{
374 m_color_settings.clear();
376}
377
378
379void SETTINGS_MANAGER::SaveColorSettings( COLOR_SETTINGS* aSettings, const std::string& aNamespace )
380{
381 // The passed settings should already be managed
382 wxASSERT( std::find_if( m_color_settings.begin(), m_color_settings.end(),
383 [aSettings] ( const std::pair<wxString, COLOR_SETTINGS*>& el )
384 {
385 return el.second->GetFilename() == aSettings->GetFilename();
386 }
387 ) != m_color_settings.end() );
388
389 if( aSettings->IsReadOnly() )
390 return;
391
392 if( !aSettings->Store() )
393 {
394 wxLogTrace( traceSettings, wxT( "Color scheme %s not modified; skipping save" ),
395 aNamespace );
396 return;
397 }
398
399 wxASSERT( aSettings->Contains( aNamespace ) );
400
401 wxLogTrace( traceSettings, wxT( "Saving color scheme %s, preserving %s" ),
402 aSettings->GetFilename(),
403 aNamespace );
404
405 std::optional<nlohmann::json> backup = aSettings->GetJson( aNamespace );
406 wxString path = GetColorSettingsPath();
407
408 aSettings->LoadFromFile( path );
409
410 if( backup )
411 ( *aSettings->Internals() )[aNamespace].update( *backup );
412
413 aSettings->Load();
414
415 aSettings->SaveToFile( path, true );
416}
417
418
420{
421 wxASSERT( aSettings );
422
423 switch( aSettings->GetLocation() )
424 {
425 case SETTINGS_LOC::USER:
426 return GetUserSettingsPath();
427
428 case SETTINGS_LOC::PROJECT:
429 // TODO: MDI support
430 return Prj().GetProjectPath();
431
432 case SETTINGS_LOC::COLORS:
433 return GetColorSettingsPath();
434
435 case SETTINGS_LOC::NONE:
436 return "";
437
438 default:
439 wxASSERT_MSG( false, wxT( "Unknown settings location!" ) );
440 }
441
442 return "";
443}
444
445
446class MIGRATION_TRAVERSER : public wxDirTraverser
447{
448private:
449 wxString m_src;
450 wxString m_dest;
451 wxString m_errors;
453
454public:
455 MIGRATION_TRAVERSER( const wxString& aSrcDir, const wxString& aDestDir, bool aMigrateTables ) :
456 m_src( aSrcDir ),
457 m_dest( aDestDir ),
458 m_migrateTables( aMigrateTables )
459 {
460 }
461
462 wxString GetErrors() { return m_errors; }
463
464 wxDirTraverseResult OnFile( const wxString& aSrcFilePath ) override
465 {
466 wxFileName file( aSrcFilePath );
467
468 if( !m_migrateTables && ( file.GetName() == wxT( "sym-lib-table" ) ||
469 file.GetName() == wxT( "fp-lib-table" ) ) )
470 {
471 return wxDIR_CONTINUE;
472 }
473
474 // Skip migrating PCM installed packages as packages themselves are not moved
475 if( file.GetFullName() == wxT( "installed_packages.json" ) )
476 return wxDIR_CONTINUE;
477
478 // Don't migrate hotkeys config files; we don't have a reasonable migration handler for them
479 // and so there is no way to resolve conflicts at the moment
480 if( file.GetExt() == wxT( "hotkeys" ) )
481 return wxDIR_CONTINUE;
482
483 wxString path = file.GetPath();
484
485 path.Replace( m_src, m_dest, false );
486 file.SetPath( path );
487
488 wxLogTrace( traceSettings, wxT( "Copying %s to %s" ), aSrcFilePath, file.GetFullPath() );
489
490 // For now, just copy everything
491 KiCopyFile( aSrcFilePath, file.GetFullPath(), m_errors );
492
493 return wxDIR_CONTINUE;
494 }
495
496 wxDirTraverseResult OnDir( const wxString& dirPath ) override
497 {
498 wxFileName dir( dirPath );
499
500 // Whitelist of directories to migrate
501 if( dir.GetName() == wxS( "colors" ) ||
502 dir.GetName() == wxS( "3d" ) )
503 {
504
505 wxString path = dir.GetPath();
506
507 path.Replace( m_src, m_dest, false );
508 dir.SetPath( path );
509
510 wxMkdir( dir.GetFullPath() );
511
512 return wxDIR_CONTINUE;
513 }
514 else
515 {
516 return wxDIR_IGNORE;
517 }
518 }
519};
520
521
523{
524 wxFileName path( GetUserSettingsPath(), wxS( "" ) );
525 wxLogTrace( traceSettings, wxT( "Using settings path %s" ), path.GetFullPath() );
526
527 if( m_headless )
528 {
529 // Special case namely for cli
530 // Ensure the settings directory at least exists to prevent additional loading errors from subdirectories
531 // TODO review headless (unit tests) vs cli needs, this should be fine for unit tests though
532 if( !path.DirExists() )
533 {
534 wxLogTrace( traceSettings, wxT( "Path didn't exist; creating it" ) );
535 path.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
536 }
537
538 wxLogTrace( traceSettings, wxT( "Settings migration not checked; running headless" ) );
539 return true;
540 }
541
542 if( path.DirExists() )
543 {
544 wxFileName common = path;
545 common.SetName( wxS( "kicad_common" ) );
546 common.SetExt( wxS( "json" ) );
547
548 if( common.Exists() )
549 {
550 wxLogTrace( traceSettings, wxT( "Path exists and has a kicad_common, continuing!" ) );
551 return true;
552 }
553 }
554
555 // Now we have an empty path, let's figure out what to put in it
556 DIALOG_MIGRATE_SETTINGS dlg( this );
557
558 if( dlg.ShowModal() != wxID_OK )
559 {
560 wxLogTrace( traceSettings, wxT( "Migration dialog canceled; exiting" ) );
561 return false;
562 }
563
564 if( !path.DirExists() )
565 {
566 wxLogTrace( traceSettings, wxT( "Path didn't exist; creating it" ) );
567 path.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
568 }
569
570 if( m_migration_source.IsEmpty() )
571 {
572 wxLogTrace( traceSettings, wxT( "No migration source given; starting with defaults" ) );
573 return true;
574 }
575
576 wxLogTrace( traceSettings, wxT( "Migrating from path %s" ), m_migration_source );
577
579 wxDir source_dir( m_migration_source );
580
581 source_dir.Traverse( traverser );
582
583 if( !traverser.GetErrors().empty() )
584 DisplayErrorMessage( nullptr, traverser.GetErrors() );
585
586 // Remove any library configuration if we didn't choose to import
588 {
589 COMMON_SETTINGS common;
590 wxString commonPath = GetPathForSettingsFile( &common );
591 common.LoadFromFile( commonPath );
592
593 const std::vector<wxString> libKeys = {
594 wxT( "KICAD6_SYMBOL_DIR" ),
595 wxT( "KICAD6_3DMODEL_DIR" ),
596 wxT( "KICAD6_FOOTPRINT_DIR" ),
597 wxT( "KICAD6_TEMPLATE_DIR" ), // Stores the default library table to be copied
598 wxT( "KICAD7_SYMBOL_DIR" ),
599 wxT( "KICAD7_3DMODEL_DIR" ),
600 wxT( "KICAD7_FOOTPRINT_DIR" ),
601 wxT( "KICAD7_TEMPLATE_DIR" ), // Stores the default library table to be copied
602
603 // Deprecated keys
604 wxT( "KICAD_PTEMPLATES" ),
605 wxT( "KISYS3DMOD" ),
606 wxT( "KISYSMOD" ),
607 wxT( "KICAD_SYMBOL_DIR" ),
608 };
609
610 for( const wxString& key : libKeys )
611 common.m_Env.vars.erase( key );
612
613 common.SaveToFile( commonPath );
614 }
615
616 return true;
617}
618
619
620bool SETTINGS_MANAGER::GetPreviousVersionPaths( std::vector<wxString>* aPaths )
621{
622 wxASSERT( aPaths );
623
624 aPaths->clear();
625
626 wxDir dir;
627 std::vector<wxFileName> base_paths;
628
629 base_paths.emplace_back( wxFileName( calculateUserSettingsPath( false ), wxS( "" ) ) );
630
631 // If the env override is set, also check the default paths
632 if( wxGetEnv( wxT( "KICAD_CONFIG_HOME" ), nullptr ) )
633 base_paths.emplace_back( wxFileName( calculateUserSettingsPath( false, false ), wxS( "" ) ) );
634
635#ifdef __WXGTK__
636 // When running inside FlatPak, KIPLATFORM::ENV::GetUserConfigPath() will return a sandboxed
637 // path. In case the user wants to move from non-FlatPak KiCad to FlatPak KiCad, let's add our
638 // best guess as to the non-FlatPak config path. Unfortunately FlatPak also hides the host
639 // XDG_CONFIG_HOME, so if the user customizes their config path, they will have to browse
640 // for it.
641 {
642 wxFileName wxGtkPath;
643 wxGtkPath.AssignDir( wxS( "~/.config/kicad" ) );
644 wxGtkPath.MakeAbsolute();
645 base_paths.emplace_back( wxGtkPath );
646
647 // We also want to pick up regular flatpak if we are nightly
648 wxGtkPath.AssignDir( wxS( "~/.var/app/org.kicad.KiCad/config/kicad" ) );
649 wxGtkPath.MakeAbsolute();
650 base_paths.emplace_back( wxGtkPath );
651 }
652#endif
653
654 wxString subdir;
655 std::string mine = GetSettingsVersion();
656
657 auto check_dir = [&] ( const wxString& aSubDir )
658 {
659 // Only older versions are valid for migration
660 if( compareVersions( aSubDir.ToStdString(), mine ) <= 0 )
661 {
662 wxString sub_path = dir.GetNameWithSep() + aSubDir;
663
664 if( IsSettingsPathValid( sub_path ) )
665 {
666 aPaths->push_back( sub_path );
667 wxLogTrace( traceSettings, wxT( "GetPreviousVersionName: %s is valid" ), sub_path );
668 }
669 }
670 };
671
672 std::set<wxString> checkedPaths;
673
674 for( const wxFileName& base_path : base_paths )
675 {
676 if( checkedPaths.count( base_path.GetFullPath() ) )
677 continue;
678
679 checkedPaths.insert( base_path.GetFullPath() );
680
681 if( !dir.Open( base_path.GetFullPath() ) )
682 {
683 wxLogTrace( traceSettings, wxT( "GetPreviousVersionName: could not open base path %s" ),
684 base_path.GetFullPath() );
685 continue;
686 }
687
688 wxLogTrace( traceSettings, wxT( "GetPreviousVersionName: checking base path %s" ),
689 base_path.GetFullPath() );
690
691 if( dir.GetFirst( &subdir, wxEmptyString, wxDIR_DIRS ) )
692 {
693 if( subdir != mine )
694 check_dir( subdir );
695
696 while( dir.GetNext( &subdir ) )
697 {
698 if( subdir != mine )
699 check_dir( subdir );
700 }
701 }
702
703 // If we didn't find one yet, check for legacy settings without a version directory
704 if( IsSettingsPathValid( dir.GetNameWithSep() ) )
705 {
706 wxLogTrace( traceSettings,
707 wxT( "GetPreviousVersionName: root path %s is valid" ), dir.GetName() );
708 aPaths->push_back( dir.GetName() );
709 }
710 }
711
712 std::sort( aPaths->begin(), aPaths->end(),
713 [&]( const wxString& a, const wxString& b ) -> bool
714 {
715 wxString verA = wxFileName::DirName( a ).GetDirs().back();
716 wxString verB = wxFileName::DirName( b ).GetDirs().back();
717
718 if( !extractVersion( verA.ToStdString() )
719 || !extractVersion( verB.ToStdString() ) )
720 {
721 return false;
722 }
723
724 return compareVersions( verA.ToStdString(), verB.ToStdString() ) >= 0;
725 } );
726
727 return aPaths->size() > 0;
728}
729
730
731bool SETTINGS_MANAGER::IsSettingsPathValid( const wxString& aPath )
732{
733 wxFileName test( aPath, wxS( "kicad_common" ) );
734
735 if( test.Exists() )
736 return true;
737
738 test.SetExt( "json" );
739
740 return test.Exists();
741}
742
743
745{
746 wxFileName path;
747
748 path.AssignDir( GetUserSettingsPath() );
749 path.AppendDir( wxS( "colors" ) );
750
751 if( !path.DirExists() )
752 {
753 if( !wxMkdir( path.GetPath() ) )
754 {
755 wxLogTrace( traceSettings,
756 wxT( "GetColorSettingsPath(): Path %s missing and could not be created!" ),
757 path.GetPath() );
758 }
759 }
760
761 return path.GetPath();
762}
763
764
766{
767 static wxString user_settings_path;
768
769 if( user_settings_path.empty() )
770 user_settings_path = calculateUserSettingsPath();
771
772 return user_settings_path;
773}
774
775
776wxString SETTINGS_MANAGER::calculateUserSettingsPath( bool aIncludeVer, bool aUseEnv )
777{
778 wxFileName cfgpath;
779
780 // http://docs.wxwidgets.org/3.0/classwx_standard_paths.html#a7c7cf595d94d29147360d031647476b0
781
782 wxString envstr;
783 if( aUseEnv && wxGetEnv( wxT( "KICAD_CONFIG_HOME" ), &envstr ) && !envstr.IsEmpty() )
784 {
785 // Override the assignment above with KICAD_CONFIG_HOME
786 cfgpath.AssignDir( envstr );
787 }
788 else
789 {
790 cfgpath.AssignDir( KIPLATFORM::ENV::GetUserConfigPath() );
791
792 cfgpath.AppendDir( TO_STR( KICAD_CONFIG_DIR ) );
793 }
794
795 if( aIncludeVer )
796 cfgpath.AppendDir( GetSettingsVersion() );
797
798 return cfgpath.GetPath();
799}
800
801
803{
804 // CMake computes the major.minor string for us.
805 return GetMajorMinorVersion().ToStdString();
806}
807
808
809int SETTINGS_MANAGER::compareVersions( const std::string& aFirst, const std::string& aSecond )
810{
811 int a_maj = 0;
812 int a_min = 0;
813 int b_maj = 0;
814 int b_min = 0;
815
816 if( !extractVersion( aFirst, &a_maj, &a_min ) || !extractVersion( aSecond, &b_maj, &b_min ) )
817 {
818 wxLogTrace( traceSettings, wxT( "compareSettingsVersions: bad input (%s, %s)" ), aFirst, aSecond );
819 return -1;
820 }
821
822 if( a_maj < b_maj )
823 {
824 return -1;
825 }
826 else if( a_maj > b_maj )
827 {
828 return 1;
829 }
830 else
831 {
832 if( a_min < b_min )
833 {
834 return -1;
835 }
836 else if( a_min > b_min )
837 {
838 return 1;
839 }
840 else
841 {
842 return 0;
843 }
844 }
845}
846
847
848bool SETTINGS_MANAGER::extractVersion( const std::string& aVersionString, int* aMajor, int* aMinor )
849{
850 std::regex re_version( "(\\d+)\\.(\\d+)" );
851 std::smatch match;
852
853 if( std::regex_match( aVersionString, match, re_version ) )
854 {
855 try
856 {
857 int major = std::stoi( match[1].str() );
858 int minor = std::stoi( match[2].str() );
859
860 if( aMajor )
861 *aMajor = major;
862
863 if( aMinor )
864 *aMinor = minor;
865 }
866 catch( ... )
867 {
868 return false;
869 }
870
871 return true;
872 }
873
874 return false;
875}
876
877
878bool SETTINGS_MANAGER::LoadProject( const wxString& aFullPath, bool aSetActive )
879{
880 // Normalize path to new format even if migrating from a legacy file
881 wxFileName path( aFullPath );
882
883 if( path.GetExt() == LegacyProjectFileExtension )
884 path.SetExt( ProjectFileExtension );
885
886 wxString fullPath = path.GetFullPath();
887
888 // If already loaded, we are all set. This might be called more than once over a project's
889 // lifetime in case the project is first loaded by the KiCad manager and then eeschema or
890 // pcbnew try to load it again when they are launched.
891 if( m_projects.count( fullPath ) )
892 return true;
893
894 bool readOnly = false;
895 LOCKFILE lockFile( fullPath );
896
897 if( !lockFile.Valid() )
898 {
899 wxLogTrace( traceSettings, wxT( "Project %s is locked; opening read-only" ), fullPath );
900 readOnly = true;
901 }
902
903 // No MDI yet
904 if( aSetActive && !m_projects.empty() )
905 {
906 PROJECT* oldProject = m_projects.begin()->second;
907 unloadProjectFile( oldProject, false );
908 m_projects.erase( m_projects.begin() );
909
910 auto it = std::find_if( m_projects_list.begin(), m_projects_list.end(),
911 [&]( const std::unique_ptr<PROJECT>& ptr )
912 {
913 return ptr.get() == oldProject;
914 } );
915
916 wxASSERT( it != m_projects_list.end() );
917 m_projects_list.erase( it );
918 }
919
920 wxLogTrace( traceSettings, wxT( "Load project %s" ), fullPath );
921
922 std::unique_ptr<PROJECT> project = std::make_unique<PROJECT>();
923 project->setProjectFullName( fullPath );
924
925 bool success = loadProjectFile( *project );
926
927 if( success )
928 {
929 project->SetReadOnly( readOnly || project->GetProjectFile().IsReadOnly() );
930
931 if( lockFile )
932 m_project_lock.reset( new LOCKFILE( std::move( lockFile ) ) );
933 }
934
935 m_projects_list.push_back( std::move( project ) );
936 m_projects[fullPath] = m_projects_list.back().get();
937
938 wxString fn( path.GetName() );
939
940 PROJECT_LOCAL_SETTINGS* settings = new PROJECT_LOCAL_SETTINGS( m_projects[fullPath], fn );
941
942 if( aSetActive )
943 settings = RegisterSettings( settings );
944 else
945 settings->LoadFromFile( path.GetPath() );
946
947 m_projects[fullPath]->setLocalSettings( settings );
948
949 if( aSetActive && m_kiway )
951
952 return success;
953}
954
955
956bool SETTINGS_MANAGER::UnloadProject( PROJECT* aProject, bool aSave )
957{
958 if( !aProject || !m_projects.count( aProject->GetProjectFullName() ) )
959 return false;
960
961 if( !unloadProjectFile( aProject, aSave ) )
962 return false;
963
964 wxString projectPath = aProject->GetProjectFullName();
965 wxLogTrace( traceSettings, wxT( "Unload project %s" ), projectPath );
966
967 PROJECT* toRemove = m_projects.at( projectPath );
968 auto it = std::find_if( m_projects_list.begin(), m_projects_list.end(),
969 [&]( const std::unique_ptr<PROJECT>& ptr )
970 {
971 return ptr.get() == toRemove;
972 } );
973
974 wxASSERT( it != m_projects_list.end() );
975 m_projects_list.erase( it );
976
977 m_projects.erase( projectPath );
978
979 // Immediately reload a null project; this is required until the rest of the application
980 // is refactored to not assume that Prj() always works
981 if( m_projects.empty() )
982 LoadProject( "" );
983
984 // Remove the reference in the environment to the previous project
985 wxSetEnv( PROJECT_VAR_NAME, wxS( "" ) );
986
987 // Release lock on the file, in case we had one
988 m_project_lock = nullptr;
989
990 if( m_kiway )
992
993 return true;
994}
995
996
998{
999 // No MDI yet: First project in the list is the active project
1000 wxASSERT_MSG( m_projects_list.size(), wxT( "no project in list" ) );
1001 return *m_projects_list.begin()->get();
1002}
1003
1004
1006{
1007 return !m_projects.empty();
1008}
1009
1010
1011PROJECT* SETTINGS_MANAGER::GetProject( const wxString& aFullPath ) const
1012{
1013 if( m_projects.count( aFullPath ) )
1014 return m_projects.at( aFullPath );
1015
1016 return nullptr;
1017}
1018
1019
1020std::vector<wxString> SETTINGS_MANAGER::GetOpenProjects() const
1021{
1022 std::vector<wxString> ret;
1023
1024 for( const std::pair<const wxString, PROJECT*>& pair : m_projects )
1025 ret.emplace_back( pair.first );
1026
1027 return ret;
1028}
1029
1030
1031bool SETTINGS_MANAGER::SaveProject( const wxString& aFullPath, PROJECT* aProject )
1032{
1033 if( !aProject )
1034 aProject = &Prj();
1035
1036 wxString path = aFullPath;
1037
1038 if( path.empty() )
1039 path = aProject->GetProjectFullName();
1040
1041 // TODO: refactor for MDI
1042 if( aProject->IsReadOnly() )
1043 return false;
1044
1045 if( !m_project_files.count( path ) )
1046 return false;
1047
1049 wxString projectPath = aProject->GetProjectPath();
1050
1051 project->SaveToFile( projectPath );
1052 aProject->GetLocalSettings().SaveToFile( projectPath );
1053
1054 return true;
1055}
1056
1057
1058void SETTINGS_MANAGER::SaveProjectAs( const wxString& aFullPath, PROJECT* aProject )
1059{
1060 if( !aProject )
1061 aProject = &Prj();
1062
1063 wxString oldName = aProject->GetProjectFullName();
1064
1065 if( aFullPath.IsSameAs( oldName ) )
1066 {
1067 SaveProject( aFullPath, aProject );
1068 return;
1069 }
1070
1071 // Changing this will cause UnloadProject to not save over the "old" project when loading below
1072 aProject->setProjectFullName( aFullPath );
1073
1074 wxFileName fn( aFullPath );
1075
1076 PROJECT_FILE* project = m_project_files.at( oldName );
1077
1078 // Ensure read-only flags are copied; this allows doing a "Save As" on a standalong board/sch
1079 // without creating project files if the checkbox is turned off
1080 project->SetReadOnly( aProject->IsReadOnly() );
1081 aProject->GetLocalSettings().SetReadOnly( aProject->IsReadOnly() );
1082
1083 project->SetFilename( fn.GetName() );
1084 project->SaveToFile( fn.GetPath() );
1085
1086 aProject->GetLocalSettings().SetFilename( fn.GetName() );
1087 aProject->GetLocalSettings().SaveToFile( fn.GetPath() );
1088
1089 m_project_files[fn.GetFullPath()] = project;
1090 m_project_files.erase( oldName );
1091
1092 m_projects[fn.GetFullPath()] = m_projects[oldName];
1093 m_projects.erase( oldName );
1094}
1095
1096
1097void SETTINGS_MANAGER::SaveProjectCopy( const wxString& aFullPath, PROJECT* aProject )
1098{
1099 if( !aProject )
1100 aProject = &Prj();
1101
1103 wxString oldName = project->GetFilename();
1104 wxFileName fn( aFullPath );
1105
1106 bool readOnly = project->IsReadOnly();
1107 project->SetReadOnly( false );
1108
1109 project->SetFilename( fn.GetName() );
1110 project->SaveToFile( fn.GetPath() );
1111 project->SetFilename( oldName );
1112
1113 PROJECT_LOCAL_SETTINGS& localSettings = aProject->GetLocalSettings();
1114
1115 localSettings.SetFilename( fn.GetName() );
1116 localSettings.SaveToFile( fn.GetPath() );
1117 localSettings.SetFilename( oldName );
1118
1119 project->SetReadOnly( readOnly );
1120}
1121
1122
1124{
1125 wxFileName fullFn( aProject.GetProjectFullName() );
1126 wxString fn( fullFn.GetName() );
1127
1128 PROJECT_FILE* file = RegisterSettings( new PROJECT_FILE( fn ), false );
1129
1130 m_project_files[aProject.GetProjectFullName()] = file;
1131
1132 aProject.setProjectFile( file );
1133 file->SetProject( &aProject );
1134
1135 wxString path( fullFn.GetPath() );
1136
1137 return file->LoadFromFile( path );
1138}
1139
1140
1142{
1143 if( !aProject )
1144 return false;
1145
1146 wxString name = aProject->GetProjectFullName();
1147
1148 if( !m_project_files.count( name ) )
1149 return false;
1150
1152
1153 auto it = std::find_if( m_settings.begin(), m_settings.end(),
1154 [&file]( const std::unique_ptr<JSON_SETTINGS>& aPtr )
1155 {
1156 return aPtr.get() == file;
1157 } );
1158
1159 if( it != m_settings.end() )
1160 {
1161 wxString projectPath = GetPathForSettingsFile( it->get() );
1162
1163 FlushAndRelease( &aProject->GetLocalSettings(), aSave );
1164
1165 if( aSave )
1166 ( *it )->SaveToFile( projectPath );
1167
1168 m_settings.erase( it );
1169 }
1170
1171 m_project_files.erase( name );
1172
1173 return true;
1174}
1175
1176
1178{
1180}
1181
1182
1183wxString SETTINGS_MANAGER::backupDateTimeFormat = wxT( "%Y-%m-%d_%H%M%S" );
1184
1185
1187{
1188 wxDateTime timestamp = wxDateTime::Now();
1189
1190 wxString fileName = wxString::Format( wxT( "%s-%s" ), Prj().GetProjectName(),
1191 timestamp.Format( backupDateTimeFormat ) );
1192
1193 wxFileName target;
1194 target.SetPath( GetProjectBackupsPath() );
1195 target.SetName( fileName );
1196 target.SetExt( ArchiveFileExtension );
1197
1198 if( !target.DirExists() && !wxMkdir( target.GetPath() ) )
1199 {
1200 wxLogTrace( traceSettings, wxT( "Could not create project backup path %s" ), target.GetPath() );
1201 return false;
1202 }
1203
1204 if( !target.IsDirWritable() )
1205 {
1206 wxLogTrace( traceSettings, wxT( "Backup directory %s is not writable" ), target.GetPath() );
1207 return false;
1208 }
1209
1210 wxLogTrace( traceSettings, wxT( "Backing up project to %s" ), target.GetPath() );
1211
1212 PROJECT_ARCHIVER archiver;
1213
1214 return archiver.Archive( Prj().GetProjectPath(), target.GetFullPath(), aReporter );
1215}
1216
1217
1218class VECTOR_INSERT_TRAVERSER : public wxDirTraverser
1219{
1220public:
1221 VECTOR_INSERT_TRAVERSER( std::vector<wxString>& aVec,
1222 std::function<bool( const wxString& )> aCond ) :
1223 m_files( aVec ),
1224 m_condition( aCond )
1225 {
1226 }
1227
1228 wxDirTraverseResult OnFile( const wxString& aFile ) override
1229 {
1230 if( m_condition( aFile ) )
1231 m_files.emplace_back( aFile );
1232
1233 return wxDIR_CONTINUE;
1234 }
1235
1236 wxDirTraverseResult OnDir( const wxString& aDirName ) override
1237 {
1238 return wxDIR_CONTINUE;
1239 }
1240
1241private:
1242 std::vector<wxString>& m_files;
1243
1244 std::function<bool( const wxString& )> m_condition;
1245};
1246
1247
1249{
1251
1252 if( !settings.enabled )
1253 return true;
1254
1255 wxString prefix = Prj().GetProjectName() + '-';
1256
1257 auto modTime =
1258 [&prefix]( const wxString& aFile )
1259 {
1260 wxDateTime dt;
1261 wxString fn( wxFileName( aFile ).GetName() );
1262 fn.Replace( prefix, wxS( "" ) );
1263 dt.ParseFormat( fn, backupDateTimeFormat );
1264 return dt;
1265 };
1266
1267 wxFileName projectPath( Prj().GetProjectPath() );
1268
1269 // Skip backup if project path isn't valid or writable
1270 if( !projectPath.IsOk() || !projectPath.Exists() || !projectPath.IsDirWritable() )
1271 return true;
1272
1273 wxString backupPath = GetProjectBackupsPath();
1274
1275 if( !wxDirExists( backupPath ) )
1276 {
1277 wxLogTrace( traceSettings, wxT( "Backup path %s doesn't exist, creating it" ), backupPath );
1278
1279 if( !wxMkdir( backupPath ) )
1280 {
1281 wxLogTrace( traceSettings, wxT( "Could not create backups path! Skipping backup" ) );
1282 return false;
1283 }
1284 }
1285
1286 wxDir dir( backupPath );
1287
1288 if( !dir.IsOpened() )
1289 {
1290 wxLogTrace( traceSettings, wxT( "Could not open project backups path %s" ), dir.GetName() );
1291 return false;
1292 }
1293
1294 std::vector<wxString> files;
1295
1296 VECTOR_INSERT_TRAVERSER traverser( files,
1297 [&modTime]( const wxString& aFile )
1298 {
1299 return modTime( aFile ).IsValid();
1300 } );
1301
1302 dir.Traverse( traverser, wxT( "*.zip" ) );
1303
1304 // Sort newest-first
1305 std::sort( files.begin(), files.end(),
1306 [&]( const wxString& aFirst, const wxString& aSecond ) -> bool
1307 {
1308 wxDateTime first = modTime( aFirst );
1309 wxDateTime second = modTime( aSecond );
1310
1311 return first.GetTicks() > second.GetTicks();
1312 } );
1313
1314 // Do we even need to back up?
1315 if( !files.empty() )
1316 {
1317 wxDateTime lastTime = modTime( files[0] );
1318
1319 if( lastTime.IsValid() )
1320 {
1321 wxTimeSpan delta = wxDateTime::Now() - modTime( files[0] );
1322
1323 if( delta.IsShorterThan( wxTimeSpan::Seconds( settings.min_interval ) ) )
1324 return true;
1325 }
1326 }
1327
1328 // Now that we know a backup is needed, apply the retention policy
1329
1330 // Step 1: if we're over the total file limit, remove the oldest
1331 if( !files.empty() && settings.limit_total_files > 0 )
1332 {
1333 while( files.size() > static_cast<size_t>( settings.limit_total_files ) )
1334 {
1335 wxRemoveFile( files.back() );
1336 files.pop_back();
1337 }
1338 }
1339
1340 // Step 2: Stay under the total size limit
1341 if( settings.limit_total_size > 0 )
1342 {
1343 wxULongLong totalSize = 0;
1344
1345 for( const wxString& file : files )
1346 totalSize += wxFileName::GetSize( file );
1347
1348 while( !files.empty() && totalSize > static_cast<wxULongLong>( settings.limit_total_size ) )
1349 {
1350 totalSize -= wxFileName::GetSize( files.back() );
1351 wxRemoveFile( files.back() );
1352 files.pop_back();
1353 }
1354 }
1355
1356 // Step 3: Stay under the daily limit
1357 if( settings.limit_daily_files > 0 && files.size() > 1 )
1358 {
1359 wxDateTime day = modTime( files[0] );
1360 int num = 1;
1361
1362 wxASSERT( day.IsValid() );
1363
1364 std::vector<wxString> filesToDelete;
1365
1366 for( size_t i = 1; i < files.size(); i++ )
1367 {
1368 wxDateTime dt = modTime( files[i] );
1369
1370 if( dt.IsSameDate( day ) )
1371 {
1372 num++;
1373
1374 if( num > settings.limit_daily_files )
1375 filesToDelete.emplace_back( files[i] );
1376 }
1377 else
1378 {
1379 day = dt;
1380 num = 1;
1381 }
1382 }
1383
1384 for( const wxString& file : filesToDelete )
1385 wxRemoveFile( file );
1386 }
1387
1388 return BackupProject( aReporter );
1389}
const char * name
Definition: DXF_plotter.cpp:56
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
Color settings are a bit different than most of the settings objects in that there can be more than o...
void SetName(const wxString &aName)
static std::vector< COLOR_SETTINGS * > CreateBuiltinColorSettings()
Constructs and returns a list of color settings objects based on the built-in color themes.
static const wxString COLOR_BUILTIN_DEFAULT
AUTO_BACKUP m_Backup
ENVIRONMENT m_Env
std::function< void(const wxFileName &)> m_action
JSON_DIR_TRAVERSER(std::function< void(const wxFileName &)> aAction)
wxDirTraverseResult OnDir(const wxString &dirPath) override
wxDirTraverseResult OnFile(const wxString &aFilePath) override
std::optional< 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....
bool Contains(const std::string &aPath) const
SETTINGS_LOC GetLocation() const
Definition: json_settings.h:80
virtual bool LoadFromFile(const wxString &aDirectory="")
Loads the backing file from disk and then calls Load()
virtual void Load()
Updates the parameters of this object based on the current JSON document contents.
bool IsReadOnly() const
Definition: json_settings.h:84
void SetReadOnly(bool aReadOnly)
Definition: json_settings.h:85
JSON_SETTINGS_INTERNALS * Internals()
void SetFilename(const wxString &aFilename)
Definition: json_settings.h:77
virtual bool SaveToFile(const wxString &aDirectory="", bool aForce=false)
virtual bool Store()
Stores the current parameters into the JSON document represented by this object Note: this doesn't do...
wxString GetFilename() const
Definition: json_settings.h:73
virtual void ProjectChanged()
Calls ProjectChanged() on all KIWAY_PLAYERs.
Definition: kiway.cpp:656
bool Valid() const
Definition: lockfile.h:228
wxDirTraverseResult OnDir(const wxString &dirPath) override
MIGRATION_TRAVERSER(const wxString &aSrcDir, const wxString &aDestDir, bool aMigrateTables)
wxDirTraverseResult OnFile(const wxString &aSrcFilePath) override
static wxString GetDefault3rdPartyPath()
Gets the default path for PCM packages.
Definition: paths.cpp:129
bool Archive(const wxString &aSrcDir, const wxString &aDestFile, REPORTER &aReporter, bool aVerbose=true, bool aIncludeExtraFiles=false)
Creates an archive of the project.
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:65
void SetProject(PROJECT *aProject)
Definition: project_file.h:81
The project local settings are things that are attached to a particular project, but also might be pa...
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Container for project specific data.
Definition: project.h:64
virtual void setProjectFile(PROJECT_FILE *aFile)
Set the backing store file for this project.
Definition: project.h:326
virtual bool IsReadOnly() const
Definition: project.h:125
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:120
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:126
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:132
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition: project.h:155
virtual void setProjectFullName(const wxString &aFullPathAndName)
Set the full directory, basename, and extension of the project.
Definition: project.cpp:88
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
static int compareVersions(const std::string &aFirst, const std::string &aSecond)
Compares two settings versions, like "5.99" and "6.0".
std::unique_ptr< LOCKFILE > m_project_lock
Lock for loaded project (expand to multiple once we support MDI)
wxString GetPathForSettingsFile(JSON_SETTINGS *aSettings)
Returns the path a given settings file should be loaded from / stored to.
static std::string GetSettingsVersion()
Parses the current KiCad build version and extracts the major and minor revision to use as the name o...
void SaveProjectAs(const wxString &aFullPath, PROJECT *aProject=nullptr)
Sets the currently loaded project path and saves it (pointers remain valid) Note that this will not m...
JSON_SETTINGS * registerSettings(JSON_SETTINGS *aSettings, bool aLoadNow=true)
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
COLOR_SETTINGS * GetColorSettings(const wxString &aName="user")
Retrieves a color settings object that applications can read colors from.
T * RegisterSettings(T *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
void SaveProjectCopy(const wxString &aFullPath, PROJECT *aProject=nullptr)
Saves a copy of the current project under the given path.
bool MigrateIfNeeded()
Handles the initialization of the user settings directory and migration from previous KiCad versions ...
wxString m_migration_source
void SaveColorSettings(COLOR_SETTINGS *aSettings, const std::string &aNamespace="")
Safely saves a COLOR_SETTINGS to disk, preserving any changes outside the given namespace.
bool BackupProject(REPORTER &aReporter) const
Creates a backup archive of the current project.
static wxString calculateUserSettingsPath(bool aIncludeVer=true, bool aUseEnv=true)
Determines the base path for user settings files.
std::map< wxString, PROJECT * > m_projects
Loaded projects, mapped according to project full name.
static bool extractVersion(const std::string &aVersionString, int *aMajor=nullptr, int *aMinor=nullptr)
Extracts the numeric version from a given settings string.
COLOR_SETTINGS * registerColorSettings(const wxString &aFilename, bool aAbsolutePath=false)
bool m_headless
True if running outside a UI context.
SETTINGS_MANAGER(bool aHeadless=false)
static wxString GetColorSettingsPath()
Returns the path where color scheme files are stored; creating it if missing (normally .
COMMON_SETTINGS * GetCommonSettings() const
Retrieves the common settings shared by all applications.
bool SaveProject(const wxString &aFullPath=wxEmptyString, PROJECT *aProject=nullptr)
Saves a loaded project.
wxString GetProjectBackupsPath() const
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
std::map< wxString, PROJECT_FILE * > m_project_files
Loaded project files, mapped according to project full name.
std::unordered_map< wxString, COLOR_SETTINGS * > m_color_settings
COLOR_SETTINGS * loadColorSettingsByName(const wxString &aName)
Attempts to load a color theme by name (the color theme directory and .json ext are assumed)
bool IsProjectOpen() const
Helper for checking if we have a project open TODO: This should be deprecated along with Prj() once w...
bool GetPreviousVersionPaths(std::vector< wxString > *aName=nullptr)
Retrieves the name of the most recent previous KiCad version that can be found in the user settings d...
static bool IsSettingsPathValid(const wxString &aPath)
Checks if a given path is probably a valid KiCad configuration directory.
std::vector< std::unique_ptr< PROJECT > > m_projects_list
Loaded projects (ownership here)
PROJECT * GetProject(const wxString &aFullPath) const
Retrieves a loaded project by name.
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Saves, unloads and unregisters the given PROJECT.
std::vector< wxString > GetOpenProjects() const
std::vector< std::unique_ptr< JSON_SETTINGS > > m_settings
bool TriggerBackupIfNeeded(REPORTER &aReporter) const
Calls BackupProject if a new backup is needed according to the current backup policy.
bool m_migrateLibraryTables
If true, the symbol and footprint library tables will be migrated from the previous version.
bool unloadProjectFile(PROJECT *aProject, bool aSave)
Optionally saves, and then unloads and unregisters the given PROJECT_FILE.
COLOR_SETTINGS * GetMigratedColorSettings()
Returns a color theme for storing colors migrated from legacy (5.x and earlier) settings,...
std::unordered_map< size_t, JSON_SETTINGS * > m_app_settings_cache
Cache for app settings.
COLOR_SETTINGS * AddNewColorSettings(const wxString &aFilename)
Registers a new color settings object with the given filename.
bool m_ok
True if settings loaded successfully at construction.
void registerBuiltinColorSettings()
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
bool loadProjectFile(PROJECT &aProject)
Registers a PROJECT_FILE and attempts to load it from disk.
static wxString backupDateTimeFormat
void ReloadColorSettings()
Re-scans the color themes directory, reloading any changes it finds.
COMMON_SETTINGS * m_common_settings
KIWAY * m_kiway
The kiway this settings manager interacts with.
void FlushAndRelease(JSON_SETTINGS *aSettings, bool aSave=true)
If the given settings object is registered, save it to disk and unregister it.
wxDirTraverseResult OnFile(const wxString &aFile) override
wxDirTraverseResult OnDir(const wxString &aDirName) override
std::vector< wxString > & m_files
VECTOR_INSERT_TRAVERSER(std::vector< wxString > &aVec, std::function< bool(const wxString &)> aCond)
std::function< bool(const wxString &)> m_condition
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:308
This file is part of the common library.
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
Definition: gestfich.cpp:216
const std::string LegacyProjectFileExtension
const std::string ProjectFileExtension
const std::string ArchiveFileExtension
const wxChar *const traceSettings
Flag to enable debug output of settings operations and management.
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
File locking utilities.
This file contains miscellaneous commonly used macros and functions.
#define TO_STR(x)
Definition: macros.h:105
wxString GetUserConfigPath()
Retrieves the operating system specific path for a user's configuration store.
STL namespace.
see class PGM_BASE
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition: project.h:39
#define PROJECT_BACKUPS_DIR_SUFFIX
Project settings path will be <projectname> + this.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:115
int min_interval
Minimum time, in seconds, between subsequent backups.
unsigned long long limit_total_size
Maximum total size of backups (bytes), 0 for unlimited.
int limit_total_files
Maximum number of backup archives to retain.
int limit_daily_files
Maximum files to keep per day, 0 for unlimited.
bool enabled
Automatically back up the project when files are saved.
constexpr int delta
Definition of file extensions used in Kicad.