58 m_commit( aFrame->GetToolManager() ),
85 const wxString previous = net->GetNetChain();
88 if( !previous.IsEmpty() &&
next.IsEmpty() && aReporter && !aDryRun )
92 _(
"Net chain assignment '%s' on net '%s' cleared by netlist "
94 previous, net->GetNetname() ),
100 net->SetNetChain(
next );
102 if( previous !=
next )
104 for(
int i = 0; i < 2; ++i )
105 net->ClearTerminalPad( i );
165 bestPosition.
x = pageSize.
x / 2;
166 bestPosition.
y = pageSize.
y / 2;
183 if( aFootprintId.
empty() )
185 msg.Printf(
_(
"Cannot add %s (no footprint assigned)." ),
194 if( footprint ==
nullptr )
196 msg.Printf(
_(
"Cannot add %s (footprint '%s' not found)." ),
205 m_board->GetComponentClassManager().GetNoneComponentClass() );
209 msg.Printf(
_(
"Add %s (footprint '%s')." ),
220 bool showRatsnest =
true;
223 showRatsnest =
m_settings->m_Display.m_ShowGlobalRatsnest;
225 pad->SetLocalRatsnestVisible( showRatsnest );
228 pad->SetNetCode( 0 );
243 msg.Printf(
_(
"Added %s (footprint '%s')." ),
256 wxString curClassName, newClassName;
260 curClassName = curClass->
GetName();
270 newClass =
m_board->GetComponentClassManager().GetEffectiveStaticComponentClass(
272 newClassName = newClass->
GetName();
275 if( curClassName == newClassName )
284 copy->SetParentGroup(
nullptr );
291 if( curClassName == wxEmptyString && newClassName != wxEmptyString )
293 msg.Printf(
_(
"Change %s component class to '%s'." ),
297 else if( curClassName != wxEmptyString && newClassName == wxEmptyString )
299 msg.Printf(
_(
"Remove %s component class (currently '%s')." ),
305 msg.Printf(
_(
"Change %s component class from '%s' to '%s'." ),
313 wxASSERT_MSG( newClass !=
nullptr,
"Component class should not be nullptr" );
317 if( curClassName == wxEmptyString && newClassName != wxEmptyString )
319 msg.Printf(
_(
"Changed %s component class to '%s'." ),
323 else if( curClassName != wxEmptyString && newClassName == wxEmptyString )
325 msg.Printf(
_(
"Removed %s component class (was '%s')." ),
331 msg.Printf(
_(
"Changed %s component class from '%s' to '%s'." ),
354 msg.Printf(
_(
"Cannot update %s (no footprint assigned)." ),
363 if( newFootprint ==
nullptr )
365 msg.Printf(
_(
"Cannot update %s (footprint '%s' not found)." ),
377 msg.Printf(
_(
"Cannot change %s footprint from '%s' to '%s' (footprint is locked)."),
388 msg.Printf(
_(
"Change %s footprint from '%s' to '%s'."),
402 msg.Printf(
_(
"Could not change %s footprint from '%s' to '%s' (footprint is locked)."),
416 m_board->ExchangeFootprint( aFootprint, newFootprint,
m_commit,
true );
418 msg.Printf(
_(
"Changed %s footprint from '%s' to '%s'."),
443 firstAssociatedVariant = &
test;
452 if( !
m_commit.GetStatus( aFootprint ) )
455 copy->SetParentGroup(
nullptr );
458 bool changed =
false;
465 msg.Printf(
_(
"Change %s reference designator to %s." ),
471 msg.Printf(
_(
"Changed %s reference designator to %s." ),
483 wxString netlistValue = aNetlistComponent->
GetValue();
485 if( firstAssociatedVariant !=
nullptr
491 if( aFootprint->
GetValue() != netlistValue )
495 msg.Printf(
_(
"Change %s value from %s to %s." ),
502 msg.Printf(
_(
"Changed %s value from %s to %s." ),
508 aFootprint->
SetValue( netlistValue );
517 if( !aNetlistComponent->
GetKIIDs().empty() )
518 new_path.push_back( aNetlistComponent->
GetKIIDs().front() );
520 if( aFootprint->
GetPath() != new_path )
524 msg.Printf(
_(
"Update %s symbol association from %s to %s." ),
531 msg.Printf(
_(
"Updated %s symbol association from %s to %s." ),
537 aFootprint->
SetPath( new_path );
543 nlohmann::ordered_map<wxString, wxString> fpFieldsAsMap;
548 if( field->IsReference() || field->IsValue() || field->IsComponentClass() )
553 fpFieldsAsMap[field->GetName()] = field->GetText();
557 nlohmann::ordered_map<wxString, wxString> compFields = aNetlistComponent->
GetFields();
563 compFields.erase( wxT(
"Component Class" ) );
565 if( firstAssociatedVariant !=
nullptr )
567 for(
const auto& [
name, value] : firstAssociatedVariant->
m_fields )
568 compFields[
name] = value;
574 bool remove_only =
true;
576 for(
const auto& [
name, value] : compFields )
578 if( fpFieldsAsMap.count(
name ) == 0 || fpFieldsAsMap[
name] != value )
586 for(
const auto& [
name, value] : fpFieldsAsMap )
588 if( compFields.count(
name ) == 0 )
601 msg.Printf(
_(
"Update %s fields." ), aFootprint->
GetReference() );
608 if( field->IsMandatory() )
611 if( compFields.count( field->GetName() ) == 0 )
615 msg.Printf(
_(
"Remove %s footprint fields not in symbol." ), aFootprint->
GetReference() );
627 msg.Printf(
_(
"Updated %s fields." ), aFootprint->
GetReference() );
633 for(
auto& [
name, value] : compFields )
642 aFootprint->
Add( newField );
663 std::vector<PCB_FIELD*> fieldList;
664 aFootprint->
GetFields( fieldList,
false );
668 if( field->IsMandatory() )
671 if( compFields.count( field->GetName() ) == 0 )
676 msg.Printf(
_(
"Removed %s footprint fields not in symbol." ), aFootprint->
GetReference() );
680 aFootprint->
Remove( field );
683 m_frame->GetCanvas()->GetView()->Remove( field );
698 if( !humanSheetPath.empty() )
699 sheetname = humanSheetPath;
700 else if( aNetlistComponent->
GetProperties().count( wxT(
"Sheetname" ) ) > 0 )
701 sheetname = aNetlistComponent->
GetProperties().at( wxT(
"Sheetname" ) );
703 if( aNetlistComponent->
GetProperties().count( wxT(
"Sheetfile" ) ) > 0 )
704 sheetfile = aNetlistComponent->
GetProperties().at( wxT(
"Sheetfile" ) );
706 if( aNetlistComponent->
GetProperties().count( wxT(
"ki_fp_filters" ) ) > 0 )
707 fpFilters = aNetlistComponent->
GetProperties().at( wxT(
"ki_fp_filters" ) );
713 msg.Printf(
_(
"Update %s sheetname to '%s'." ),
720 msg.Printf(
_(
"Updated %s sheetname to '%s'." ),
732 msg.Printf(
_(
"Update %s sheetfile to '%s'." ),
739 msg.Printf(
_(
"Updated %s sheetfile to '%s'." ),
751 msg.Printf(
_(
"Update %s footprint filters to '%s'." ),
758 msg.Printf(
_(
"Updated %s footprint filters to '%s'." ),
766 bool netlistExcludeFromBOM = aNetlistComponent->
GetProperties().count( wxT(
"exclude_from_bom" ) ) > 0;
775 if( netlistExcludeFromBOM )
776 msg.Printf(
_(
"Add %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
778 msg.Printf(
_(
"Remove %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
784 if( netlistExcludeFromBOM )
787 msg.Printf(
_(
"Added %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
792 msg.Printf(
_(
"Removed %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
802 bool netlistDNP = aNetlistComponent->
GetProperties().count( wxT(
"dnp" ) ) > 0;
804 if( firstAssociatedVariant !=
nullptr && firstAssociatedVariant->
m_hasDnp )
805 netlistDNP = firstAssociatedVariant->
m_dnp;
812 msg.Printf(
_(
"Add %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
814 msg.Printf(
_(
"Remove %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
823 msg.Printf(
_(
"Added %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
828 msg.Printf(
_(
"Removed %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
838 bool netlistExcludeFromPosFiles = aNetlistComponent->
GetProperties().count( wxT(
"exclude_from_pos_files" ) ) > 0;
848 if( netlistExcludeFromPosFiles )
850 msg.Printf(
_(
"Add %s 'exclude from position files' fabrication attribute." ),
855 msg.Printf(
_(
"Remove %s 'exclude from position files' fabrication attribute." ),
863 if( netlistExcludeFromPosFiles )
866 msg.Printf(
_(
"Added %s 'exclude from position files' fabrication attribute." ),
872 msg.Printf(
_(
"Removed %s 'exclude from position files' fabrication attribute." ),
895 msg.Printf(
_(
"Added %s 'duplicate pad numbers are jumpers' attribute." ),
900 msg.Printf(
_(
"Removed %s 'duplicate pad numbers are jumpers' attribute." ),
908 msg.Printf(
_(
"Add %s 'duplicate pad numbers are jumpers' attribute." ),
913 msg.Printf(
_(
"Remove %s 'duplicate pad numbers are jumpers' attribute." ),
927 msg.Printf(
_(
"Updated %s jumper pad groups" ), aFootprint->
GetReference() );
931 msg.Printf(
_(
"Update %s jumper pad groups" ), aFootprint->
GetReference() );
937 if( changed &&
copy )
957 if( !
m_commit.GetStatus( aPcbFootprint ) )
960 copy->SetParentGroup(
nullptr );
963 bool changed =
false;
972 KIID existingGroupKIID = existingGroup ? existingGroup->
m_Uuid : 0;
975 auto it = std::find_if(
m_board->Groups().begin(),
m_board->Groups().end(),
977 return group->m_Uuid == newGroupKIID;
981 if( it !=
m_board->Groups().end() )
985 if( newGroupKIID == existingGroupKIID )
989 if( existingGroupKIID != 0 )
993 msg.Printf(
_(
"Remove %s from group '%s'." ),
999 msg.Printf(
_(
"Removed %s from group '%s'." ),
1007 if( existingGroup->
GetItems().size() < 2 )
1018 if( newGroupKIID != 0 )
1022 msg.Printf(
_(
"Add %s to group '%s'." ),
1028 msg.Printf(
_(
"Added %s to group '%s'." ),
1034 if( newGroup ==
nullptr )
1037 newGroup->
SetUuid( newGroupKIID );
1051 newGroup->
AddItem( aPcbFootprint );
1057 if( changed &&
copy )
1077 copy->SetParentGroup(
nullptr );
1080 bool changed =
false;
1083 std::deque<PAD*> pads = aFootprint->
Pads();
1084 std::set<wxString> padNetnames;
1086 std::sort( pads.begin(), pads.end(),
1089 return a->m_Uuid < b->m_Uuid;
1096 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1097 wxT(
"Processing pad %s of component %s" ),
1101 wxString pinFunction;
1106 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1107 wxT(
" Found valid net: %s" ),
1114 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1115 wxT(
" No net found for pad %s" ),
1121 if(
pad->GetPinFunction() != pinFunction )
1124 pad->SetPinFunction( pinFunction );
1127 if(
pad->GetPinType() != pinType )
1130 pad->SetPinType( pinType );
1139 if( !net.
IsValid() || !
pad->IsOnCopperLayer() )
1141 if( !
pad->GetNetname().IsEmpty() )
1145 msg.Printf(
_(
"Disconnect %s pin %s." ),
1151 msg.Printf(
_(
"Disconnected %s pin %s." ),
1158 else if(
pad->IsOnCopperLayer() && !
pad->GetNumber().IsEmpty() )
1161 msg.Printf(
_(
"No net found for component %s pad %s (no pin %s in symbol)." ),
1176 if(
pad->GetNetname().IsEmpty() )
1177 pad->SetPinFunction( wxEmptyString );
1189 if(
pad->IsNoConnectPad() )
1191 netName = wxString::Format( wxS(
"%s" ), net.
GetNetName() );
1193 for(
int jj = 1; !padNetnames.insert( netName ).second
1197 netName = wxString::Format( wxS(
"%s_%d" ), net.
GetNetName(), jj );
1206 if(
pad->GetNetname() != netName )
1209 if( netinfo ==
nullptr )
1216 if( netinfo ==
nullptr )
1228 msg.Printf(
_(
"Add net %s." ),
1233 if( !
pad->GetNetname().IsEmpty() )
1239 msg.Printf(
_(
"Reconnect %s pin %s from %s to %s."),
1247 msg.Printf(
_(
"Reconnected %s pin %s from %s to %s."),
1258 msg.Printf(
_(
"Connect %s pin %s to %s."),
1265 msg.Printf(
_(
"Connected %s pin %s to %s."),
1277 pad->SetNet( netinfo );
1287 if( changed &&
copy )
1299 std::vector<FOOTPRINT::FP_UNIT_INFO> newUnits;
1302 newUnits.push_back( { u.m_unitName, u.m_pins } );
1304 const std::vector<FOOTPRINT::FP_UNIT_INFO>& curUnits = aFootprint->
GetUnitInfo();
1306 auto unitsEqual = [](
const std::vector<FOOTPRINT::FP_UNIT_INFO>& a,
1307 const std::vector<FOOTPRINT::FP_UNIT_INFO>& b )
1309 if( a.size() != b.size() )
1312 for(
size_t i = 0; i < a.size(); ++i )
1314 if( a[i].m_unitName != b[i].m_unitName )
1317 if( a[i].m_pins != b[i].m_pins )
1324 if( unitsEqual( curUnits, newUnits ) )
1331 msg.Printf(
_(
"Update %s unit metadata." ), aFootprint->
GetReference() );
1339 if( !
m_commit.GetStatus( aFootprint ) )
1342 copy->SetParentGroup(
nullptr );
1347 msg.Printf(
_(
"Updated %s unit metadata." ), aFootprint->
GetReference() );
1362 return aBoardFpid == aSchematicFpid;
1367 const std::vector<FOOTPRINT*>& aFootprints,
1368 const LIB_ID& aBaseFpid )
1373 if( aBaseFpid.
empty() )
1385 std::vector<VARIANT_INFO> variantInfo;
1386 variantInfo.reserve( variants.size() );
1388 for(
const auto& [variantName, variant] : variants )
1390 LIB_ID variantFPID = aBaseFpid;
1392 auto fieldIt = variant.m_fields.find( footprintFieldName );
1394 if( fieldIt != variant.m_fields.end() && !fieldIt->second.IsEmpty() )
1398 if( parsedId.
Parse( fieldIt->second,
true ) >= 0 )
1400 msg.Printf(
_(
"Invalid footprint ID '%s' for variant '%s' on %s." ),
1409 variantFPID = parsedId;
1413 variantInfo.push_back( { variantName, &variant, variantFPID } );
1416 for(
FOOTPRINT* footprint : aFootprints )
1426 copy->SetParentGroup(
nullptr );
1429 bool changed =
false;
1431 auto printAttributeMessage =
1432 [&](
bool add,
const wxString& attrName,
const wxString& variantName )
1436 if( aFootprints.size() > 1 )
1438 msg.Printf( add ?
_(
"Add %s '%s' attribute to variant %s (footprint %s)." )
1439 :
_(
"Remove %s '%s' attribute from variant %s (footprint %s)." ),
1440 footprint->GetReference(),
1443 footprint->GetFPIDAsString() );
1447 msg.Printf( add ?
_(
"Add %s '%s' attribute to variant %s." )
1448 :
_(
"Remove %s '%s' attribute from variant %s." ),
1449 footprint->GetReference(),
1456 if( aFootprints.size() > 1 )
1458 msg.Printf( add ?
_(
"Added %s '%s' attribute to variant %s (footprint %s)." )
1459 :
_(
"Removed %s '%s' attribute from variant %s (footprint %s)." ),
1460 footprint->GetReference(),
1463 footprint->GetFPIDAsString() );
1467 msg.Printf( add ?
_(
"Added %s '%s' attribute to variant %s." )
1468 :
_(
"Removed %s '%s' attribute from variant %s." ),
1469 footprint->GetReference(),
1476 std::set<wxString> excessVariants;
1478 for(
const auto& [variantName,
_] : footprint->GetVariants() )
1479 excessVariants.insert( variantName );
1481 for(
const VARIANT_INFO&
info : variantInfo )
1494 if( !isAssociatedFootprint )
1497 excessVariants.erase(
info.name );
1498 bool targetDnp = variant.
m_hasDnp ? variant.
m_dnp : footprint->IsDNP();
1499 bool currentDnp = currentVariant ? currentVariant->
GetDNP() : footprint->IsDNP();
1501 if( currentDnp != targetDnp )
1503 printAttributeMessage( targetDnp,
_(
"Do not place" ),
info.name );
1508 fpVariant->SetDNP( targetDnp );
1516 : footprint->IsExcludedFromBOM();
1518 : footprint->IsExcludedFromBOM();
1520 if( currentExcludedFromBOM != targetExcludedFromBOM )
1522 printAttributeMessage( targetExcludedFromBOM,
_(
"exclude from BOM" ),
info.name );
1527 fpVariant->SetExcludedFromBOM( targetExcludedFromBOM );
1535 : footprint->IsExcludedFromPosFiles();
1537 : footprint->IsExcludedFromPosFiles();
1539 if( currentExcludedFromPosFiles != targetExcludedFromPosFiles )
1541 printAttributeMessage( targetExcludedFromPosFiles,
_(
"exclude from position files" ),
info.name );
1546 fpVariant->SetExcludedFromPosFiles( targetExcludedFromPosFiles );
1553 for(
const auto& [fieldName, fieldValue] : variant.
m_fields )
1555 if( fieldName.CmpNoCase( footprintFieldName ) == 0 )
1558 bool hasCurrentValue = currentVariant && currentVariant->
HasFieldValue( fieldName );
1559 wxString currentValue = hasCurrentValue ? currentVariant->
GetFieldValue( fieldName ) : wxString();
1561 if( currentValue != fieldValue )
1565 if( aFootprints.size() > 1 )
1567 msg.Printf(
_(
"Change %s field '%s' to '%s' on variant %s (footprint %s)." ),
1568 footprint->GetReference(),
1572 footprint->GetFPIDAsString() );
1576 msg.Printf(
_(
"Change %s field '%s' to '%s' on variant %s." ),
1577 footprint->GetReference(),
1585 if( aFootprints.size() > 1 )
1587 msg.Printf(
_(
"Changed %s field '%s' to '%s' on variant %s (footprint %s)." ),
1588 footprint->GetReference(),
1592 footprint->GetFPIDAsString() );
1596 msg.Printf(
_(
"Changed %s field '%s' to '%s' on variant %s." ),
1597 footprint->GetReference(),
1604 fpVariant->SetFieldValue( fieldName, fieldValue );
1613 for(
const wxString& excess : excessVariants )
1617 msg.Printf(
_(
"Remove variant %s:%s no longer associated with footprint %s." ),
1618 footprint->GetReference(),
1620 footprint->GetFPIDAsString() );
1624 msg.Printf(
_(
"Removed variant %s:%s no longer associated with footprint %s." ),
1625 footprint->GetReference(),
1627 footprint->GetFPIDAsString() );
1629 footprint->DeleteVariant( excess );
1638 bool isBaseFootprint =
fpidsEquivalent( footprint->GetFPID(), aBaseFpid );
1640 if( !isBaseFootprint && !footprint->IsDNP() )
1642 msg.Printf(
m_isDryRun ?
_(
"Add %s 'Do not place' fabrication attribute." )
1643 :
_(
"Added %s 'Do not place' fabrication attribute." ),
1644 footprint->GetReference() );
1649 footprint->SetDNP(
true );
1666 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
1677 std::set<wxString> netlistNetnames;
1679 for(
int ii = 0; ii < (int) aNetlist.
GetCount(); ii++ )
1683 for(
unsigned jj = 0; jj < component->
GetNetCount(); jj++ )
1695 if( netlistNetnames.count(
via->GetNetname() ) == 0 )
1697 wxString updatedNetname = wxEmptyString;
1706 if( !updatedNetname.IsEmpty() )
1710 wxString originalNetname =
via->GetNetname();
1712 msg.Printf(
_(
"Reconnect via from %s to %s." ),
1727 wxString originalNetname =
via->GetNetname();
1730 via->SetNet( netinfo );
1732 msg.Printf(
_(
"Reconnected via from %s to %s." ),
1742 msg.Printf(
_(
"Via connected to unknown net (%s)." ),
1754 auto isInNetlist = [&](
const wxString& aNetName ) ->
bool
1756 if( netlistNetnames.count( aNetName ) )
1761 for(
const wxString& netName : netlistNetnames )
1763 if( aNetName.StartsWith( netName ) )
1773 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
1776 if( !isInNetlist( zone->GetNetname() ) )
1781 wxString updatedNetname = wxEmptyString;
1794 if( updatedNetname.IsEmpty() &&
m_oldToNewNets.count( zone->GetNetname() ) )
1799 if( !updatedNetname.IsEmpty() )
1803 wxString originalNetname = zone->GetNetname();
1805 if( !zone->GetZoneName().IsEmpty() )
1807 msg.Printf(
_(
"Reconnect copper zone '%s' from %s to %s." ),
1808 zone->GetZoneName(),
1814 msg.Printf(
_(
"Reconnect copper zone from %s to %s." ),
1830 wxString originalNetname = zone->GetNetname();
1833 zone->SetNet( netinfo );
1835 if( !zone->GetZoneName().IsEmpty() )
1837 msg.Printf(
_(
"Reconnected copper zone '%s' from %s to %s." ),
1844 msg.Printf(
_(
"Reconnected copper zone from %s to %s." ),
1855 if( !zone->GetZoneName().IsEmpty() )
1857 msg.Printf(
_(
"Copper zone '%s' has no pads connected." ),
1862 wxString layerNames = zone->LayerMaskDescribe();
1867 if(
m_settings->m_Display.m_DisplayInvertXAxis )
1870 if(
m_settings->m_Display.m_DisplayInvertYAxis )
1874 msg.Printf(
_(
"Copper zone on %s at (%s, %s) has no pads connected to net \"%s\"." ),
1884 zone->GetNetname() );
1908 if( netlistGroup ==
nullptr )
1911 if( netlistGroup->
name != pcbGroup->GetName() )
1915 msg.Printf(
_(
"Change group name from '%s' to '%s'." ),
1921 msg.Printf(
_(
"Changed group name from '%s' to '%s'." ),
1925 pcbGroup->SetName( netlistGroup->
name );
1931 if( netlistGroup->
libId != pcbGroup->GetDesignBlockLibId() )
1935 msg.Printf(
_(
"Change group library link from '%s' to '%s'." ),
1936 EscapeHTML( pcbGroup->GetDesignBlockLibId().GetUniStringLibId() ),
1941 msg.Printf(
_(
"Changed group library link from '%s' to '%s'." ),
1942 EscapeHTML( pcbGroup->GetDesignBlockLibId().GetUniStringLibId() ),
1945 pcbGroup->SetDesignBlockLibId( netlistGroup->
libId );
1959 if( candidate->m_Uuid == member )
1961 childGroup = candidate;
1966 if( !childGroup || childGroup == pcbGroup || childGroup->
GetParentGroup() == pcbGroup )
1973 msg.Printf(
_(
"Add group '%s' to group '%s'." ),
EscapeHTML( childGroup->
GetName() ),
1978 msg.Printf(
_(
"Added group '%s' to group '%s'." ),
EscapeHTML( childGroup->
GetName() ),
1982 pcbGroup->AddItem( childGroup );
1994 std::map<COMPONENT*, FOOTPRINT*>& aFootprintMap )
2002 for(
int i = 0; i < (int) aNetlist.
GetCount(); i++ )
2005 FOOTPRINT* footprint = aFootprintMap[component];
2011 for(
unsigned jj = 0; jj < component->
GetNetCount(); jj++ )
2015 if( padNumber.IsEmpty() )
2018 msg.Printf(
_(
"Symbol %s has pins with no number. These pins can not be matched "
2028 msg.Printf(
_(
"%s pad %s not found in %s." ),
2044 FOOTPRINT* lastPreexistingFootprint =
nullptr;
2047 std::unordered_set<wxString> sheetPaths;
2048 std::unordered_set<FOOTPRINT*> usedFootprints;
2054 std::map<COMPONENT*, FOOTPRINT*> footprintMap;
2056 if( !
m_board->Footprints().empty() )
2057 lastPreexistingFootprint =
m_board->Footprints().back();
2067 net->SetIsCurrent( net->GetNetCode() == 0 );
2069 m_board->GetComponentClassManager().InitNetlistUpdate();
2073 for(
unsigned ii = 0; ii < aNetlist.
GetCount(); ii++ )
2077 for(
unsigned jj = 0; jj <
comp->GetNetCount(); jj++ )
2084 for(
unsigned i = 0; i < aNetlist.
GetCount(); i++ )
2088 if( component->
GetProperties().count( wxT(
"exclude_from_board" ) ) )
2091 msg.Printf(
_(
"Processing symbol '%s:%s'." ),
2097 const bool hasBaseFpid = !baseFpid.
empty();
2101 msg.Printf(
_(
"Warning: %s footprint '%s' is missing a library name. "
2102 "Use the full 'Library:Footprint' format to avoid repeated update "
2110 std::vector<FOOTPRINT*> matchingFootprints;
2121 base.push_back( uuid );
2123 if( footprint->GetPath() == base )
2132 match = footprint->GetReference().CmpNoCase( component->
GetReference() ) == 0;
2136 matchingFootprints.push_back( footprint );
2138 if( footprint == lastPreexistingFootprint )
2145 std::vector<LIB_ID> expectedFpids;
2146 std::unordered_set<wxString> expectedFpidKeys;
2148 auto addExpectedFpid =
2149 [&](
const LIB_ID& aFpid )
2154 wxString key = aFpid.Format();
2156 if( expectedFpidKeys.insert( key ).second )
2157 expectedFpids.push_back( aFpid );
2160 addExpectedFpid( baseFpid );
2164 for(
const auto& [variantName, variant] : component->
GetVariants() )
2166 auto fieldIt = variant.m_fields.find( footprintFieldName );
2168 if( fieldIt == variant.m_fields.end() || fieldIt->second.IsEmpty() )
2173 if( parsedId.
Parse( fieldIt->second,
true ) >= 0 )
2175 msg.Printf(
_(
"Invalid footprint ID '%s' for variant '%s' on %s." ),
2184 addExpectedFpid( parsedId );
2187 auto isExpectedFpid =
2188 [&](
const LIB_ID& aFpid ) ->
bool
2193 if( expectedFpidKeys.count( aFpid.Format() ) > 0 )
2205 auto takeMatchingFootprint =
2208 for(
FOOTPRINT* footprint : matchingFootprints )
2210 if( usedFootprints.count( footprint ) )
2220 std::vector<FOOTPRINT*> componentFootprints;
2221 componentFootprints.reserve( expectedFpids.size() );
2225 baseFootprint = takeMatchingFootprint( baseFpid );
2226 else if( !matchingFootprints.empty() )
2227 baseFootprint = matchingFootprints.front();
2233 for(
FOOTPRINT* footprint : matchingFootprints )
2235 if( usedFootprints.count( footprint ) )
2238 if( isExpectedFpid( footprint->GetFPID() ) )
2241 replaceCandidate = footprint;
2245 if( replaceCandidate )
2250 baseFootprint = replaced;
2252 baseFootprint = replaceCandidate;
2256 if( !baseFootprint && ( hasBaseFpid || expectedFpids.empty() ) )
2261 componentFootprints.push_back( baseFootprint );
2262 usedFootprints.insert( baseFootprint );
2263 footprintMap[ component ] = baseFootprint;
2266 for(
const LIB_ID& fpid : expectedFpids )
2274 FOOTPRINT* footprint = takeMatchingFootprint( fpid );
2281 componentFootprints.push_back( footprint );
2282 usedFootprints.insert( footprint );
2286 for(
FOOTPRINT* footprint : componentFootprints )
2297 sheetPaths.insert( footprint->GetSheetname() );
2300 if( !componentFootprints.empty() )
2312 bool matched =
false;
2318 bool isStaleVariantFootprint =
false;
2320 if( usedFootprints.count( footprint ) )
2331 if( component && component->
GetProperties().count( wxT(
"exclude_from_board" ) ) == 0 )
2339 isStaleVariantFootprint =
true;
2350 if( isStaleVariantFootprint )
2353 if( doDelete && !matched && footprint->IsLocked() && !
m_overrideLocks )
2357 msg.Printf(
_(
"Cannot remove unused footprint %s (footprint is locked)." ),
2358 footprint->GetReference() );
2362 msg.Printf(
_(
"Could not remove unused footprint %s (footprint is locked)." ),
2363 footprint->GetReference() );
2371 if( doDelete && !matched )
2375 msg.Printf(
_(
"Remove unused footprint %s." ),
2376 footprint->GetReference() );
2381 msg.Printf(
_(
"Removed unused footprint %s." ),
2382 footprint->GetReference() );
2392 for(
PAD*
pad : footprint->Pads() )
2395 pad->GetNet()->SetIsCurrent(
true );
2403 m_board->GetComponentClassManager().FinishNetlistUpdate();
2404 m_board->SynchronizeComponentClasses( sheetPaths );
2411 if( !net->IsCurrent() )
2413 msg.Printf(
_(
"Removed unused net %s." ),
2422 const std::vector<wxString>& netlistVariants = aNetlist.
GetVariantNames();
2424 if( !netlistVariants.empty() || !
m_board->GetVariantNames().empty() )
2428 auto findBoardVariantName =
2429 [&](
const wxString& aVariantName ) -> wxString
2431 for(
const wxString&
name :
m_board->GetVariantNames() )
2433 if(
name.CmpNoCase( aVariantName ) == 0 )
2437 return wxEmptyString;
2440 std::vector<wxString> updatedVariantNames;
2441 updatedVariantNames.reserve( netlistVariants.size() );
2443 for(
const wxString& variantName : netlistVariants )
2445 wxString actualName = findBoardVariantName( variantName );
2447 if( actualName.IsEmpty() )
2449 m_board->AddVariant( variantName );
2450 actualName = findBoardVariantName( variantName );
2452 if( !actualName.IsEmpty() )
2454 msg.Printf(
_(
"Added variant '%s'." ), actualName );
2459 if( actualName.IsEmpty() )
2464 wxString oldDescription =
m_board->GetVariantDescription( actualName );
2466 if( newDescription != oldDescription )
2468 m_board->SetVariantDescription( actualName, newDescription );
2469 msg.Printf(
_(
"Updated description for variant '%s'." ), actualName );
2473 updatedVariantNames.push_back( actualName );
2476 std::vector<wxString> variantsToRemove;
2478 for(
const wxString& existingName :
m_board->GetVariantNames() )
2482 for(
const wxString& variantName : netlistVariants )
2484 if( existingName.CmpNoCase( variantName ) == 0 )
2492 variantsToRemove.push_back( existingName );
2495 for(
const wxString& variantName : variantsToRemove )
2497 m_board->DeleteVariant( variantName );
2498 msg.Printf(
_(
"Removed variant '%s'." ), variantName );
2502 if( !updatedVariantNames.empty() )
2503 m_board->SetVariantNames( updatedVariantNames );
2522 if( !colorStr.IsEmpty() )
2536 std::shared_ptr<NET_SETTINGS>& netSettings =
m_board->GetDesignSettings().m_NetSettings;
2540 netSettings->ClearNetChainClasses();
2541 netSettings->ClearChainPatternAssignments();
2544 netSettings->SetNetChainClass(
chain, className );
2552 const wxString& chainName = net->GetNetChain();
2554 if( chainName.IsEmpty() )
2557 auto it = chainClasses.find( chainName );
2559 if( it == chainClasses.end() || it->second.IsEmpty() )
2562 if( netSettings->HasNetclass( it->second ) )
2563 netSettings->SetChainPatternAssignment( net->GetNetname(), it->second );
2568 m_board->SynchronizeNetsAndNetClasses(
true );
2572 m_board->SynchronizeNetsAndNetClasses(
true );
2577 PAD* pads[2] = {
nullptr,
nullptr };
2579 for(
size_t i = 0; i < sig.second.size() && i < 2; ++i )
2581 const wxString& ref = sig.second[i].first;
2582 const wxString&
pin = sig.second[i].second;
2588 PAD* candidate =
nullptr;
2589 PAD* best =
nullptr;
2590 int bestDist = std::numeric_limits<int>::max();
2599 if( !best || dist < bestDist || ( dist == bestDist && candidate->
m_Uuid < best->
m_Uuid ) )
2609 for(
int i = 0; i < 2; ++i )
2616 if( !termNet || termNet->
GetNetChain() != sig.first )
2621 if( net != termNet && net->
GetNetChain() == sig.first
2622 && net->GetTerminalPad( i ) )
2624 net->ClearTerminalPad( i );
2640 for(
const std::pair<const wxString, NETINFO_ITEM*>& addedNet :
m_addedNets )
2641 delete addedNet.second;
constexpr EDA_IU_SCALE pcbIUScale
wxString GetNetname() const
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
void SetUuid(const KIID &aUuid)
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
std::map< PAD *, wxString > m_padNets
PCBNEW_SETTINGS * m_settings
bool m_deleteUnusedFootprints
void cacheNetname(PAD *aPad, const wxString &aNetname)
bool UpdateNetlist(NETLIST &aNetlist)
Update the board's components according to the new netlist.
wxString getNetname(PAD *aPad)
wxString getPinFunction(PAD *aPad)
std::vector< FOOTPRINT * > m_addedFootprints
bool updateFootprintParameters(FOOTPRINT *aFootprint, COMPONENT *aNetlistComponent)
std::map< wxString, wxString > m_oldToNewNets
static void ApplyChainAssignments(BOARD *aBoard, const NETLIST &aNetlist, REPORTER *aReporter, bool aDryRun)
Apply the netlist's chain assignments to every NETINFO_ITEM on the board.
bool updateFootprintGroup(FOOTPRINT *aPcbFootprint, COMPONENT *aNetlistComponent)
static bool fpidsEquivalent(const LIB_ID &aBoardFpid, const LIB_ID &aSchematicFpid)
Compare a board footprint ID against a schematic-derived footprint ID, ignoring the library nickname ...
std::map< wxString, NETINFO_ITEM * > m_addedNets
std::vector< PCB_GROUP * > m_addedGroups
bool testConnectivity(NETLIST &aNetlist, std::map< COMPONENT *, FOOTPRINT * > &aFootprintMap)
bool updateCopperZoneNets(NETLIST &aNetlist)
void cachePinFunction(PAD *aPad, const wxString &aPinFunction)
bool updateGroups(NETLIST &aNetlist)
BOARD_NETLIST_UPDATER(PCB_EDIT_FRAME *aFrame, BOARD *aBoard)
Construct an updater for interactive use from the board editor.
bool updateComponentClass(FOOTPRINT *aFootprint, COMPONENT *aNewComponent)
bool updateComponentPadConnections(FOOTPRINT *aFootprint, COMPONENT *aNewComponent)
VECTOR2I estimateFootprintInsertionPosition()
std::map< PAD *, wxString > m_padPinFunctions
void applyComponentVariants(COMPONENT *aComponent, const std::vector< FOOTPRINT * > &aFootprints, const LIB_ID &aBaseFpid)
std::map< ZONE *, std::vector< PAD * > > m_zoneConnectionsCache
FOOTPRINT * replaceFootprint(NETLIST &aNetlist, FOOTPRINT *aFootprint, COMPONENT *aNewComponent)
void cacheCopperZoneConnections()
bool updateComponentUnits(FOOTPRINT *aFootprint, COMPONENT *aNewComponent)
FOOTPRINT * addNewFootprint(COMPONENT *aComponent)
std::set< wxString > m_schematicNetNames
Information pertinent to a Pcbnew printed circuit board.
const NETINFO_LIST & GetNetInfo() const
constexpr size_type GetWidth() const
constexpr Vec Centre() const
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
static wxString GetFullClassNameForConstituents(const std::unordered_set< wxString > &classNames)
Gets the full effective class name for the given set of constituent classes.
A lightweight representation of a component class.
const wxString & GetName() const
Fetches the full name of this component class.
Used to store the component pin name to net name (and pin function) associations stored in a netlist.
const wxString & GetNetName() const
const wxString & GetPinFunction() const
const wxString & GetPinName() const
const wxString & GetPinType() const
Store all of the related component information found in a netlist.
const std::vector< UNIT_INFO > & GetUnitInfo() const
const wxString & GetHumanReadablePath() const
const COMPONENT_NET & GetNet(unsigned aIndex) const
const KIID_PATH & GetPath() const
const wxString & GetReference() const
const wxString & GetValue() const
const nlohmann::ordered_map< wxString, wxString > & GetFields() const
const std::map< wxString, wxString > & GetProperties() const
const CASE_INSENSITIVE_MAP< COMPONENT_VARIANT > & GetVariants() const
NETLIST_GROUP * GetGroup() const
const std::vector< KIID > & GetKIIDs() const
bool GetDuplicatePadNumbersAreJumpers() const
const LIB_ID & GetFPID() const
unsigned GetNetCount() const
std::unordered_set< wxString > & GetComponentClassNames()
std::vector< std::set< wxString > > & JumperPadGroups()
std::unordered_set< EDA_ITEM * > & GetItems()
void RemoveItem(EDA_ITEM *aItem)
Remove item from group.
void AddItem(EDA_ITEM *aItem)
Add item to group.
void SetName(const wxString &aName)
virtual EDA_GROUP * GetParentGroup() const
virtual void SetParent(EDA_ITEM *aParent)
virtual void SetVisible(bool aVisible)
virtual void SetText(const wxString &aText)
A color representation with 4 components: red, green, blue, alpha.
bool SetFromHexString(const wxString &aColorString)
wxString AsString() const
A logical library item identifier and consists of various portions much like a URI.
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
wxString GetUniStringLibId() const
const UTF8 & GetLibItemName() const
Handle the data for a net.
const wxString & GetNetChain() const
void SetTerminal(int aIndex, PAD *aPad)
Set the terminal-pad pointer and the persisted UUID at aIndex from a single pad, keeping the two view...
void SetIsCurrent(bool isCurrent)
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
const std::map< wxString, std::vector< std::pair< wxString, wxString > > > & GetNetChainTerminalPins() const
const std::vector< wxString > & GetVariantNames() const
unsigned GetCount() const
COMPONENT * GetComponentByPath(const KIID_PATH &aPath)
Return a COMPONENT by aPath.
COMPONENT * GetComponentByReference(const wxString &aReference)
Return a COMPONENT by aReference.
const std::map< wxString, wxString > & GetNetChainNetClasses() const
const std::map< wxString, wxString > & GetSignalChainClasses() const
NETLIST_GROUP * GetGroupByUuid(const KIID &aUuid)
Return a NETLIST_GROUP by aUuid.
const std::map< wxString, wxString > & GetNetChainColors() const
COMPONENT * GetComponent(unsigned aIndex)
Return the COMPONENT at aIndex.
wxString GetNetChainFor(const wxString &aNet) const
wxString GetVariantDescription(const wxString &aVariantName) const
A singleton reporter that reports to nowhere.
const wxString & GetPinFunction() const
VECTOR2I GetPosition() const override
The main frame for Pcbnew.
void SetName(const wxString &aName)
A set of BOARD_ITEMs (i.e., without duplicates).
EDA_ITEM * AsEdaItem() override
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
virtual void SetPosition(const VECTOR2I &aPos) override
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
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.
Handle a list of polygons defining a copper zone.
KICOMMON_API wxString MessageTextFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A helper to convert the double length aValue to a string in inches, millimeters, or unscaled units.
Class to handle a set of BOARD_ITEMs.
FOOTPRINT * LoadFootprintFromProject(BOARD *aBoard, const LIB_ID &aFootprintId, bool aKeepUuid)
Load a footprint from the project library table and apply board default settings.
T * GetAppSettings(const char *aFilename)
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
wxString UnescapeString(const wxString &aSource)
bool m_excludedFromPosFiles
bool m_hasExcludedFromBOM
bool m_hasExcludedFromPosFiles
nlohmann::ordered_map< wxString, wxString > m_fields
std::vector< KIID > members
@ USER
The field ID hasn't been set yet; field is invalid.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
wxString GetCanonicalFieldName(FIELD_T aFieldType)
VECTOR3I expected(15, 30, 45)
const SHAPE_LINE_CHAIN chain
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
VECTOR2< int32_t > VECTOR2I