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;
73 return wxT(
"EasyEDA (JLCEDA) Schematic Importer" );
79 if( aFileName.Lower().EndsWith( wxS(
".epro" ) ) )
83 else if( aFileName.Lower().EndsWith( wxS(
".zip" ) ) )
85 std::shared_ptr<wxZipEntry> entry;
86 wxFFileInputStream in( aFileName );
87 wxZipInputStream
zip( in );
92 while( entry.reset(
zip.GetNextEntry() ), entry.get() != NULL )
94 wxString
name = entry->GetName();
96 if(
name == wxS(
"project.json" ) )
118 wxFileName libFname( aLibraryPath );
149 if( libFname.GetExt() == wxS(
"epro" ) || libFname.GetExt() == wxS(
"zip" ) )
151 std::map<wxString, EASYEDAPRO::PRJ_SYMBOL> prjSymbols =
project.at(
"symbols" );
152 std::map<wxString, EASYEDAPRO::PRJ_FOOTPRINT> prjFootprints =
project.at(
"footprints" );
153 std::map<wxString, EASYEDAPRO::PRJ_DEVICE> prjDevices =
project.at(
"devices" );
155 auto prjSymIt = std::find_if( prjSymbols.begin(), prjSymbols.end(),
156 [&](
const auto& pair )
158 return pair.second.title == aAliasName;
161 if( prjSymIt == prjSymbols.end() )
164 wxString prjSymUuid = prjSymIt->first;
167 for(
auto& [key, device] : prjDevices )
169 auto val =
get_opt( device.attributes,
"Symbol" );
171 if( val && *val == prjSymUuid )
173 if(
auto fpUuid =
get_opt( device.attributes,
"Footprint" ) )
175 if(
auto prjFp =
get_opt( prjFootprints, *fpUuid ) )
177 fpTitle = prjFp->title;
184 auto cb = [&](
const wxString&
name,
const wxString& symUuid, wxInputStream&
zip ) ->
bool
186 if( !
name.EndsWith( wxS(
".esym" ) ) )
189 if( symUuid != prjSymUuid )
192 wxTextInputStream txt(
zip, wxS(
" " ), wxConvUTF8 );
194 std::vector<nlohmann::json> lines;
195 while(
zip.CanRead() )
197 nlohmann::json js = nlohmann::json::parse( txt.ReadLine() );
198 lines.emplace_back( js );
208 symInfo.
libSymbol->SetName( aAliasName );
209 symInfo.
libSymbol->GetFootprintField().SetText( symLibName + wxS(
"/" ) + fpTitle );
223 const wxString& aLibraryPath,
226 wxFileName fname( aLibraryPath );
228 if( fname.GetExt() == wxS(
"esym" ) )
230 wxFFileInputStream ffis( aLibraryPath );
231 wxTextInputStream txt( ffis, wxS(
" " ), wxConvUTF8 );
233 while( ffis.CanRead() )
235 wxString line = txt.ReadLine();
237 if( !line.Contains( wxS(
"ATTR" ) ) )
240 nlohmann::json js = nlohmann::json::parse( line );
241 if( js.at( 0 ) ==
"ATTR" && js.at( 3 ) ==
"Symbol" )
243 aSymbolNameList.Add( js.at( 4 ).get<wxString>() );
247 else if( fname.GetExt() == wxS(
"epro" ) || fname.GetExt() == wxS(
"zip" ) )
250 std::map<wxString, nlohmann::json> symbolMap =
project.at(
"symbols" );
252 for(
auto& [key, value] : symbolMap )
253 aSymbolNameList.Add( value.at(
"title" ) );
259 const wxString& aLibraryPath,
262 wxFileName libFname( aLibraryPath );
263 wxArrayString symbolNameList;
268 if( libFname.GetExt() == wxS(
"epro" ) || libFname.GetExt() == wxS(
"zip" ) )
271 for(
const wxString& symbolName : symbolNameList )
276 aSymbolList.push_back( sym );
289 wxFileName fname( aProjectPath );
292 if( fname.GetExt() != wxS(
"epro" ) && fname.GetExt() != wxS(
"zip" ) )
297 std::map<wxString, EASYEDAPRO::PRJ_SYMBOL> prjSymbols =
project.at(
"symbols" );
298 std::map<wxString, EASYEDAPRO::PRJ_FOOTPRINT> prjFootprints =
project.at(
"footprints" );
299 std::map<wxString, EASYEDAPRO::PRJ_DEVICE> prjDevices =
project.at(
"devices" );
301 auto cb = [&](
const wxString&
name,
const wxString& baseName, wxInputStream&
zip ) ->
bool
303 if( !
name.EndsWith( wxS(
".esym" ) ) && !
name.EndsWith( wxS(
".eblob" ) ) )
308 if(
name.EndsWith( wxS(
".esym" ) ) )
318 for(
auto& [key, device] : prjDevices )
320 auto val =
get_opt( device.attributes,
"Symbol" );
322 if( val && *val == baseName )
324 if(
auto fpUuid =
get_opt( device.attributes,
"Footprint" ) )
326 if(
auto prjFp =
get_opt( prjFootprints, *fpUuid ) )
328 fpTitle = prjFp->title;
338 symInfo.
libSymbol->GetFootprintField().SetText( symLibName + wxS(
"/" ) + fpTitle );
342 else if(
name.EndsWith( wxS(
".eblob" ) ) )
344 for(
const nlohmann::json& line : lines )
346 if( line.at( 0 ) ==
"BLOB" )
361 const wxString& aAliasName,
364 wxFileName libFname( aLibraryPath );
367 if( libFname.GetExt() == wxS(
"epro" ) || libFname.GetExt() == wxS(
"zip" ) )
378 wxCHECK( !aFileName.IsEmpty() && aSchematic,
nullptr );
384 wxCHECK_MSG( aSchematic->
IsValid(),
nullptr,
385 wxS(
"Can't append to a schematic with no root!" ) );
387 rootSheet = &aSchematic->
Root();
393 aSchematic->
SetRoot( rootSheet );
405 wxCHECK_MSG( libTable,
nullptr, wxS(
"Could not load symbol lib table." ) );
408 wxFileName fname( aFileName );
413 if( fname.GetExt() != wxS(
"epro" ) && fname.GetExt() != wxS(
"zip" ) )
418 std::map<wxString, EASYEDAPRO::PRJ_SCHEMATIC> prjSchematics =
project.at(
"schematics" );
420 wxString schematicToLoad;
422 if( aProperties && aProperties->
Exists(
"sch_id" ) )
424 schematicToLoad = wxString::FromUTF8( aProperties->at(
"sch_id" ) );
428 if( prjSchematics.size() == 1 )
430 schematicToLoad = prjSchematics.begin()->first;
437 if( chosen.size() > 0 )
438 schematicToLoad = chosen[0].SchematicId;
442 if( schematicToLoad.empty() )
447 wxFileName rootFname( aFileName );
448 rootFname.SetFullName( rootBaseName + wxS(
"." )
451 rootSheet->
SetName( prjSchematics[schematicToLoad].
name );
455 const std::vector<EASYEDAPRO::PRJ_SHEET>& prjSchematicSheets =
456 prjSchematics[schematicToLoad].sheets;
463 auto cbs = [&](
const wxString&
name,
const wxString& symUuid, wxInputStream&
zip ) ->
bool
465 if( !
name.EndsWith( wxS(
".esch" ) ) )
468 wxArrayString nameParts = wxSplit(
name,
'\\',
'\0' );
470 if( nameParts.size() == 1 )
471 nameParts = wxSplit(
name,
'/',
'\0' );
473 if( nameParts.size() < 3 )
476 wxString schematicUuid = nameParts[1];
477 wxString sheetFileName = nameParts[2];
478 wxString sheetId = sheetFileName.BeforeLast(
'.' );
480 sheetId.ToInt( &sheetId_i );
482 if( schematicUuid != schematicToLoad )
485 auto prjSheetIt = std::find_if( prjSchematicSheets.begin(), prjSchematicSheets.end(),
488 return s.id == sheetId_i;
491 if( prjSheetIt == prjSchematicSheets.end() )
494 wxString sheetBaseName =
497 wxFileName sheetFname( aFileName );
498 sheetFname.SetFullName( sheetBaseName + wxS(
"." )
501 std::unique_ptr<SCH_SHEET> subSheet = std::make_unique<SCH_SHEET>( aSchematic );
502 subSheet->SetFileName( sheetFname.GetFullPath() );
503 subSheet->SetName( prjSheetIt->name );
508 subSheet->SetScreen( screen );
515 subSheet->SetPosition( pos );
535 sch_plugin.
set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
541 wxString libTableUri = wxS(
"${KIPRJMOD}/" ) + libFileName.GetFullName();
553 libTable->
Format( &formatter, 0 );
566 sch_plugin->
SaveSymbol( libFileName.GetFullPath(), symInfo.libSymbol.release(),
569 sch_plugin->
SaveLibrary( libFileName.GetFullPath() );
constexpr EDA_IU_SCALE schIUScale
void SetPageNumber(const wxString &aPageNumber)
A logical library item identifier and consists of various portions much like a URI.
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)
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)
PROGRESS_REPORTER * m_progressReporter
int GetModifyHash() const override
Return the modification hash from the library cache.
const wxString GetName() const override
Return a brief hard coded name for this SCH_PLUGIN.
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...
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_PLUGIN implementation knows about,...
void LoadAllDataFromProject(const wxString &aLibraryPath)
bool CanReadSchematicFile(const wxString &aFileName) const override
Checks if this SCH_PLUGIN can read the specified schematic file.
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.
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
void set(SCH_PLUGIN *aPlugin)
virtual void SaveSymbol(const wxString &aLibraryPath, const LIB_SYMBOL *aSymbol, const STRING_UTF8_MAP *aProperties=nullptr)
Write aSymbol to an existing library located at aLibraryPath.
virtual void SaveLibrary(const wxString &aFileName, const STRING_UTF8_MAP *aProperties=nullptr)
virtual void CreateSymbolLib(const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties=nullptr)
Create a new empty symbol library at aLibraryPath.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
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_PLUGIN obje...
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()
const std::string KiCadSymbolLibFileExtension
const std::string KiCadSchematicFileExtension
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
LIB_ID ToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
nlohmann::json ReadProjectFile(const wxString &aZipFileName)
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)
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::SYM_INFO > m_Symbols
std::map< wxString, EASYEDAPRO::BLOB > m_Blobs
Definition of file extensions used in Kicad.