24 #include <wx/filename.h> 25 #include <wx/snglinst.h> 26 #include <wx/stdpaths.h> 49 #define PROJECT_BACKUPS_DIR_SUFFIX wxT( "-backups" ) 53 m_headless( aHeadless ),
55 m_common_settings( nullptr ),
57 m_migrateLibraryTables( true )
87 std::unique_ptr<JSON_SETTINGS> ptr( aSettings );
89 ptr->SetManager(
this );
91 wxLogTrace(
traceSettings,
"Registered new settings object <%s>", ptr->GetFullFilename() );
114 [&aSettings](
const std::unique_ptr<JSON_SETTINGS>& aPtr )
116 return aPtr.get() == aSettings;
129 if( dynamic_cast<COLOR_SETTINGS*>( settings.get() ) )
140 [&aSettings](
const std::unique_ptr<JSON_SETTINGS>& aPtr )
142 return aPtr.get() == aSettings;
147 wxLogTrace(
traceSettings,
"Saving %s", ( *it )->GetFullFilename() );
156 [&aSettings](
const std::unique_ptr<JSON_SETTINGS>& aPtr )
158 return aPtr.get() == aSettings;
163 wxLogTrace(
traceSettings,
"Flush and release %s", ( *it )->GetFullFilename() );
168 size_t typeHash =
typeid( *it->get() ).hash_code();
200 wxLogTrace(
traceSettings,
"Attempting to load color theme %s", aName );
204 if( !fn.IsOk() || !fn.Exists() )
206 wxLogTrace(
traceSettings,
"Theme file %s.json not found, falling back to user", aName );
210 auto cs = static_cast<COLOR_SETTINGS*>(
213 if( cs->GetFilename() != aName.ToStdString() )
215 wxLogTrace(
traceSettings,
"Warning: stored filename is actually %s, ", cs->GetFilename() );
235 wxDirTraverseResult
OnFile(
const wxString& aFilePath )
override 237 wxFileName file( aFilePath );
239 if( file.GetExt() !=
"json" )
240 return wxDIR_CONTINUE;
244 return wxDIR_CONTINUE;
247 wxDirTraverseResult
OnDir(
const wxString& dirPath )
override 266 wxString filename = aFilename;
268 if( filename.EndsWith( wxT(
".json" ) ) )
269 filename = filename.BeforeLast(
'.' );
306 if( colors_dir.IsOpened() )
307 colors_dir.Traverse( loader );
322 [aSettings] (
const std::pair<wxString, COLOR_SETTINGS*>& el )
324 return el.second->GetFilename() == aSettings->
GetFilename();
330 if( !aSettings->
Store() )
332 wxLogTrace(
traceSettings,
"Color scheme %s not modified; skipping save",
337 wxASSERT( aSettings->contains( ptr ) );
347 ( *aSettings )[ptr].update( backup );
356 wxASSERT( aSettings );
373 wxASSERT_MSG(
false,
"Unknown settings location!" );
398 wxDirTraverseResult
OnFile(
const wxString& aSrcFilePath )
override 400 wxFileName file( aSrcFilePath );
403 file.GetName() == wxT(
"fp-lib-table" ) ) )
405 return wxDIR_CONTINUE;
410 if( file.GetExt() == wxT(
"hotkeys" ) )
411 return wxDIR_CONTINUE;
413 wxString
path = file.GetPath();
416 file.SetPath(
path );
418 wxLogTrace(
traceSettings,
"Copying %s to %s", aSrcFilePath, file.GetFullPath() );
423 return wxDIR_CONTINUE;
426 wxDirTraverseResult
OnDir(
const wxString& dirPath )
override 428 wxFileName dir( dirPath );
431 if( dir.GetName() ==
"colors" ||
432 dir.GetName() ==
"3d" )
435 wxString
path = dir.GetPath();
440 wxMkdir( dir.GetFullPath() );
442 return wxDIR_CONTINUE;
456 wxLogTrace(
traceSettings,
"Settings migration not checked; running headless" );
463 if(
path.DirExists() )
465 wxFileName common =
path;
466 common.SetName(
"kicad_common" );
467 common.SetExt(
"json" );
469 if( common.Exists() )
471 wxLogTrace(
traceSettings,
"Path exists and has a kicad_common, continuing!" );
479 if( dlg.ShowModal() != wxID_OK )
481 wxLogTrace(
traceSettings,
"Migration dialog canceled; exiting" );
485 if( !
path.DirExists() )
487 wxLogTrace(
traceSettings,
"Path didn't exist; creating it" );
488 path.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
493 wxLogTrace(
traceSettings,
"No migration source given; starting with defaults" );
500 source_dir.Traverse( traverser );
502 if( !traverser.GetErrors().empty() )
516 std::vector<wxFileName> base_paths;
521 if( wxGetEnv( wxT(
"KICAD_CONFIG_HOME" ),
nullptr ) )
531 wxFileName wxGtkPath;
532 wxGtkPath.AssignDir(
"~/.config/kicad" );
533 wxGtkPath.MakeAbsolute();
534 base_paths.emplace_back( wxGtkPath.GetPath() );
537 wxGtkPath.AssignDir(
"~/.var/app/org.kicad.KiCad/config/kicad" );
538 wxGtkPath.MakeAbsolute();
539 base_paths.emplace_back( wxGtkPath.GetPath() );
546 auto check_dir = [&] (
const wxString& aSubDir )
551 wxString sub_path = dir.GetNameWithSep() + aSubDir;
555 aPaths->push_back( sub_path );
556 wxLogTrace(
traceSettings,
"GetPreviousVersionName: %s is valid", sub_path );
561 std::set<wxString> checkedPaths;
563 for(
auto base_path : base_paths )
565 if( checkedPaths.count( base_path.GetFullPath() ) )
568 checkedPaths.insert( base_path.GetFullPath() );
570 if( !dir.Open( base_path.GetFullPath() ) )
572 wxLogTrace(
traceSettings,
"GetPreviousVersionName: could not open base path %s",
573 base_path.GetFullPath() );
577 wxLogTrace(
traceSettings,
"GetPreviousVersionName: checking base path %s",
578 base_path.GetFullPath() );
580 if( dir.GetFirst( &subdir, wxEmptyString, wxDIR_DIRS ) )
585 while( dir.GetNext( &subdir ) )
596 "GetPreviousVersionName: root path %s is valid", dir.GetName() );
597 aPaths->push_back( dir.GetName() );
601 return aPaths->size() > 0;
607 wxFileName
test( aPath,
"kicad_common" );
612 test.SetExt(
"json" );
614 return test.Exists();
623 path.AppendDir(
"colors" );
625 if( !
path.DirExists() )
627 if( !wxMkdir(
path.GetPath() ) )
630 "GetColorSettingsPath(): Path %s missing and could not be created!",
635 return path.GetPath();
641 static wxString user_settings_path;
643 if( user_settings_path.empty() )
646 return user_settings_path;
657 if( aUseEnv && wxGetEnv( wxT(
"KICAD_CONFIG_HOME" ), &envstr ) && !envstr.IsEmpty() )
660 cfgpath.AssignDir( envstr );
666 cfgpath.AppendDir(
TO_STR( KICAD_CONFIG_DIR ) );
672 return cfgpath.GetPath();
692 wxLogTrace(
traceSettings,
"compareSettingsVersions: bad input (%s, %s)", aFirst, aSecond );
700 else if( a_maj > b_maj )
710 else if( a_min > b_min )
724 std::regex re_version(
"(\\d+)\\.(\\d+)" );
727 if( std::regex_match( aVersionString, match, re_version ) )
731 *aMajor = std::stoi( match[1].str() );
732 *aMinor = std::stoi( match[2].str() );
749 wxFileName
path( aFullPath );
754 wxString fullPath =
path.GetFullPath();
762 bool readOnly =
false;
763 std::unique_ptr<wxSingleInstanceChecker> lockFile =
::LockFile( fullPath );
767 wxLogTrace(
traceSettings,
"Project %s is locked; opening read-only", fullPath );
781 std::unique_ptr<PROJECT>
project = std::make_unique<PROJECT>();
782 project->setProjectFullName( fullPath );
788 project->SetReadOnly( readOnly ||
project->GetProjectFile().IsReadOnly() );
797 wxString fn(
path.GetName() );
802 settings = static_cast<PROJECT_LOCAL_SETTINGS*>(
RegisterSettings( settings ) );
804 m_projects[fullPath]->setLocalSettings( settings );
822 wxLogTrace(
traceSettings,
"Unload project %s", projectPath );
826 [&](
const std::unique_ptr<PROJECT>& ptr )
828 return ptr.get() == toRemove;
878 std::vector<wxString> ret;
880 for(
const std::pair<const wxString, PROJECT*>& pair :
m_projects )
881 ret.emplace_back( pair.first );
889 wxString
path = aFullPath;
895 if(
Prj().IsReadOnly() )
904 project->SaveToFile( projectPath );
918 wxFileName fn( aFullPath );
921 project->SetFilename( fn.GetName() );
922 project->SaveToFile( fn.GetPath() );
938 wxString oldName =
project->GetFilename();
939 wxFileName fn( aFullPath );
941 project->SetFilename( fn.GetName() );
942 project->SaveToFile( fn.GetPath() );
943 project->SetFilename( oldName );
954 wxString fn( fullFn.GetName() );
962 file->SetProject( &aProject );
964 wxString
path( fullFn.GetPath() );
966 return file->LoadFromFile(
path );
983 [&file](
const std::unique_ptr<JSON_SETTINGS>& aPtr )
985 return aPtr.get() == file;
995 ( *it )->SaveToFile( projectPath );
1017 wxDateTime timestamp = wxDateTime::Now();
1024 target.SetName( fileName );
1027 wxDir dir( target.GetPath() );
1029 if( !target.DirExists() && !wxMkdir( target.GetPath() ) )
1031 wxLogTrace(
traceSettings,
"Could not create project backup path %s", target.GetPath() );
1035 if( !target.IsDirWritable() )
1037 wxLogTrace(
traceSettings,
"Backup directory %s is not writeable", target.GetPath() );
1041 wxLogTrace(
traceSettings,
"Backing up project to %s", target.GetPath() );
1045 return archiver.
Archive(
Prj().GetProjectPath(), target.GetFullPath(), aReporter );
1053 std::function<
bool(
const wxString& )> aCond ) :
1059 wxDirTraverseResult
OnFile(
const wxString& aFile )
override 1062 m_files.emplace_back( aFile );
1064 return wxDIR_CONTINUE;
1067 wxDirTraverseResult
OnDir(
const wxString& aDirName )
override 1069 return wxDIR_CONTINUE;
1089 [&prefix](
const wxString& aFile )
1092 wxString fn( wxFileName( aFile ).GetName() );
1093 fn.Replace( prefix,
"" );
1098 wxFileName projectPath(
Prj().GetProjectPath() );
1101 if( !projectPath.IsOk() || !projectPath.Exists() || !projectPath.IsDirWritable() )
1106 if( !wxDirExists( backupPath ) )
1108 wxLogTrace(
traceSettings,
"Backup path %s doesn't exist, creating it", backupPath );
1110 if( !wxMkdir( backupPath ) )
1112 wxLogTrace(
traceSettings,
"Could not create backups path! Skipping backup" );
1117 wxDir dir( backupPath );
1119 if( !dir.IsOpened() )
1121 wxLogTrace(
traceSettings,
"Could not open project backups path %s", dir.GetName() );
1125 std::vector<wxString> files;
1128 [&modTime](
const wxString& aFile )
1130 return modTime( aFile ).IsValid();
1133 dir.Traverse( traverser, wxT(
"*.zip" ) );
1136 std::sort( files.begin(), files.end(),
1137 [&](
const wxString& aFirst,
const wxString& aSecond ) ->
bool 1139 wxDateTime first = modTime( aFirst );
1140 wxDateTime second = modTime( aSecond );
1142 return first.GetTicks() > second.GetTicks();
1146 if( !files.empty() )
1148 wxDateTime lastTime = modTime( files[0] );
1150 if( lastTime.IsValid() )
1152 wxTimeSpan delta = wxDateTime::Now() - modTime( files[0] );
1154 if( delta.IsShorterThan( wxTimeSpan::Seconds( settings.
min_interval ) ) )
1166 wxRemoveFile( files.back() );
1174 wxULongLong totalSize = 0;
1176 for(
const wxString& file : files )
1177 totalSize += wxFileName::GetSize( file );
1179 while( !files.empty() && totalSize > static_cast<wxULongLong>( settings.
limit_total_size ) )
1181 totalSize -= wxFileName::GetSize( files.back() );
1182 wxRemoveFile( files.back() );
1190 wxDateTime day = modTime( files[0] );
1193 wxASSERT( day.IsValid() );
1195 std::vector<wxString> filesToDelete;
1197 for(
size_t i = 1; i < files.size(); i++ )
1199 wxDateTime dt = modTime( files[i] );
1201 if( dt.IsSameDate( day ) )
1206 filesToDelete.emplace_back( files[i] );
1215 for(
const wxString& file : filesToDelete )
1216 wxRemoveFile( file );
static wxString backupDateTimeFormat
bool Archive(const wxString &aSrcDir, const wxString &aDestFile, REPORTER &aReporter, bool aVerbose=true, bool aIncludeExtraFiles=false)
Creates an archive of the project.
virtual bool Store()
Stores the current parameters into the JSON document represented by this object Note: this doesn't do...
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
Container for project specific data.
unsigned long long limit_total_size
Maximum total size of backups (bytes), 0 for unlimited.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
This file is part of the common library TODO brief description.
std::unique_ptr< wxSingleInstanceChecker > m_project_lock
Lock for loaded project (expand to multiple once we support MDI)
This file is part of the common library.
void SaveProjectAs(const wxString &aFullPath)
Sets the currently loaded project path and saves it (pointers remain valid)
static bool IsSettingsPathValid(const wxString &aPath)
Checks if a given path is probably a valid KiCad configuration directory.
wxDirTraverseResult OnFile(const wxString &aFilePath) override
const std::string ProjectFileExtension
KIWAY * m_kiway
The kiway this settings manager interacts with.
wxString GetFilename() const
bool m_migrateLibraryTables
If true, the symbol and footprint library tables will be migrated from the previous version.
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
bool enabled
Automatically back up the project when files are saved.
virtual bool LoadFromFile(const wxString &aDirectory="")
Loads the backing file from disk and then calls Load()
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
wxDirTraverseResult OnFile(const wxString &aSrcFilePath) override
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
std::unordered_map< size_t, JSON_SETTINGS * > m_app_settings_cache
Cache for app settings.
#define PROJECT_BACKUPS_DIR_SUFFIX
Project settings path will be <projectname> + this.
VECTOR_INSERT_TRAVERSER(std::vector< wxString > &aVec, std::function< bool(const wxString &)> aCond)
std::map< wxString, PROJECT_FILE * > m_project_files
Loaded project files, mapped according to project full name.
bool MigrateIfNeeded()
Handles the initialization of the user settings directory and migration from previous KiCad versions ...
A pure virtual class used to derive REPORTER objects from.
COLOR_SETTINGS * AddNewColorSettings(const wxString &aFilename)
Registers a new color settings object with the given filename.
static int compareVersions(const std::string &aFirst, const std::string &aSecond)
Compares two settings versions, like "5.99" and "6.0".
bool BackupProject(REPORTER &aReporter) const
Creates a backup archive of the current project.
virtual const wxString GetProjectPath() const
Return the full path of the project.
The backing store for a PROJECT, in JSON format.
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
This file contains miscellaneous commonly used macros and functions.
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
std::vector< wxString > & m_files
The color scheme directory (e.g. ~/.config/kicad/colors/)
wxString m_migration_source
bool m_ok
True if settings loaded successfully at construction.
bool unloadProjectFile(PROJECT *aProject, bool aSave)
Optionally saves, and then unloads and unregisters the given PROJECT_FILE.
virtual bool SaveToFile(const wxString &aDirectory="", bool aForce=false)
void SaveProjectCopy(const wxString &aFullPath)
Saves a copy of the current project under the given path.
bool IsProjectOpen() const
Helper for checking if we have a project open TODO: This should be deprecated along with Prj() once w...
wxDirTraverseResult OnDir(const wxString &aDirName) override
The settings directory inside a project folder.
bool TriggerBackupIfNeeded(REPORTER &aReporter) const
Calls BackupProject if a new backup is needed according to the current backup policy.
SETTINGS_LOC GetLocation() const
std::function< bool(const wxString &)> m_condition
bool GetPreviousVersionPaths(std::vector< wxString > *aName=nullptr)
Retreives the name of the most recent previous KiCad version that can be found in the user settings d...
COMMON_SETTINGS * GetCommonSettings() const
Retrieves the common settings shared by all applications.
virtual void ProjectChanged()
Calls ProjectChanged() on all KIWAY_PLAYERs.
std::unique_ptr< wxSingleInstanceChecker > LockFile(const wxString &aFileName)
Test to see if aFileName can be locked (is not already locked) and only then returns a wxSingleInstan...
Definition of file extensions used in Kicad.
static std::vector< COLOR_SETTINGS * > CreateBuiltinColorSettings()
Constructs and returns a list of color settings objects based on the built-in color themes.
bool m_headless
True if running outside a UI context.
wxDirTraverseResult OnFile(const wxString &aFile) override
void registerColorSettings(const wxString &aFilename)
static void EnsureUserPathsExist()
Ensures/creates user default paths.
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
const std::string LegacyProjectFileExtension
No directory prepended, full path in filename (used for PROJECT_FILE)
std::map< wxString, PROJECT * > m_projects
Loaded projects, mapped according to project full name.
SETTINGS_MANAGER(bool aHeadless=false)
virtual void setProjectFullName(const wxString &aFullPathAndName)
Set the full directory, basename, and extension of the project.
static wxString GetColorSettingsPath()
Returns the path where color scheme files are stored; creating it if missing (normally .
wxString GetProjectBackupsPath() const
bool loadProjectFile(PROJECT &aProject)
Registers a PROJECT_FILE and attempts to load it from disk.
static wxString GetUserSettingsPath()
Return the user configuration path used to store KiCad's configuration files.
JSON_SETTINGS * RegisterSettings(JSON_SETTINGS *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
std::unordered_map< wxString, COLOR_SETTINGS * > m_color_settings
int min_interval
Minimum time, in seconds, between subsequent backups.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
COLOR_SETTINGS * loadColorSettingsByName(const wxString &aName)
Attempts to load a color theme by name (the color theme directory and .json ext are assumed)
COLOR_SETTINGS * GetColorSettings(const wxString &aName="user")
Retrieves a color settings object that applications can read colors from.
COLOR_SETTINGS_LOADER(std::function< void(const wxString &)> aAction)
void ReloadColorSettings()
Re-scans the color themes directory, reloading any changes it finds.
std::vector< std::unique_ptr< JSON_SETTINGS > > m_settings
std::vector< wxString > GetOpenProjects() const
static wxString calculateUserSettingsPath(bool aIncludeVer=true, bool aUseEnv=true)
Determines the base path for user settings files.
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Saves, unloads and unregisters the given PROJECT.
The main config directory (e.g. ~/.config/kicad/)
bool SaveProject(const wxString &aFullPath=wxEmptyString)
Saves a loaded project.
wxDirTraverseResult OnDir(const wxString &dirPath) override
void SaveColorSettings(COLOR_SETTINGS *aSettings, const std::string &aNamespace="")
Safely saves a COLOR_SETTINGS to disk, preserving any changes outside the given namespace.
static std::string GetSettingsVersion()
Parses the current KiCad build version and extracts the major and minor revision to use as the name o...
Color settings are a bit different than most of the settings objects in that there can be more than o...
virtual const wxString GetProjectName() const
Return the short name of the project.
int limit_daily_files
Maximum files to keep per day, 0 for unlimited.
wxDirTraverseResult OnDir(const wxString &dirPath) override
const wxChar *const traceSettings
Flag to enable debug output of settings operations and management.
COMMON_SETTINGS * m_common_settings
void SetFilename(const wxString &aFilename)
virtual void setProjectFile(PROJECT_FILE *aFile)
Set the backing store file for this project.
COLOR_SETTINGS * GetMigratedColorSettings()
Returns a color theme for storing colors migrated from legacy (5.x and earlier) settings,...
static nlohmann::json::json_pointer PointerFromString(std::string aPath)
Builds a JSON pointer based on a given string.
std::function< void(const wxString &)> m_action
MIGRATION_TRAVERSER(const wxString &aSrcDir, const wxString &aDestDir, bool aMigrateTables)
void FlushAndRelease(JSON_SETTINGS *aSettings, bool aSave=true)
If the given settings object is registered, save it to disk and unregister it.
std::vector< std::unique_ptr< PROJECT > > m_projects_list
Loaded projects (ownership here)
virtual void Load()
Updates the parameters of this object based on the current JSON document contents.
PROJECT * GetProject(const wxString &aFullPath) const
Retrieves a loaded project by name.
int limit_total_files
Maximum number of backup archives to retain.
static bool extractVersion(const std::string &aVersionString, int *aMajor, int *aMinor)
Extracts the numeric version from a given settings string.
void loadAllColorSettings()
wxString GetPathForSettingsFile(JSON_SETTINGS *aSettings)
Returns the path a given settings file should be loaded from / stored to.
const std::string ArchiveFileExtension