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
187 std::vector<wxString> candidates;
190 if( !ownNick.IsEmpty() )
191 candidates.push_back( ownNick );
193 for(
const wxString& nick : aSourceLibNicknames )
195 if( nick != ownNick )
196 candidates.push_back( nick );
199 std::vector<wxString> matches;
201 for(
const wxString& nick : candidates )
214 if( !provenance.count( nick ) )
218 if( !def || !sameInterface( *candidate, *def ) )
222 matches.push_back( nick );
225 return matches.size() == 1 ? matches.front() : wxString( wxEmptyString );
228 std::vector<SCH_SYMBOL*> symbols = placedSymbols( aSchematic );
231 std::map<SOURCE_KEY, wxString> targetByKey;
232 std::set<SOURCE_KEY> cacheKeys;
233 std::map<SOURCE_KEY, std::vector<SCH_SYMBOL*>> instancesByKey;
237 wxString
name = symbol->GetLibId().GetUniStringLibItemName();
242 SOURCE_KEY key( symbol->GetLibId().GetUniStringLibNickname(),
name );
244 instancesByKey[key].push_back( symbol );
246 if( targetByKey.count( key ) )
249 wxString sourceNick = resolveSource( symbol,
name );
250 targetByKey[key] = sourceNick;
252 if( sourceNick.IsEmpty() )
253 cacheKeys.insert( key );
257 std::set<wxString> takenNames;
259 auto uniqueName = [&takenNames](
const wxString& aName )
261 wxString candidate = aName;
263 for(
int suffix = 1; !takenNames.insert( candidate ).second; ++suffix )
264 candidate = wxString::Format( wxS(
"%s_%d" ), aName, suffix );
270 std::map<wxString, LIB_SYMBOL*> cacheDefs;
271 std::map<SOURCE_KEY, wxString> cacheNameByKey;
272 std::map<const LIB_SYMBOL*, wxString> cacheNameByDef;
273 std::vector<std::unique_ptr<LIB_SYMBOL>> placedDefs;
274 std::vector<wxString> renameReports;
277 std::vector<std::pair<LIB_SYMBOL*, SOURCE_KEY>> parentFixups;
279 for(
const SOURCE_KEY& key : cacheKeys )
281 const wxString&
name = key.second;
286 const std::vector<SCH_SYMBOL*>& instances = instancesByKey[key];
288 if( instances.empty() || !instances.front()->GetLibSymbolRef() )
291 wxString firstSig = placedSignature( instances.front() );
293 for(
auto it = instances.begin() + 1; it != instances.end(); ++it )
295 if( placedSignature( *it ) != firstSig )
297 m_reporter.Report( wxString::Format(
_(
"Imported symbol '%s' has conflicting "
298 "placed definitions; keeping the "
305 placedDefs.push_back(
306 std::make_unique<LIB_SYMBOL>( *instances.front()->GetLibSymbolRef() ) );
307 def = placedDefs.back().get();
311 if(
auto it = cacheNameByDef.find( def ); it != cacheNameByDef.end() )
313 cacheNameByKey[key] = it->second;
317 wxString cacheName = uniqueName(
name );
319 cacheNameByDef[def] = cacheName;
320 cacheNameByKey[key] = cacheName;
321 cacheDefs[cacheName] = def;
324 parentFixups.emplace_back( def, SOURCE_KEY( key.first, def->
GetParentName() ) );
326 if( cacheName !=
name )
328 renameReports.push_back(
329 wxString::Format(
_(
"Imported symbol '%s' from '%s' was renamed to '%s' "
330 "because another library supplies a different symbol of "
331 "that name." ),
name, key.first, cacheName ) );
335 for(
const auto& [def, parentKey] : parentFixups )
337 if(
auto it = cacheNameByKey.find( parentKey ); it != cacheNameByKey.end() )
338 def->SetParentName( it->second );
341 if( !cacheDefs.empty() )
345 if( !
result.m_cacheNickname.IsEmpty() )
347 for(
const wxString& report : renameReports )
354 LIB_ID libId = symbol->GetLibId();
361 auto it = targetByKey.find( key );
363 if( it == targetByKey.end() )
370 if( it->second.IsEmpty() )
372 auto cacheName = cacheNameByKey.find( key );
374 if(
result.m_cacheNickname.IsEmpty() || cacheName == cacheNameByKey.end() )
382 symbol->SetLibId( libId );
388 symbol->SetLibId( libId );
389 result.m_linkedToSource++;
398 const wxString& aCacheNickname,
const std::map<wxString, LIB_SYMBOL*>& aCacheDefs,
402 wxString finalPath = finalFn.GetFullPath();
403 wxString tempPath = finalPath + wxS(
".tmp" );
408 if( existingRow && !isManagedCache( existingRow ) )
410 m_reporter.Report( wxString::Format(
_(
"A symbol library named '%s' is already "
411 "registered; leaving imported symbols "
412 "unresolved." ), aCacheNickname ),
421 m_reporter.Report(
_(
"Cannot reconcile imported symbols: no KiCad symbol writer." ),
427 auto safeDelete = [&pi](
const wxString& aPath )
431 pi->DeleteLibrary( aPath );
442 if( wxFileExists( tempPath ) )
443 pi->DeleteLibrary( tempPath );
445 pi->CreateLibrary( tempPath );
448 std::map<std::string, UTF8> properties;
451 for(
const auto& [
name, def] : aCacheDefs )
453 std::unique_ptr<LIB_SYMBOL>
copy = std::make_unique<LIB_SYMBOL>( *def );
460 id.SetLibNickname( aCacheNickname );
461 copy->SetLibId(
id );
462 pi->SaveSymbol( tempPath, std::move(
copy ), &properties );
465 pi->SaveLibrary( tempPath );
470 m_reporter.Report( wxString::Format(
_(
"Error writing imported symbol cache '%s': %s" ),
471 aCacheNickname, ioe.
What() ),
477 if( wxFileExists( tempPath ) )
478 safeDelete( tempPath );
484 if( wxFileExists( finalPath ) )
486 if( isManagedCache( existingRow ) )
488 safeDelete( finalPath );
492 m_reporter.Report( wxString::Format(
_(
"A library already exists at '%s'; leaving "
493 "imported symbols unresolved." ), finalPath ),
495 safeDelete( tempPath );
500 if( !wxRenameFile( tempPath, finalPath,
false ) )
502 m_reporter.Report( wxString::Format(
_(
"Could not publish imported symbol cache to "
503 "'%s'." ), finalPath ),
505 safeDelete( tempPath );