34#include <wx/txtstrm.h>
35#include <wx/wfstream.h>
36#include <wx/mstream.h>
37#include <wx/zipstrm.h>
41#include <nlohmann/json.hpp>
53 std::map<wxString, EASYEDAPRO::BLOB>
m_Blobs;
72 if( aFileName.Lower().EndsWith( wxS(
".epro" ) ) )
76 else if( aFileName.Lower().EndsWith( wxS(
".zip" ) ) )
78 std::shared_ptr<wxZipEntry> entry;
79 wxFFileInputStream in( aFileName );
80 wxZipInputStream
zip( in );
85 while( entry.reset(
zip.GetNextEntry() ), entry.get() != NULL )
87 wxString
name = entry->GetName();
89 if(
name == wxS(
"project.json" ) )
111 wxFileName libFname( aLibraryPath );
142 if( libFname.GetExt() == wxS(
"elibz" ) || libFname.GetExt() == wxS(
"epro" )
143 || libFname.GetExt() == wxS(
"zip" ) )
145 std::map<wxString, EASYEDAPRO::PRJ_SYMBOL> prjSymbols =
project.at(
"symbols" );
146 std::map<wxString, EASYEDAPRO::PRJ_FOOTPRINT> prjFootprints =
project.at(
"footprints" );
147 std::map<wxString, EASYEDAPRO::PRJ_DEVICE> prjDevices =
project.at(
"devices" );
149 auto prjSymIt = std::find_if( prjSymbols.begin(), prjSymbols.end(),
150 [&](
const auto& pair )
152 return pair.second.title == aAliasName;
155 if( prjSymIt == prjSymbols.end() )
158 wxString prjSymUuid = prjSymIt->first;
160 wxString description;
162 std::map<wxString, wxString> deviceAttributes;
165 for(
auto& [key, device] : prjDevices )
167 auto val =
get_opt( device.attributes,
"Symbol" );
169 if( val && *val == prjSymUuid )
171 description = device.description;
172 deviceAttributes = device.attributes;
174 if( device.custom_tags.is_string() )
175 customTags = device.custom_tags.get<wxString>();
177 if(
auto fpUuid =
get_opt( device.attributes,
"Footprint" ) )
179 if(
auto prjFp =
get_opt( prjFootprints, *fpUuid ) )
181 fpTitle = prjFp->title;
188 auto cb = [&](
const wxString&
name,
const wxString& symUuid, wxInputStream&
zip ) ->
bool
190 if( !
name.EndsWith( wxS(
".esym" ) ) )
193 if( symUuid != prjSymUuid )
196 wxTextInputStream txt(
zip, wxS(
" " ), wxConvUTF8 );
198 std::vector<nlohmann::json> lines;
199 while(
zip.CanRead() )
201 nlohmann::json js = nlohmann::json::parse( txt.ReadLine() );
202 lines.emplace_back( js );
212 symInfo.
libSymbol->SetName( aAliasName );
213 symInfo.
libSymbol->GetFootprintField().SetText( symLibName + wxS(
":" ) + fpTitle );
215 wxString keywords = customTags;
216 keywords.Replace( wxS(
":" ), wxS(
" " ),
true );
218 symInfo.
libSymbol->SetKeyWords( keywords );
220 description.Replace( wxS(
"\u2103" ), wxS(
"\u00B0C" ),
true );
222 symInfo.
libSymbol->SetDescription( description );
236 const wxString& aLibraryPath,
239 wxFileName fname( aLibraryPath );
241 if( fname.GetExt() == wxS(
"esym" ) )
243 wxFFileInputStream ffis( aLibraryPath );
244 wxTextInputStream txt( ffis, wxS(
" " ), wxConvUTF8 );
246 while( ffis.CanRead() )
248 wxString line = txt.ReadLine();
250 if( !line.Contains( wxS(
"ATTR" ) ) )
253 nlohmann::json js = nlohmann::json::parse( line );
254 if( js.at( 0 ) ==
"ATTR" && js.at( 3 ) ==
"Symbol" )
256 aSymbolNameList.Add( js.at( 4 ).get<wxString>() );
260 else if( fname.GetExt() == wxS(
"elibz" ) || fname.GetExt() == wxS(
"epro" )
261 || fname.GetExt() == wxS(
"zip" ) )
264 std::map<wxString, nlohmann::json> symbolMap =
project.at(
"symbols" );
266 for(
auto& [key, value] : symbolMap )
270 if( value.contains(
"display_title" ) )
271 title = value.at(
"display_title" ).get<wxString>();
273 title = value.at(
"title" ).get<wxString>();
275 aSymbolNameList.Add( title );
282 const wxString& aLibraryPath,
285 wxFileName libFname( aLibraryPath );
286 wxArrayString symbolNameList;
291 if( libFname.GetExt() == wxS(
"elibz" ) || libFname.GetExt() == wxS(
"epro" )
292 || libFname.GetExt() == wxS(
"zip" ) )
297 for(
const wxString& symbolName : symbolNameList )
302 aSymbolList.push_back( sym );
315 wxFileName fname( aProjectPath );
318 if( fname.GetExt() != wxS(
"epro" ) && fname.GetExt() != wxS(
"zip" ) )
323 std::map<wxString, EASYEDAPRO::PRJ_SYMBOL> prjSymbols =
project.at(
"symbols" );
324 std::map<wxString, EASYEDAPRO::PRJ_FOOTPRINT> prjFootprints =
project.at(
"footprints" );
325 std::map<wxString, EASYEDAPRO::PRJ_DEVICE> prjDevices =
project.at(
"devices" );
327 auto cb = [&](
const wxString&
name,
const wxString& baseName, wxInputStream&
zip ) ->
bool
329 if( !
name.EndsWith( wxS(
".esym" ) ) && !
name.EndsWith( wxS(
".eblob" ) ) )
334 if(
name.EndsWith( wxS(
".esym" ) ) )
336 wxString description;
338 std::map<wxString, wxString> deviceAttributes;
341 for(
auto& [key, device] : prjDevices )
343 auto val =
get_opt( device.attributes,
"Symbol" );
345 if( val && *val == baseName )
347 description = device.description;
348 deviceAttributes = device.attributes;
350 if( device.custom_tags.is_string() )
351 customTags = device.custom_tags.get<wxString>();
353 if(
auto fpUuid =
get_opt( device.attributes,
"Footprint" ) )
355 if(
auto prjFp =
get_opt( prjFootprints, *fpUuid ) )
357 fpTitle = prjFp->title;
373 symInfo.
libSymbol->GetFootprintField().SetText( symLibName + wxS(
":" ) + fpTitle );
375 wxString keywords = customTags;
376 keywords.Replace( wxS(
":" ), wxS(
" " ),
true );
378 symInfo.
libSymbol->SetKeyWords( keywords );
380 description.Replace( wxS(
"\u2103" ), wxS(
"\u00B0C" ),
true );
382 symInfo.
libSymbol->SetDescription( description );
386 else if(
name.EndsWith( wxS(
".eblob" ) ) )
388 for(
const nlohmann::json& line : lines )
390 if( line.at( 0 ) ==
"BLOB" )
407 wxFileName libFname( aLibraryPath );
410 if( libFname.GetExt() == wxS(
"elibz" ) || libFname.GetExt() == wxS(
"epro" )
411 || libFname.GetExt() == wxS(
"zip" ) )
424 wxCHECK( !aFileName.IsEmpty() && aSchematic,
nullptr );
430 wxCHECK_MSG( aSchematic->
IsValid(),
nullptr,
431 wxS(
"Can't append to a schematic with no root!" ) );
433 rootSheet = &aSchematic->
Root();
439 aSchematic->
SetRoot( rootSheet );
451 wxCHECK_MSG( libTable,
nullptr, wxS(
"Could not load symbol lib table." ) );
454 wxFileName fname( aFileName );
459 if( fname.GetExt() != wxS(
"epro" ) && fname.GetExt() != wxS(
"zip" ) )
464 std::map<wxString, EASYEDAPRO::PRJ_SCHEMATIC> prjSchematics =
project.at(
"schematics" );
466 wxString schematicToLoad;
468 if( aProperties && aProperties->
Exists(
"sch_id" ) )
470 schematicToLoad = wxString::FromUTF8( aProperties->at(
"sch_id" ) );
474 if( prjSchematics.size() == 1 )
476 schematicToLoad = prjSchematics.begin()->first;
483 if( chosen.size() > 0 )
484 schematicToLoad = chosen[0].SchematicId;
488 if( schematicToLoad.empty() )
493 wxFileName rootFname( aFileName );
494 rootFname.SetFullName( rootBaseName + wxS(
"." )
497 rootSheet->
SetName( prjSchematics[schematicToLoad].
name );
501 const std::vector<EASYEDAPRO::PRJ_SHEET>& prjSchematicSheets =
502 prjSchematics[schematicToLoad].sheets;
509 const int schSheetsCount = prjSchematicSheets.size();
511 auto cbs = [&](
const wxString&
name,
const wxString& baseName, wxInputStream&
zip ) ->
bool
513 if( !
name.EndsWith( wxS(
".esch" ) ) )
516 wxArrayString nameParts = wxSplit(
name,
'\\',
'\0' );
518 if( nameParts.size() == 1 )
519 nameParts = wxSplit(
name,
'/',
'\0' );
521 if( nameParts.size() < 3 )
524 wxString schematicUuid = nameParts[1];
525 wxString sheetFileName = nameParts[2];
526 wxString sheetId = sheetFileName.BeforeLast(
'.' );
528 sheetId.ToInt( &sheetId_i );
530 if( schematicUuid != schematicToLoad )
533 auto prjSheetIt = std::find_if( prjSchematicSheets.begin(), prjSchematicSheets.end(),
536 return s.id == sheetId_i;
539 if( prjSheetIt == prjSchematicSheets.end() )
544 if( schSheetsCount > 1 )
546 wxString sheetBaseName =
549 wxFileName sheetFname( aFileName );
550 sheetFname.SetFullName( sheetBaseName + wxS(
"." )
553 wxFileName relSheetPath( sheetFname );
554 relSheetPath.MakeRelativeTo( rootFname.GetPath() );
556 std::unique_ptr<SCH_SHEET> subSheet = std::make_unique<SCH_SHEET>( aSchematic );
557 subSheet->SetFileName( relSheetPath.GetFullPath() );
558 subSheet->SetName( prjSheetIt->name );
563 subSheet->SetScreen( screen );
570 subSheet->SetPosition( pos );
598 sch_plugin->CreateLibrary( libFileName.GetFullPath() );
599 wxString libTableUri = wxS(
"${KIPRJMOD}/" ) + libFileName.GetFullName();
611 libTable->
Format( &formatter, 0 );
624 sch_plugin->SaveSymbol( libFileName.GetFullPath(), symInfo.libSymbol.release(),
627 sch_plugin->SaveLibrary( libFileName.GetFullPath() );
constexpr EDA_IU_SCALE schIUScale
void SetPageNumber(const wxString &aPageNumber)
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
A logical library item identifier and consists of various portions much like a URI.
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Define a library symbol object.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
CHOOSE_PROJECT_HANDLER m_choose_project_handler
Callback to choose projects to import.
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
virtual const wxString GetProjectPath() const
Return the full path of the project.
virtual void SetElem(ELEM_T aIndex, _ELEM *aElem)
Holds all the data relating to one schematic.
SCH_SHEET_PATH & CurrentSheet() const override
void SetCurrentSheet(const SCH_SHEET_PATH &aPath) override
void FixupJunctions()
Add junctions to this schematic where required.
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
EASYEDAPRO::SYM_INFO ParseSymbol(const std::vector< nlohmann::json > &aLines, const std::map< wxString, wxString > &aDeviceAttributes)
void ParseSchematic(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet, const nlohmann::json &aProject, std::map< wxString, EASYEDAPRO::SYM_INFO > &aSymbolMap, const std::map< wxString, EASYEDAPRO::BLOB > &aBlobMap, const std::vector< nlohmann::json > &aLines, const wxString &aLibName)
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const STRING_UTF8_MAP *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
void LoadAllDataFromProject(const wxString &aLibraryPath)
int GetModifyHash() const override
Return the modification hash from the library cache.
bool CanReadSchematicFile(const wxString &aFileName) const override
Checks if this SCH_IO can read the specified schematic file.
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const STRING_UTF8_MAP *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
Base class that schematic file and library loading and saving plugins should derive from.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
void SetFileName(const wxString &aFilename)
void SetName(const wxString &aName)
SCH_SCREEN * GetScreen() const
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
A name/value tuple with unique names and optional values.
bool Exists(const std::string &aProperty) const
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_IO object i...
static const wxString & GetSymbolLibTableFileName()
virtual void Format(OUTPUTFORMATTER *aOutput, int aIndentLevel) const override
Generate the table in s-expression format to aOutput with an indentation level of aIndentLevel.
static REPORTER & GetInstance()
static const std::string KiCadSchematicFileExtension
static const std::string KiCadSymbolLibFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
LIB_ID ToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
void IterateZipFiles(const wxString &aFileName, std::function< bool(const wxString &, const wxString &, wxInputStream &)> aCallback)
std::vector< nlohmann::json > ParseJsonLines(wxInputStream &aInput, const wxString &aSource)
std::vector< IMPORT_PROJECT_DESC > ProjectToSelectorDialog(const nlohmann::json &aProject, bool aPcbOnly=false, bool aSchOnly=false)
nlohmann::json ReadProjectOrDeviceFile(const wxString &aZipFileName)
wxString ShortenLibName(wxString aProjectName)
LIB_SYMBOL * loadSymbol(const wxString &aLibraryPath, nlohmann::json aFileData, const wxString &aAliasName, const STRING_UTF8_MAP *aProperties)
static LIB_SYMBOL * loadSymbol(nlohmann::json project, const wxString &aLibraryPath, const wxString &aAliasName, const STRING_UTF8_MAP *aProperties)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
std::unique_ptr< LIB_SYMBOL > libSymbol
constexpr int MilsToIU(int mils) const
std::map< wxString, EASYEDAPRO::BLOB > m_Blobs
std::map< wxString, EASYEDAPRO::SYM_INFO > m_Symbols
Definition of file extensions used in Kicad.