27#include <wx/filename.h>
49 const wxString& aProjectPath,
61std::vector<SCH_SYMBOL*> placedSymbols(
SCHEMATIC* aSchematic )
63 std::vector<SCH_SYMBOL*> symbols;
66 for(
SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
69 symbols.push_back(
static_cast<SCH_SYMBOL*
>( item ) );
77wxString placedSignature(
const SCH_SYMBOL* aSymbol )
84 return wxString::Format( wxS(
"%d:%d" ), part->GetPinCount(), part->GetUnitCount() );
90 const wxString& aName )
94 return aAdapter.
LoadSymbol( aNickname, aName );
103std::multiset<wxString> pinNumbers(
const LIB_SYMBOL& aSymbol )
105 std::multiset<wxString> numbers;
108 numbers.insert(
pin->GetNumber() );
131 std::vector<std::unique_ptr<LIB_SYMBOL>> aDefinitions,
132 const wxString& aCacheNickname,
133 const std::vector<wxString>& aSourceLibNicknames )
141 using SOURCE_KEY = std::pair<wxString, wxString>;
143 std::map<SOURCE_KEY, LIB_SYMBOL*> defByKey;
144 std::map<wxString, std::vector<LIB_SYMBOL*>> defsByName;
146 for(
const std::unique_ptr<LIB_SYMBOL>& def : aDefinitions )
148 wxString
name = def->GetLibId().GetUniStringLibItemName();
151 name = def->GetName();
156 defByKey.emplace( SOURCE_KEY( def->GetLibId().GetUniStringLibNickname(),
name ), def.get() );
157 defsByName[
name].push_back( def.get() );
162 auto findDef = [&](
const wxString& aNick,
const wxString& aName ) ->
LIB_SYMBOL*
164 if(
auto it = defByKey.find( SOURCE_KEY( aNick, aName ) ); it != defByKey.end() )
167 auto byName = defsByName.find( aName );
169 if( byName == defsByName.end() || byName->second.size() != 1 )
172 return byName->second.front();
176 for(
const wxString& nick : aSourceLibNicknames )
182 std::set<wxString> provenance( aSourceLibNicknames.begin(), aSourceLibNicknames.end() );
185 auto resolveSource = [&](
const SCH_SYMBOL* aSymbol,
const wxString& aName ) -> wxString
190 if( !ownNick.IsEmpty() )
193 for(
const wxString& nick : aSourceLibNicknames )
195 if( nick != ownNick )
199 std::vector<wxString> matches;
214 if( !provenance.count( nick ) )
222 if( !def || !sameInterface( *candidate, *def ) )
226 matches.push_back( nick );
229 return matches.size() == 1 ? matches.front() : wxString( wxEmptyString );
232 std::vector<SCH_SYMBOL*> symbols = placedSymbols( aSchematic );
235 std::map<SOURCE_KEY, wxString> targetByKey;
236 std::set<SOURCE_KEY> cacheKeys;
237 std::map<SOURCE_KEY, std::vector<SCH_SYMBOL*>> instancesByKey;
241 wxString
name = symbol->GetLibId().GetUniStringLibItemName();
246 SOURCE_KEY key( symbol->GetLibId().GetUniStringLibNickname(),
name );
248 instancesByKey[key].push_back( symbol );
250 if( targetByKey.count( key ) )
253 wxString sourceNick = resolveSource( symbol,
name );
254 targetByKey[key] = sourceNick;
256 if( sourceNick.IsEmpty() )
257 cacheKeys.insert( key );
261 std::set<wxString> takenNames;
263 auto uniqueName = [&takenNames](
const wxString& aName )
267 wxString candidate = legalName;
269 for(
int suffix = 1; !takenNames.insert( candidate ).second; ++suffix )
270 candidate = wxString::Format( wxS(
"%s_%d" ), legalName, suffix );
276 std::map<wxString, LIB_SYMBOL*> cacheDefs;
277 std::map<SOURCE_KEY, wxString> cacheNameByKey;
278 std::map<const LIB_SYMBOL*, wxString> cacheNameByDef;
279 std::vector<std::unique_ptr<LIB_SYMBOL>> placedDefs;
280 std::vector<wxString> renameReports;
283 std::vector<std::pair<LIB_SYMBOL*, SOURCE_KEY>> parentFixups;
285 for(
const SOURCE_KEY& key : cacheKeys )
287 const wxString&
name = key.second;
292 const std::vector<SCH_SYMBOL*>& instances = instancesByKey[key];
294 if( instances.empty() || !instances.front()->GetLibSymbolRef() )
297 wxString firstSig = placedSignature( instances.front() );
299 for(
auto it = instances.begin() + 1; it != instances.end(); ++it )
301 if( placedSignature( *it ) != firstSig )
303 m_reporter.Report( wxString::Format(
_(
"Imported symbol '%s' has conflicting "
304 "placed definitions; keeping the "
311 placedDefs.push_back(
312 std::make_unique<LIB_SYMBOL>( *instances.front()->GetLibSymbolRef() ) );
313 def = placedDefs.back().get();
317 if(
auto it = cacheNameByDef.find( def ); it != cacheNameByDef.end() )
319 cacheNameByKey[key] = it->second;
323 wxString cacheName = uniqueName(
name );
325 cacheNameByDef[def] = cacheName;
326 cacheNameByKey[key] = cacheName;
327 cacheDefs[cacheName] = def;
330 parentFixups.emplace_back( def, SOURCE_KEY( key.first, def->
GetParentName() ) );
332 if( cacheName !=
name )
334 renameReports.push_back(
335 wxString::Format(
_(
"Imported symbol '%s' from '%s' was renamed to '%s' "
336 "in the import cache." ),
name, key.first, cacheName ) );
340 for(
const auto& [def, parentKey] : parentFixups )
342 if(
auto it = cacheNameByKey.find( parentKey ); it != cacheNameByKey.end() )
343 def->SetParentName( it->second );
346 if( !cacheDefs.empty() )
350 if( !
result.m_cacheNickname.IsEmpty() )
352 for(
const wxString& report : renameReports )
372 screen->
Append( aSymbol );
378 LIB_ID libId = symbol->GetLibId();
385 auto it = targetByKey.find( key );
387 if( it == targetByKey.end() )
394 if( it->second.IsEmpty() )
396 auto cacheName = cacheNameByKey.find( key );
398 if(
result.m_cacheNickname.IsEmpty() || cacheName == cacheNameByKey.end() )
406 setLibId( symbol, libId );
412 setLibId( symbol, libId );
413 result.m_linkedToSource++;
422 const wxString& aCacheNickname,
const std::map<wxString, LIB_SYMBOL*>& aCacheDefs,
426 wxString finalPath = finalFn.GetFullPath();
427 wxString tempPath = finalPath + wxS(
".tmp" );
432 if( existingRow && !isManagedCache( existingRow ) )
434 m_reporter.Report( wxString::Format(
_(
"A symbol library named '%s' is already "
435 "registered; leaving imported symbols "
436 "unresolved." ), aCacheNickname ),
445 m_reporter.Report(
_(
"Cannot reconcile imported symbols: no KiCad symbol writer." ),
451 auto safeDelete = [&pi](
const wxString& aPath )
455 pi->DeleteLibrary( aPath );
466 if( wxFileExists( tempPath ) )
467 pi->DeleteLibrary( tempPath );
469 pi->CreateLibrary( tempPath );
472 std::map<std::string, UTF8> properties;
475 for(
const auto& [
name, def] : aCacheDefs )
477 std::unique_ptr<LIB_SYMBOL>
copy = std::make_unique<LIB_SYMBOL>( *def );
484 id.SetLibNickname( aCacheNickname );
485 copy->SetLibId(
id );
486 pi->SaveSymbol( tempPath, std::move(
copy ), &properties );
489 pi->SaveLibrary( tempPath );
494 m_reporter.Report( wxString::Format(
_(
"Error writing imported symbol cache '%s': %s" ),
495 aCacheNickname, ioe.
What() ),
501 if( wxFileExists( tempPath ) )
502 safeDelete( tempPath );
508 if( wxFileExists( finalPath ) )
510 if( isManagedCache( existingRow ) )
512 safeDelete( finalPath );
516 m_reporter.Report( wxString::Format(
_(
"A library already exists at '%s'; leaving "
517 "imported symbols unresolved." ), finalPath ),
519 safeDelete( tempPath );
524 if( !wxRenameFile( tempPath, finalPath,
false ) )
526 m_reporter.Report( wxString::Format(
_(
"Could not publish imported symbol cache to "
527 "'%s'." ), finalPath ),
529 safeDelete( tempPath );
544 std::optional<LIBRARY_TABLE*> tableOpt =
m_adapter.ProjectTable();
546 if( !tableOpt || !*tableOpt )
548 m_reporter.Report(
_(
"Cannot register imported symbol cache: no project library "
554 wxString cacheFile = aCacheNickname + wxS(
"." )
556 wxString uri = wxS(
"${KIPRJMOD}/" ) + cacheFile;
558 ?
table->Row( aCacheNickname ).value_or(
nullptr )
559 : &
table->InsertRow();
566 row->
SetType( wxS(
"KiCad" ) );
573 m_reporter.Report(
_(
"Error saving project symbol library table; imported symbols left "
586 const wxString& aSchematicPath,
587 const std::map<std::string, UTF8>* aProperties,
REPORTER& aReporter )
590 std::vector<std::unique_ptr<LIB_SYMBOL>> definitions;
595 definitions.emplace_back( symbol );
609 std::vector<wxString> sourceLibs;
612 if( cacheNick.IsEmpty() )
615 wxFileName( aSchematicPath ).GetName() );
623 result = reconciler.
Reconcile( &aSchematic, std::move( definitions ), cacheNick,
628 aReporter.
Report( wxString::Format(
_(
"Could not reconcile imported symbol libraries: "
EDA_ITEM * GetParent() const
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
void SetOptions(const wxString &aOptions)
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
std::map< std::string, UTF8 > GetOptionsMap() const
void SetURI(const wxString &aUri)
void SetScope(LIBRARY_TABLE_SCOPE aScope)
A logical library item identifier and consists of various portions much like a URI.
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
const wxString GetUniStringLibNickname() const
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Define a library symbol object.
const wxString & GetParentName() const
int GetUnitCount() const override
void SetLibId(const LIB_ID &aLibId)
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const override
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
virtual void SetName(const wxString &aName)
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
virtual const wxString GetProjectPath() const
Return the full path of the project.
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Holds all the data relating to one schematic.
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.
virtual std::vector< LIB_SYMBOL * > GetImportedCachedLibrarySymbols()
Return the canonical symbol definitions produced by the last LoadSchematicFile().
Base class for any item which can be embedded within the SCHEMATIC container class,...
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
void SetLibId(const LIB_ID &aName)
bool UseLibIdLookup() const
const LIB_ID & GetLibId() const override
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Frame-independent, non-interactive service that reconciles the symbol-library references of a freshly...
bool registerCacheRow(const wxString &aCacheNickname)
Insert or refresh the project symbol-library-table row for the generated cache.
SYMBOL_IMPORT_RECONCILER(SYMBOL_LIBRARY_ADAPTER &aAdapter, const wxString &aProjectPath, REPORTER &aReporter=NULL_REPORTER::GetInstance())
SYMBOL_IMPORT_RECONCILE_RESULT Reconcile(SCHEMATIC *aSchematic, std::vector< std::unique_ptr< LIB_SYMBOL > > aDefinitions, const wxString &aCacheNickname, const std::vector< wxString > &aSourceLibNicknames)
Reconcile aSchematic against the importer definitions and the provenance source libraries.
SYMBOL_LIBRARY_ADAPTER & m_adapter
void writeAndRegisterCache(const wxString &aCacheNickname, const std::map< wxString, LIB_SYMBOL * > &aCacheDefs, SYMBOL_IMPORT_RECONCILE_RESULT &aResult)
Write the residual definitions into an atomically-published .kicad_sym and register its row.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
static const std::string KiCadSymbolLibFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
void ReadSymbolProps(const std::map< std::string, UTF8 > *aProps, wxString &aCacheNickname, std::vector< wxString > &aSourceSymLibs)
Read the symbol-import coordination properties out of a properties map.
wxString ManagedCacheOption()
Options string identifying a library-table row as a generated import cache.
constexpr char MANAGED_CACHE_KEY[]
Library-table row option key marking a row as a generated import cache.
wxString MakeSymbolCacheNickname(const wxString &aStem)
Derive the generated symbol-cache nickname from a project or file stem.
LIB_SYMBOL * loadSymbol(const wxString &aLibraryPath, nlohmann::json aFileData, const wxString &aAliasName, const std::map< std::string, UTF8 > *aProperties)
Outcome of a post-import symbol-library reconciliation pass.
wxString m_cacheNickname
nickname of the generated cache, empty if none written
int m_savedToCache
distinct definitions written into the cache library
SYMBOL_IMPORT_RECONCILE_RESULT ReconcileImportedSymbols(SCH_IO &aPlugin, SCHEMATIC &aSchematic, PROJECT &aProject, const wxString &aSchematicPath, const std::map< std::string, UTF8 > *aProperties, REPORTER &aReporter)
Reconcile aSchematic against the definitions aPlugin retained while loading it.
static std::vector< int > candidates(const SEGMENT_INDEX &aIndex, const SEG &aQuery, int aPadding)
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.