26#include <wx/filename.h>
48 const wxString& aProjectPath,
60std::vector<SCH_SYMBOL*> placedSymbols(
SCHEMATIC* aSchematic )
62 std::vector<SCH_SYMBOL*> symbols;
65 for(
SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
68 symbols.push_back(
static_cast<SCH_SYMBOL*
>( item ) );
76wxString placedSignature(
const SCH_SYMBOL* aSymbol )
83 return wxString::Format( wxS(
"%d:%d" ), part->GetPinCount(), part->GetUnitCount() );
89 const wxString& aName )
93 return aAdapter.
LoadSymbol( aNickname, aName );
102std::multiset<wxString> pinNumbers(
const LIB_SYMBOL& aSymbol )
104 std::multiset<wxString> numbers;
107 numbers.insert(
pin->GetNumber() );
130 std::vector<std::unique_ptr<LIB_SYMBOL>> aDefinitions,
131 const wxString& aCacheNickname,
132 const std::vector<wxString>& aSourceLibNicknames )
139 std::map<wxString, LIB_SYMBOL*> defByName;
141 for(
const std::unique_ptr<LIB_SYMBOL>& def : aDefinitions )
143 wxString
name = def->GetLibId().GetUniStringLibItemName();
146 name = def->GetName();
148 if( !
name.IsEmpty() )
149 defByName.emplace(
name, def.get() );
153 for(
const wxString& nick : aSourceLibNicknames )
159 std::set<wxString> provenance( aSourceLibNicknames.begin(), aSourceLibNicknames.end() );
162 auto resolveSource = [&](
const SCH_SYMBOL* aSymbol,
const wxString& aName ) -> wxString
164 std::vector<wxString> candidates;
167 if( !ownNick.IsEmpty() )
168 candidates.push_back( ownNick );
170 for(
const wxString& nick : aSourceLibNicknames )
172 if( nick != ownNick )
173 candidates.push_back( nick );
176 std::vector<wxString> matches;
178 for(
const wxString& nick : candidates )
191 if( !provenance.count( nick ) )
193 auto def = defByName.find( aName );
195 if( def == defByName.end() || !sameInterface( *candidate, *def->second ) )
199 matches.push_back( nick );
202 return matches.size() == 1 ? matches.front() : wxString( wxEmptyString );
205 std::vector<SCH_SYMBOL*> symbols = placedSymbols( aSchematic );
209 std::map<wxString, wxString> targetByKey;
210 std::set<wxString> cacheNames;
211 std::map<wxString, std::vector<SCH_SYMBOL*>> instancesByName;
213 auto keyOf = [](
const wxString& aNick,
const wxString& aName )
215 return aNick + wxS(
"\x1f" ) + aName;
220 wxString
name = symbol->GetLibId().GetUniStringLibItemName();
225 instancesByName[
name].push_back( symbol );
227 wxString key = keyOf( symbol->GetLibId().GetUniStringLibNickname(),
name );
229 if( targetByKey.count( key ) )
232 wxString sourceNick = resolveSource( symbol,
name );
233 targetByKey[key] = sourceNick;
235 if( sourceNick.IsEmpty() )
236 cacheNames.insert(
name );
240 std::map<wxString, LIB_SYMBOL*> cacheDefs;
241 std::vector<std::unique_ptr<LIB_SYMBOL>> placedDefs;
243 for(
const wxString&
name : cacheNames )
245 if(
auto it = defByName.find(
name ); it != defByName.end() )
247 cacheDefs[
name] = it->second;
251 const std::vector<SCH_SYMBOL*>& instances = instancesByName[
name];
253 if( instances.empty() || !instances.front()->GetLibSymbolRef() )
256 wxString firstSig = placedSignature( instances.front() );
258 for(
auto it = instances.begin() + 1; it != instances.end(); ++it )
260 if( placedSignature( *it ) != firstSig )
262 m_reporter.Report( wxString::Format(
_(
"Imported symbol '%s' has conflicting "
263 "placed definitions; keeping the first." ),
270 placedDefs.push_back(
271 std::make_unique<LIB_SYMBOL>( *instances.front()->GetLibSymbolRef() ) );
272 cacheDefs[
name] = placedDefs.back().get();
275 if( !cacheDefs.empty() )
281 LIB_ID libId = symbol->GetLibId();
289 if( it == targetByKey.end() )
296 if( it->second.IsEmpty() )
298 if(
result.m_cacheNickname.IsEmpty() )
305 symbol->SetLibId( libId );
311 symbol->SetLibId( libId );
312 result.m_linkedToSource++;
321 const wxString& aCacheNickname,
const std::map<wxString, LIB_SYMBOL*>& aCacheDefs,
325 wxString finalPath = finalFn.GetFullPath();
326 wxString tempPath = finalPath + wxS(
".tmp" );
331 if( existingRow && !isManagedCache( existingRow ) )
333 m_reporter.Report( wxString::Format(
_(
"A symbol library named '%s' is already "
334 "registered; leaving imported symbols "
335 "unresolved." ), aCacheNickname ),
344 m_reporter.Report(
_(
"Cannot reconcile imported symbols: no KiCad symbol writer." ),
350 auto safeDelete = [&pi](
const wxString& aPath )
354 pi->DeleteLibrary( aPath );
365 if( wxFileExists( tempPath ) )
366 pi->DeleteLibrary( tempPath );
368 pi->CreateLibrary( tempPath );
371 std::map<std::string, UTF8> properties;
374 for(
const auto& [
name, def] : aCacheDefs )
376 std::unique_ptr<LIB_SYMBOL>
copy = std::make_unique<LIB_SYMBOL>( *def );
379 id.SetLibNickname( aCacheNickname );
380 copy->SetLibId(
id );
381 pi->SaveSymbol( tempPath,
copy.release(), &properties );
384 pi->SaveLibrary( tempPath );
389 m_reporter.Report( wxString::Format(
_(
"Error writing imported symbol cache '%s': %s" ),
390 aCacheNickname, ioe.
What() ),
396 if( wxFileExists( tempPath ) )
397 safeDelete( tempPath );
403 if( wxFileExists( finalPath ) )
405 if( isManagedCache( existingRow ) )
407 safeDelete( finalPath );
411 m_reporter.Report( wxString::Format(
_(
"A library already exists at '%s'; leaving "
412 "imported symbols unresolved." ), finalPath ),
414 safeDelete( tempPath );
419 if( !wxRenameFile( tempPath, finalPath,
false ) )
421 m_reporter.Report( wxString::Format(
_(
"Could not publish imported symbol cache to "
422 "'%s'." ), finalPath ),
424 safeDelete( tempPath );
439 std::optional<LIBRARY_TABLE*> tableOpt =
m_adapter.ProjectTable();
441 if( !tableOpt || !*tableOpt )
443 m_reporter.Report(
_(
"Cannot register imported symbol cache: no project library "
449 wxString cacheFile = aCacheNickname + wxS(
"." )
451 wxString uri = wxS(
"${KIPRJMOD}/" ) + cacheFile;
453 ?
table->Row( aCacheNickname ).value_or(
nullptr )
454 : &
table->InsertRow();
461 row->
SetType( wxS(
"KiCad" ) );
468 m_reporter.Report(
_(
"Error saving project symbol library table; imported symbols left "
481 const wxString& aSchematicPath,
482 const std::map<std::string, UTF8>* aProperties,
REPORTER& aReporter )
485 std::vector<std::unique_ptr<LIB_SYMBOL>> definitions;
490 definitions.emplace_back( symbol );
500 if( definitions.empty() )
510 std::vector<wxString> sourceLibs;
513 if( cacheNick.IsEmpty() )
516 wxFileName( aSchematicPath ).GetName() );
524 result = reconciler.
Reconcile( &aSchematic, std::move( definitions ), cacheNick,
529 aReporter.
Report( wxString::Format(
_(
"Could not reconcile imported symbol libraries: "
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 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
Define a library symbol object.
std::vector< SCH_PIN * > GetPins() const override
int GetUnitCount() const override
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.
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.
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.