48#include <wx/filename.h>
56 wxFileName fileName( aFileName );
58 if( fileName.IsFileReadable() && fileName.GetModificationTime().IsValid() )
59 return fileName.GetModificationTime().GetValue().GetValue();
67 const wxString& aSymbolName,
68 const std::map<wxString, EASYEDAPRO::BLOB>& aBlobs,
76 static const std::map<wxString, wxString> emptyAttributes;
94 wxString fpTitle = *fpUuid;
97 if(
index.contains(
"footprints" ) &&
index.at(
"footprints" ).is_object() )
99 const nlohmann::json& footprints =
index.at(
"footprints" );
100 const std::string key( fpUuid->ToUTF8() );
102 if( footprints.contains( key ) )
113 if( !keywords.empty() )
122 SCH_IO( wxS(
"EasyEDA Pro (JLCEDA) Schematic v3" ) )
163 const std::map<std::string, UTF8>* aProperties )
171 aSymbolNameList.Add(
name );
177 const std::map<std::string, UTF8>* aProperties )
189 for(
const auto& [symbolName, item] : items )
194 aSymbolList.push_back( symbol );
196 catch( nlohmann::json::exception& e )
199 wxString::Format(
_(
"EasyEDA Pro v3 symbol '%s' in '%s' was skipped due to parse error: %s" ),
200 symbolName, aLibraryPath, e.what() ) );
207 const std::map<std::string, UTF8>* aProperties )
214 auto itemIt = items.find( aAliasName );
216 if( itemIt == items.end() )
228 catch( nlohmann::json::exception& e )
231 wxString::Format(
_(
"Cannot load symbol '%s' from '%s': %s" ), aAliasName, aLibraryPath, e.what() ) );
238 const std::map<std::string, UTF8>* aProperties )
240 wxCHECK( !aFileName.IsEmpty() && aSchematic,
nullptr );
248 wxCHECK_MSG( aSchematic->
IsValid(),
nullptr, wxS(
"Can't append to a schematic with no root!" ) );
250 rootSheet = aAppendToMe;
274 std::map<wxString, EASYEDAPRO::PRJ_SCHEMATIC> prjSchematics =
project.at(
"schematics" );
276 wxString schematicToLoad;
278 if( aProperties && aProperties->contains(
"sch_id" ) )
280 schematicToLoad = wxString::FromUTF8( aProperties->at(
"sch_id" ) );
282 else if( prjSchematics.size() == 1 )
284 schematicToLoad = prjSchematics.begin()->first;
288 std::vector<IMPORT_PROJECT_DESC> chosen =
291 if( !chosen.empty() )
292 schematicToLoad = chosen[0].SchematicId;
294 else if( !prjSchematics.empty() )
296 schematicToLoad = prjSchematics.begin()->first;
299 if( schematicToLoad.empty() )
302 auto prjSchIt = prjSchematics.find( schematicToLoad );
304 if( prjSchIt == prjSchematics.end() )
307 wxString::Format(
_(
"Schematic document '%s' not found in '%s'" ), schematicToLoad, aFileName ) );
310 wxFileName sourceName( aFileName );
317 wxFileName rootFname( aFileName );
320 rootSheet->
SetName( prjSchIt->second.name );
326 std::map<wxString, EASYEDAPRO::PRJ_SYMBOL> prjSymbols;
327 std::map<wxString, EASYEDAPRO::PRJ_FOOTPRINT> prjFootprints;
328 std::map<wxString, EASYEDAPRO::PRJ_DEVICE> prjDevices;
332 if(
project.contains(
"symbols" ) )
333 prjSymbols =
project.at(
"symbols" );
335 if(
project.contains(
"footprints" ) )
336 prjFootprints =
project.at(
"footprints" );
338 if(
project.contains(
"devices" ) )
339 prjDevices =
project.at(
"devices" );
341 catch( nlohmann::json::exception& e )
344 wxString::Format(
_(
"Failed to parse EasyEDA Pro v3 symbol/device metadata: %s" ), e.what() ) );
349 std::set<wxString> usedLibNames;
350 std::map<wxString, wxString> deviceLibNames =
353 std::map<wxString, EASYEDAPRO::SYM_INFO> symbols;
356 for(
const auto& [symbolUuid, rawDoc] :
v3.GetRawDocs( wxS(
"SYMBOL" ) ) )
358 auto symMetaIt = prjSymbols.find( symbolUuid );
360 if( symMetaIt == prjSymbols.end() )
370 catch( nlohmann::json::exception& e )
372 wxLogWarning( wxString::Format(
_(
"EasyEDA Pro v3 symbol '%s' was skipped due to parse error: %s" ),
373 symbolUuid, e.what() ) );
388 if( !keywords.empty() )
391 symbols.emplace( symbolUuid, std::move( symInfo ) );
394 const std::vector<EASYEDAPRO::PRJ_SHEET>& prjSchematicSheets = prjSchIt->second.sheets;
396 bool rootAssigned =
false;
397 int subSheetIndex = 0;
405 wxLogWarning( wxString::Format(
_(
"EasyEDA Pro v3 schematic page '%s' was not found and was skipped." ),
410 wxString sheetId = wxString::Format(
"%d", prjSheet.id );
425 catch( nlohmann::json::exception& e )
428 wxString::Format(
_(
"EasyEDA Pro v3 schematic page '%s' was skipped due to parse error: %s" ),
429 prjSheet.uuid, e.what() ) );
433 rootSheet->
SetName( prjSheet.name );
441 wxFileName sheetFname( aFileName );
442 sheetFname.SetFullName( sheetBaseName + wxS(
"." )
445 wxFileName relSheetPath( sheetFname );
446 relSheetPath.MakeRelativeTo( rootFname.GetPath() );
448 std::unique_ptr<SCH_SHEET> subSheet = std::make_unique<SCH_SHEET>( aSchematic );
449 subSheet->SetFileName( relSheetPath.GetFullPath() );
450 subSheet->SetName( prjSheet.name );
455 subSheet->SetScreen( screen );
459 pos.
y =
schIUScale.MilsToIU( 200 ) + ( subSheet->GetSize().y +
schIUScale.MilsToIU( 200 ) ) * subSheetIndex;
461 subSheet->SetPosition( pos );
473 catch( nlohmann::json::exception& e )
476 wxString::Format(
_(
"EasyEDA Pro v3 schematic page '%s' was skipped due to parse error: %s" ),
477 prjSheet.uuid, e.what() ) );
489 wxCHECK_MSG(
table,
nullptr,
"Could not load symbol lib table." );
491 if( !
table->HasRow( libName ) )
493 schPlugin->CreateLibrary( libFileName.GetFullPath() );
494 wxString libTableUri = wxS(
"${KIPRJMOD}/" ) + libFileName.GetFullName();
498 row.
SetURI( libTableUri );
502 symAdapter->
LoadOne( libName );
505 std::map<std::string, UTF8> properties;
508 std::set<wxString> symbolsSavedViaDevices;
511 for(
const auto& [devUuid, device] : prjDevices )
513 auto symbolAttr =
get_opt( device.attributes,
"Symbol" );
527 deviceSymInfo = parser.
ParseSymbol( *symbolDoc, device.attributes, blobs );
529 catch( nlohmann::json::exception& e )
531 wxLogWarning( wxString::Format(
_(
"EasyEDA Pro v3 device '%s' was skipped due to parse error: %s" ),
532 device.title, e.what() ) );
539 auto nameIt = deviceLibNames.find( devUuid );
540 wxString itemName = ( nameIt != deviceLibNames.end() ) ? nameIt->second : device.title;
546 if(
auto fpUuid =
get_opt( device.attributes,
"Footprint" ) )
548 if(
auto prjFp =
get_opt( prjFootprints, *fpUuid ) )
552 wxString description = device.description;
554 if( description.empty() )
555 description =
get_def( device.attributes, wxS(
"Description" ), wxEmptyString );
557 if( !description.empty() )
565 if( !keywords.empty() )
568 schPlugin->SaveSymbol( libFileName.GetFullPath(), deviceSymInfo.
libSymbol.release(), &properties );
569 symbolsSavedViaDevices.insert( *symbolAttr );
573 for(
auto& [symbolUuid, symInfo] : symbols )
575 if( !symInfo.libSymbol || symbolsSavedViaDevices.contains( symbolUuid ) )
581 symInfo.libSymbol->SetLibId( libID );
582 symInfo.libSymbol->SetName( itemName );
584 schPlugin->SaveSymbol( libFileName.GetFullPath(), symInfo.libSymbol.release(), &properties );
587 schPlugin->SaveLibrary( libFileName.GetFullPath() );
592 if(
v3.GetSkippedCount() > 0 )
594 wxLogWarning( wxString::Format(
_(
"EasyEDA (JLCEDA) Pro v3 import skipped %d unsupported object(s)." ),
595 v3.GetSkippedCount() ) );
constexpr EDA_IU_SCALE schIUScale
void SetPageNumber(const wxString &aPageNumber)
Parses EasyEDA Pro v3 .epro2 archives.
const V3_DOC_RAW * FindRawDoc(const wxString &aDocType, const wxString &aUuid) const
static bool IsV3Library(const wxString &aFileName, const wxString &aRequiredDocType=wxEmptyString)
Return true if aFileName looks like an EasyEDA Pro v3 library archive.
const nlohmann::json & GetLibraryIndex() const
static bool IsV3Archive(const wxString &aFileName)
Return true if aFileName looks like an EasyEDA Pro v3 archive.
RAII class to set and restore the fontconfig reporter.
const wxString & GetName() const
Return a brief hard coded name for this IO interface.
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetURI(const wxString &aUri)
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.
SCH_FIELD & GetFootprintField()
Return reference to the footprint field.
void SetDescription(const wxString &aDescription)
Gets the Description field text value */.
void SetKeyWords(const wxString &aKeyWords)
void SetLibId(const LIB_ID &aLibId)
virtual void SetName(const wxString &aName)
static LOAD_INFO_REPORTER & GetInstance()
CHOOSE_PROJECT_HANDLER m_choose_project_handler
Callback to choose projects to import.
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Holds all the data relating to one schematic.
void SetCurrentSheet(const SCH_SHEET_PATH &aPath)
int FixupJunctionsAfterImport()
Add junctions to this schematic where required.
PROJECT & Project() const
Return a reference to the project this schematic is part of.
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
void SetTopLevelSheets(const std::vector< SCH_SHEET * > &aSheets)
SCH_SHEET_PATH & CurrentSheet() const
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 EASYEDAPRO::V3_DOC_RAW &aDoc, const wxString &aLibName)
EASYEDAPRO::SYM_INFO ParseSymbol(const EASYEDAPRO::V3_DOC_RAW &aDoc, const std::map< wxString, wxString > &aDeviceAttributes, const std::map< wxString, EASYEDAPRO::BLOB > &aBlobMap={})
void SetText(const wxString &aText) override
bool CanReadLibrary(const wxString &aFileName) const override
Checks if this IO object can read the specified library file/directory.
long long m_cachedLibraryTimestamp
std::unique_ptr< EASYEDAPRO::V3_DOC_PARSER > m_cachedLibraryParser
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
const EASYEDAPRO::V3_DOC_PARSER & getCachedLibraryParser(const wxString &aLibraryPath) const
~SCH_IO_EASYEDAPRO_V3() override
wxString m_cachedLibraryPath
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 std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
SCH_IO(const wxString &aName)
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
const KIID & GetUuid() const
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.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
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.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
wxString get_def(const std::map< wxString, wxString > &aMap, const char *aKey, const char *aDefval="")
std::optional< V > get_opt(const std::map< wxString, V > &aMap, const wxString &aKey)
nlohmann::json BuildV3ProjectIndexFromRawDocs(const V3_DOC_PARSER &aParser, bool aIncludeLibraryMetadata=true)
Build a minimal legacy-style project index from parsed v3 raw documents.
LIB_ID ToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
wxString MakeUniqueLibName(std::set< wxString > &aUsedNames, const wxString &aName, const wxString &aFallback)
Allocate a unique library item name, recording it in aUsedNames.
wxString KeywordsFromV3Tags(const nlohmann::json &aTags)
Build KiCad keywords from a v3 tags object (parent_tag / child_tag name fields).
wxString GetV3LibraryItemTitle(const nlohmann::json &aMetadata, const wxString &aUuid)
wxString ResolveDeviceFieldVariables(const wxString &aInput, const std::map< wxString, wxString > &aDeviceAttributes)
Resolve EasyEDA ={Var} / ={A}text{B} field expressions against device attributes.
wxString NormalizeEasyEDAText(wxString aText)
Replace EasyEDA temperature glyph (℃) with °C.
std::vector< IMPORT_PROJECT_DESC > ProjectToSelectorDialog(const nlohmann::json &aProject, bool aPcbOnly=false, bool aSchOnly=false)
wxString ShortenLibName(wxString aProjectName)
std::map< wxString, V3_SYMBOL_LIB_ITEM > BuildV3SymbolLibraryMap(const V3_DOC_PARSER &aParser)
std::map< wxString, BLOB > BuildV3BlobMap(const V3_DOC_PARSER &aParser)
std::map< wxString, wxString > BuildV3DeviceLibNames(nlohmann::json &aProject, const std::map< wxString, PRJ_DEVICE > &aDevices, std::set< wxString > *aUsedNames=nullptr)
Stable project-lib item names keyed by Device UUID (one entry per Device).
static long long getFileTimestamp(const wxString &aFileName)
static LIB_SYMBOL * LoadV3LibrarySymbolItem(const EASYEDAPRO::V3_DOC_PARSER &aParser, const EASYEDAPRO::V3_SYMBOL_LIB_ITEM &aItem, const wxString &aLibName, const wxString &aSymbolName, const std::map< wxString, EASYEDAPRO::BLOB > &aBlobs, SCH_EASYEDAPRO_V3_PARSER &aSymbolParser)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
std::map< wxString, wxString > attributes
std::unique_ptr< LIB_SYMBOL > libSymbol
Raw parsed document from an EasyEDA Pro v3 .epru stream.
Build the schematic-library name map for a v3 .elibz2.
std::vector< std::vector< std::string > > table
VECTOR2< int32_t > VECTOR2I
Definition of file extensions used in Kicad.