28#include <wx/filename.h>
30#include <wx/translation.h>
33#include <wx/datetime.h>
52 default:
return wxString::Format( wxT(
"UNKNOWN (%d)" ), aFileType );
60 if( aFileType.CmpNoCase( wxT(
"KiCad" ) ) == 0 )
64 else if( aFileType ==
_(
"KiCad" ) )
80 default:
return nullptr;
90 if( parser.
Parse( aLibPath.ToStdString() ).has_value() )
104 const wxString& aOldFilePath,
105 const wxString& aNewFilePath )
121 if( !oldFilePI || !kicadPI )
124 wxArrayString dbNames;
125 wxFileName newFileName( aNewFilePath );
128 if( newFileName.HasExt() )
130 wxString extraDir = newFileName.GetFullName();
131 newFileName.ClearExt();
132 newFileName.SetName(
"" );
133 newFileName.AppendDir( extraDir );
136 if( !newFileName.DirExists() && !wxFileName::Mkdir( aNewFilePath, wxS_DIR_DEFAULT ) )
141 bool bestEfforts =
false;
142 oldFilePI->DesignBlockEnumerate( dbNames, aOldFilePath, bestEfforts, aOldFileProps );
144 for(
const wxString& dbName : dbNames )
146 std::unique_ptr<DESIGN_BLOCK> db(
147 oldFilePI->DesignBlockLoad( aOldFilePath, dbName,
false, aOldFileProps ) );
148 db->SetLibId(
LIB_ID( newLibName, dbName ) );
149 kicadPI->DesignBlockSave( aNewFilePath, db.get() );
170 wxDir libDir( aLibraryPath );
172 if( !libDir.IsOpened() )
178 bool hasMoreFiles = libDir.GetFirst( &filename, wxEmptyString, wxDIR_DIRS );
180 while( hasMoreFiles )
182 wxFileName blockDir( aLibraryPath, filename );
188 hasMoreFiles = libDir.GetNext( &filename );
196 const std::map<std::string, UTF8>* aProperties )
198 if( wxDir::Exists( aLibraryPath ) )
199 THROW_IO_ERRORF(
_(
"Cannot overwrite library path '%s'." ), aLibraryPath.GetData() );
202 dir.SetPath( aLibraryPath );
207 "Make sure you have write permissions and try again." ), dir.GetPath() );
213 const std::map<std::string, UTF8>* aProperties )
216 fn.SetPath( aLibraryPath );
219 if( !fn.DirExists() )
222 if( !fn.IsDirWritable() )
223 THROW_IO_ERRORF(
_(
"Insufficient permissions to delete folder '%s'." ), aLibraryPath.GetData() );
225 wxDir dir( aLibraryPath );
229 THROW_IO_ERRORF(
_(
"Library folder '%s' has unexpected files." ), aLibraryPath.GetData() );
232 if( dir.HasSubDirs() )
239 for(
size_t i = 0; i < dirs.GetCount(); i++ )
241 wxFileName tmp = dirs[i];
247 aLibraryPath.GetData() );
251 for(
size_t i = 0; i < dirs.GetCount(); i++ )
252 wxRemoveFile( dirs[i] );
255 wxLogTrace(
traceDesignBlocks, wxT(
"Removing design block library '%s'." ), aLibraryPath.GetData() );
259 if( !wxFileName::Rmdir( aLibraryPath, wxPATH_RMDIR_RECURSIVE ) )
260 THROW_IO_ERRORF(
_(
"Design block library '%s' cannot be deleted." ), aLibraryPath.GetData() );
266 wxMilliSleep( 250L );
274 const wxString& aLibraryPath,
bool aBestEfforts,
275 const std::map<std::string, UTF8>* aProperties )
278 wxDir dir( aLibraryPath );
280 if( !dir.IsOpened() )
281 THROW_IO_ERRORF(
_(
"Design block library folder '%s' could not be opened." ), aLibraryPath );
285 bool cont = dir.GetFirst( &dirname, fileSpec, wxDIR_DIRS );
289 aDesignBlockNames.Add( dirname.BeforeLast( wxT(
'.' ) ) );
290 cont = dir.GetNext( &dirname );
296 const wxString& aDesignBlockName,
bool aKeepUUID,
297 const std::map<std::string, UTF8>* aProperties )
299 wxString dbPath = aLibraryPath + wxFileName::GetPathSeparator() + aDesignBlockName + wxT(
"." )
301 wxString dbSchPath = dbPath + aDesignBlockName + wxT(
"." )
306 if( !wxDir::Exists( dbPath ) )
307 THROW_IO_ERRORF(
_(
"Design block '%s' does not exist in library '%s'." ), aDesignBlockName, aLibraryPath );
315 if( wxFileExists( dbSchPath ) )
318 if( wxFileExists( dbPcbPath ) )
322 if( wxFileExists( dbMetadataPath ) )
326 nlohmann::ordered_json dbMetadata;
327 std::ifstream dbMetadataFile( dbMetadataPath.fn_str() );
329 dbMetadataFile >> dbMetadata;
331 if( dbMetadata.contains(
"description" ) )
334 if( dbMetadata.contains(
"keywords" ) )
335 newDB->
SetKeywords( dbMetadata[
"keywords"].get<std::string>() );
338 if( dbMetadata.contains(
"fields" ) )
340 for(
auto& item : dbMetadata[
"fields"].items() )
342 wxString
name = wxString::FromUTF8( item.key() );
343 wxString value = wxString::FromUTF8( item.value().get<std::string>() );
352 THROW_IO_ERRORF(
_(
"Design block metadata file '%s' could not be read." ), dbMetadataPath );
361 const wxString& aDesignBlockName,
362 const std::map<std::string, UTF8>* aProperties )
364 wxString dbPath = aLibraryPath + wxFileName::GetPathSeparator() + aDesignBlockName + wxT(
"." )
367 return wxDir::Exists( dbPath );
373 const std::map<std::string, UTF8>* aProperties )
377 THROW_IO_ERROR(
_(
"Design block does not have a valid library ID." ) );
380 THROW_IO_ERROR(
_(
"Design block does not have a schematic or board file." ) );
385 if( !aDesignBlock->
GetSchematicFile().IsEmpty() && !schematicFile.FileExists() )
386 THROW_IO_ERRORF(
_(
"Schematic source file '%s' does not exist." ), schematicFile.GetFullPath() );
388 if( !aDesignBlock->
GetBoardFile().IsEmpty() && !boardFile.FileExists() )
389 THROW_IO_ERRORF(
_(
"Board source file '%s' does not exist." ), boardFile.GetFullPath() );
392 wxFileName dbFolder( aLibraryPath + wxFileName::GetPathSeparator()
395 + wxFileName::GetPathSeparator() );
397 if( !dbFolder.DirExists() )
399 if( !dbFolder.Mkdir() )
400 THROW_IO_ERRORF(
_(
"Design block folder '%s' could not be created." ), dbFolder.GetFullPath().GetData() );
406 wxString dbSchematicFile = dbFolder.GetFullPath() + aDesignBlock->
GetLibId().
GetLibItemName() + wxT(
"." )
411 if( schematicFile.GetFullPath() != dbSchematicFile )
414 if( !wxCopyFile( schematicFile.GetFullPath(), dbSchematicFile ) )
416 THROW_IO_ERRORF(
_(
"Schematic file '%s' could not be saved as design block at '%s'." ),
417 schematicFile.GetFullPath(),
431 if( boardFile.GetFullPath() != dbBoardFile )
434 if( !wxCopyFile( boardFile.GetFullPath(), dbBoardFile ) )
436 THROW_IO_ERRORF(
_(
"Board file '%s' could not be saved as design block at '%s'." ),
437 boardFile.GetFullPath(),
447 nlohmann::ordered_json dbMetadata;
449 dbMetadata[
"keywords"] = aDesignBlock->
GetKeywords();
450 dbMetadata[
"fields"] = aDesignBlock->
GetFields();
452 bool success =
false;
456 std::string payload = dbMetadata.dump( 0 );
461 wxLogError(
_(
"Cannot save design block metadata '%s': %s" ), dbMetadataFile, writeError );
469 THROW_IO_ERRORF(
_(
"Design block metadata file '%s' could not be saved." ), dbMetadataFile );
474 const std::map<std::string, UTF8>* aProperties )
476 wxFileName dbDir = wxFileName( aLibPath + wxFileName::GetPathSeparator() + aDesignBlockName
479 if( !dbDir.DirExists() )
480 THROW_IO_ERRORF(
_(
"Design block '%s' does not exist." ), dbDir.GetFullName() );
483 if( !wxFileName::Rmdir( dbDir.GetFullPath(), wxPATH_RMDIR_RECURSIVE ) )
484 THROW_IO_ERRORF(
_(
"Design block folder '%s' could not be deleted." ), dbDir.GetFullPath().GetData() );
490 wxFileName
path( aLibraryPath );
491 return path.IsOk() &&
path.IsDirWritable();
@ KICAD_SEXP
S-expression KiCad file format.
@ DESIGN_BLOCK_FILE_UNKNOWN
0 is not a legal menu id on Mac
static const wxString ShowType(DESIGN_BLOCK_FILE_T aFileType)
static DESIGN_BLOCK_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
static DESIGN_BLOCK_FILE_T EnumFromStr(const wxString &aFileType)
static bool ConvertLibrary(std::map< std::string, UTF8 > *aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilePath)
Convert a design block library to the latest KiCad format.
static DESIGN_BLOCK_IO * FindPlugin(DESIGN_BLOCK_FILE_T aFileType)
bool DesignBlockExists(const wxString &aLibraryPath, const wxString &aDesignBlockName, const std::map< std::string, UTF8 > *aProperties=nullptr)
long long GetLibraryTimestamp(const wxString &aLibraryPath) const
void DesignBlockDelete(const wxString &aLibraryPath, const wxString &aDesignBlockName, const std::map< std::string, UTF8 > *aProperties=nullptr)
DESIGN_BLOCK * DesignBlockLoad(const wxString &aLibraryPath, const wxString &aDesignBlockName, bool aKeepUUID=false, const std::map< std::string, UTF8 > *aProperties=nullptr)
void DesignBlockSave(const wxString &aLibraryPath, const DESIGN_BLOCK *aDesignBlock, const std::map< std::string, UTF8 > *aProperties=nullptr)
void DesignBlockEnumerate(wxArrayString &aDesignBlockNames, const wxString &aLibraryPath, bool aBestEfforts, const std::map< std::string, UTF8 > *aProperties=nullptr)
virtual bool DeleteLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Delete an existing library and returns true, or if library does not exist returns false,...
void CreateLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Create a new empty library at aLibraryPath empty.
bool IsLibraryWritable(const wxString &aLibraryPath) override
Return true if the library at aLibraryPath is writable.
const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
Get the descriptor for the library container that this IO plugin operates on.
void SetLibDescription(const wxString &aDesc)
void SetKeywords(const wxString &aKeywords)
void SetSchematicFile(const wxString &aFile)
void SetBoardFile(const wxString &aFile)
const wxString & GetKeywords() const
const wxString & GetLibDescription() const
void SetLibId(const LIB_ID &aName)
const wxString & GetBoardFile() const
const wxString & GetSchematicFile() const
const LIB_ID & GetLibId() const
const nlohmann::ordered_map< wxString, wxString > & GetFields() const
tl::expected< LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR > Parse(const std::filesystem::path &aPath)
static const wxString TABLE_TYPE_NAME
A logical library item identifier and consists of various portions much like a URI.
bool IsValid() const
Check if this LID_ID is valid.
const UTF8 & GetLibItemName() const
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
void CollectSubdirsLoopSafe(const wxString &aRoot, wxArrayString &aDirs, int aFlags)
Recursively collect every subdirectory under aRoot using the same loop detection as CollectFilesLoopS...
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
static const std::string KiCadDesignBlockLibPathExtension
static const std::string KiCadDesignBlockPathExtension
static const std::string JsonFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string KiCadPcbFileExtension
const wxChar *const traceDesignBlocks
Some functions to handle hotkeys in KiCad.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
#define KICTL_NONKICAD_ONLY
chosen file is non-KiCad according to user
Container that describes file type info.
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.