59 m_commit( aFrame->GetToolManager() ),
86 const wxString previous = net->GetNetChain();
89 if( !previous.IsEmpty() &&
next.IsEmpty() && aReporter && !aDryRun )
93 _(
"Net chain assignment '%s' on net '%s' cleared by netlist "
95 previous, net->GetNetname() ),
101 net->SetNetChain(
next );
103 if( previous !=
next )
105 for(
int i = 0; i < 2; ++i )
106 net->ClearTerminalPad( i );
120 netSettings->ClearNetChainClasses();
121 netSettings->ClearNetChainNetClasses();
124 netSettings->SetNetChainClass(
chain, className );
127 netSettings->SetNetChainNetClass(
chain, netclass );
189 bestPosition.
x = pageSize.
x / 2;
190 bestPosition.
y = pageSize.
y / 2;
207 if( aFootprintId.
empty() )
209 msg.Printf(
_(
"Cannot add %s (no footprint assigned)." ),
218 if( footprint ==
nullptr )
220 msg.Printf(
_(
"Cannot add %s (footprint '%s' not found)." ),
229 m_board->GetComponentClassManager().GetNoneComponentClass() );
233 msg.Printf(
_(
"Add %s (footprint '%s')." ),
244 bool showRatsnest =
true;
247 showRatsnest =
m_settings->m_Display.m_ShowGlobalRatsnest;
249 pad->SetLocalRatsnestVisible( showRatsnest );
252 pad->SetNetCode( 0 );
267 msg.Printf(
_(
"Added %s (footprint '%s')." ),
280 wxString curClassName, newClassName;
284 curClassName = curClass->
GetName();
294 newClass =
m_board->GetComponentClassManager().GetEffectiveStaticComponentClass(
296 newClassName = newClass->
GetName();
299 if( curClassName == newClassName )
308 copy->SetParentGroup(
nullptr );
315 if( curClassName == wxEmptyString && newClassName != wxEmptyString )
317 msg.Printf(
_(
"Change %s component class to '%s'." ),
321 else if( curClassName != wxEmptyString && newClassName == wxEmptyString )
323 msg.Printf(
_(
"Remove %s component class (currently '%s')." ),
329 msg.Printf(
_(
"Change %s component class from '%s' to '%s'." ),
337 wxASSERT_MSG( newClass !=
nullptr,
"Component class should not be nullptr" );
341 if( curClassName == wxEmptyString && newClassName != wxEmptyString )
343 msg.Printf(
_(
"Changed %s component class to '%s'." ),
347 else if( curClassName != wxEmptyString && newClassName == wxEmptyString )
349 msg.Printf(
_(
"Removed %s component class (was '%s')." ),
355 msg.Printf(
_(
"Changed %s component class from '%s' to '%s'." ),
378 msg.Printf(
_(
"Cannot update %s (no footprint assigned)." ),
387 if( newFootprint ==
nullptr )
389 msg.Printf(
_(
"Cannot update %s (footprint '%s' not found)." ),
401 msg.Printf(
_(
"Cannot change %s footprint from '%s' to '%s' (footprint is locked)."),
412 msg.Printf(
_(
"Change %s footprint from '%s' to '%s'."),
426 msg.Printf(
_(
"Could not change %s footprint from '%s' to '%s' (footprint is locked)."),
440 m_board->ExchangeFootprint( aFootprint, newFootprint,
m_commit,
true );
442 msg.Printf(
_(
"Changed %s footprint from '%s' to '%s'."),
468 firstAssociatedVariant = &
test;
477 if( !
m_commit.GetStatus( aFootprint ) )
480 copy->SetParentGroup(
nullptr );
483 bool changed =
false;
490 msg.Printf(
_(
"Change %s reference designator to %s." ),
496 msg.Printf(
_(
"Changed %s reference designator to %s." ),
508 wxString netlistValue = aNetlistComponent->
GetValue();
510 if( firstAssociatedVariant !=
nullptr
516 if( aFootprint->
GetValue() != netlistValue )
520 msg.Printf(
_(
"Change %s value from %s to %s." ),
527 msg.Printf(
_(
"Changed %s value from %s to %s." ),
533 aFootprint->
SetValue( netlistValue );
542 if( !aNetlistComponent->
GetKIIDs().empty() )
543 new_path.push_back( aNetlistComponent->
GetKIIDs().front() );
545 if( aFootprint->
GetPath() != new_path )
549 msg.Printf(
_(
"Update %s symbol association from %s to %s." ),
556 msg.Printf(
_(
"Updated %s symbol association from %s to %s." ),
562 aFootprint->
SetPath( new_path );
568 nlohmann::ordered_map<wxString, wxString> fpFieldsAsMap;
573 if( field->IsReference() || field->IsValue() || field->IsComponentClass() )
578 fpFieldsAsMap[field->GetName()] = field->GetText();
582 nlohmann::ordered_map<wxString, wxString> compFields = aNetlistComponent->
GetFields();
588 compFields.erase( wxT(
"Component Class" ) );
590 if( firstAssociatedVariant !=
nullptr )
592 for(
const auto& [
name, value] : firstAssociatedVariant->
m_fields )
593 compFields[
name] = value;
599 bool remove_only =
true;
601 for(
const auto& [
name, value] : compFields )
603 if( fpFieldsAsMap.count(
name ) == 0 || fpFieldsAsMap[
name] != value )
611 for(
const auto& [
name, value] : fpFieldsAsMap )
613 if( compFields.count(
name ) == 0 )
626 msg.Printf(
_(
"Update %s fields." ), aFootprint->
GetReference() );
633 if( field->IsMandatory() )
636 if( compFields.count( field->GetName() ) == 0 )
640 msg.Printf(
_(
"Remove %s footprint fields not in symbol." ), aFootprint->
GetReference() );
652 msg.Printf(
_(
"Updated %s fields." ), aFootprint->
GetReference() );
658 for(
auto& [
name, value] : compFields )
667 aFootprint->
Add( newField );
688 std::vector<PCB_FIELD*> fieldList;
689 aFootprint->
GetFields( fieldList,
false );
693 if( field->IsMandatory() )
696 if( compFields.count( field->GetName() ) == 0 )
701 msg.Printf(
_(
"Removed %s footprint fields not in symbol." ), aFootprint->
GetReference() );
705 aFootprint->
Remove( field );
708 m_frame->GetCanvas()->GetView()->Remove( field );
723 if( !humanSheetPath.empty() )
724 sheetname = humanSheetPath;
725 else if( aNetlistComponent->
GetProperties().count( wxT(
"Sheetname" ) ) > 0 )
726 sheetname = aNetlistComponent->
GetProperties().at( wxT(
"Sheetname" ) );
728 if( aNetlistComponent->
GetProperties().count( wxT(
"Sheetfile" ) ) > 0 )
729 sheetfile = aNetlistComponent->
GetProperties().at( wxT(
"Sheetfile" ) );
731 if( aNetlistComponent->
GetProperties().count( wxT(
"ki_fp_filters" ) ) > 0 )
732 fpFilters = aNetlistComponent->
GetProperties().at( wxT(
"ki_fp_filters" ) );
738 msg.Printf(
_(
"Update %s sheetname to '%s'." ),
745 msg.Printf(
_(
"Updated %s sheetname to '%s'." ),
757 msg.Printf(
_(
"Update %s sheetfile to '%s'." ),
764 msg.Printf(
_(
"Updated %s sheetfile to '%s'." ),
776 msg.Printf(
_(
"Update %s footprint filters to '%s'." ),
783 msg.Printf(
_(
"Updated %s footprint filters to '%s'." ),
791 bool netlistExcludeFromBOM = aNetlistComponent->
GetProperties().count( wxT(
"exclude_from_bom" ) ) > 0;
800 if( netlistExcludeFromBOM )
801 msg.Printf(
_(
"Add %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
803 msg.Printf(
_(
"Remove %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
809 if( netlistExcludeFromBOM )
812 msg.Printf(
_(
"Added %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
817 msg.Printf(
_(
"Removed %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
827 bool netlistExcludeFromSim = aNetlistComponent->
GetProperties().count( wxT(
"exclude_from_sim" ) ) > 0;
837 if( netlistExcludeFromSim )
838 msg.Printf(
_(
"Add %s 'exclude from simulation' attribute." ), aFootprint->
GetReference() );
840 msg.Printf(
_(
"Remove %s 'exclude from simulation' attribute." ), aFootprint->
GetReference() );
846 if( netlistExcludeFromSim )
849 msg.Printf(
_(
"Added %s 'exclude from simulation' attribute." ), aFootprint->
GetReference() );
854 msg.Printf(
_(
"Removed %s 'exclude from simulation' attribute." ), aFootprint->
GetReference() );
864 bool netlistDNP = aNetlistComponent->
GetProperties().count( wxT(
"dnp" ) ) > 0;
866 if( firstAssociatedVariant !=
nullptr && firstAssociatedVariant->
m_hasDnp )
867 netlistDNP = firstAssociatedVariant->
m_dnp;
874 msg.Printf(
_(
"Add %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
876 msg.Printf(
_(
"Remove %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
885 msg.Printf(
_(
"Added %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
890 msg.Printf(
_(
"Removed %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
900 bool netlistExcludeFromPosFiles = aNetlistComponent->
GetProperties().count( wxT(
"exclude_from_pos_files" ) ) > 0;
910 if( netlistExcludeFromPosFiles )
912 msg.Printf(
_(
"Add %s 'exclude from position files' fabrication attribute." ),
917 msg.Printf(
_(
"Remove %s 'exclude from position files' fabrication attribute." ),
925 if( netlistExcludeFromPosFiles )
928 msg.Printf(
_(
"Added %s 'exclude from position files' fabrication attribute." ),
934 msg.Printf(
_(
"Removed %s 'exclude from position files' fabrication attribute." ),
957 msg.Printf(
_(
"Added %s 'duplicate pad numbers are jumpers' attribute." ),
962 msg.Printf(
_(
"Removed %s 'duplicate pad numbers are jumpers' attribute." ),
970 msg.Printf(
_(
"Add %s 'duplicate pad numbers are jumpers' attribute." ),
975 msg.Printf(
_(
"Remove %s 'duplicate pad numbers are jumpers' attribute." ),
989 msg.Printf(
_(
"Updated %s jumper pad groups" ), aFootprint->
GetReference() );
993 msg.Printf(
_(
"Update %s jumper pad groups" ), aFootprint->
GetReference() );
999 if( changed &&
copy )
1016 KIID existingGroupKIID = existingGroup ? existingGroup->
m_Uuid : 0;
1019 if( newGroupKIID == existingGroupKIID )
1030 copy->SetParentGroup(
nullptr );
1033 bool changed =
false;
1040 auto it = std::find_if(
m_board->Groups().begin(),
m_board->Groups().end(),
1042 return group->m_Uuid == newGroupKIID;
1046 if( it !=
m_board->Groups().end() )
1050 if( existingGroupKIID != 0 )
1054 msg.Printf(
_(
"Remove %s from group '%s'." ),
1060 msg.Printf(
_(
"Removed %s from group '%s'." ),
1068 if( existingGroup->
GetItems().size() < 2 )
1079 if( newGroupKIID != 0 )
1083 msg.Printf(
_(
"Add %s to group '%s'." ),
1089 msg.Printf(
_(
"Added %s to group '%s'." ),
1095 if( newGroup ==
nullptr )
1098 newGroup->
SetUuid( newGroupKIID );
1112 newGroup->
AddItem( aPcbFootprint );
1118 if( changed &&
copy )
1138 copy->SetParentGroup(
nullptr );
1141 bool changed =
false;
1144 std::deque<PAD*> pads = aFootprint->
Pads();
1145 std::set<wxString> padNetnames;
1147 std::sort( pads.begin(), pads.end(),
1150 return a->m_Uuid < b->m_Uuid;
1157 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1158 wxT(
"Processing pad %s of component %s" ),
1162 wxString pinFunction;
1167 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1168 wxT(
" Found valid net: %s" ),
1175 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1176 wxT(
" No net found for pad %s" ),
1182 if(
pad->GetPinFunction() != pinFunction )
1185 pad->SetPinFunction( pinFunction );
1188 if(
pad->GetPinType() != pinType )
1191 pad->SetPinType( pinType );
1200 if( !net.
IsValid() || !
pad->IsOnCopperLayer() )
1202 if( !
pad->GetNetname().IsEmpty() )
1206 msg.Printf(
_(
"Disconnect %s pin %s." ),
1212 msg.Printf(
_(
"Disconnected %s pin %s." ),
1219 else if(
pad->IsOnCopperLayer() && !
pad->GetNumber().IsEmpty() )
1222 msg.Printf(
_(
"No net found for component %s pad %s (no pin %s in symbol)." ),
1237 if(
pad->GetNetname().IsEmpty() )
1238 pad->SetPinFunction( wxEmptyString );
1250 if(
pad->IsNoConnectPad() )
1252 netName = wxString::Format( wxS(
"%s" ), net.
GetNetName() );
1254 for(
int jj = 1; !padNetnames.insert( netName ).second
1258 netName = wxString::Format( wxS(
"%s_%d" ), net.
GetNetName(), jj );
1267 if(
pad->GetNetname() != netName )
1270 if( netinfo ==
nullptr )
1277 if( netinfo ==
nullptr )
1289 msg.Printf(
_(
"Add net %s." ),
1294 if( !
pad->GetNetname().IsEmpty() )
1300 msg.Printf(
_(
"Reconnect %s pin %s from %s to %s."),
1308 msg.Printf(
_(
"Reconnected %s pin %s from %s to %s."),
1319 msg.Printf(
_(
"Connect %s pin %s to %s."),
1326 msg.Printf(
_(
"Connected %s pin %s to %s."),
1338 pad->SetNet( netinfo );
1348 if( changed &&
copy )
1360 std::vector<FOOTPRINT::FP_UNIT_INFO> newUnits;
1363 newUnits.push_back( { u.m_unitName, u.m_pins } );
1365 const std::vector<FOOTPRINT::FP_UNIT_INFO>& curUnits = aFootprint->
GetUnitInfo();
1367 if( std::ranges::equal( curUnits, newUnits,
1368 [](
const auto& a,
const auto& b )
1370 return a.m_unitName == b.m_unitName && a.m_pins == b.m_pins;
1378 msg.Printf(
_(
"Update %s unit metadata." ), aFootprint->
GetReference() );
1386 if( !
m_commit.GetStatus( aFootprint ) )
1389 copy->SetParentGroup(
nullptr );
1394 msg.Printf(
_(
"Updated %s unit metadata." ), aFootprint->
GetReference() );
1409 return aBoardFpid == aSchematicFpid;
1414 const std::vector<FOOTPRINT*>& aFootprints,
1415 const LIB_ID& aBaseFpid )
1420 if( aBaseFpid.
empty() )
1432 std::vector<VARIANT_INFO> variantInfo;
1433 variantInfo.reserve( variants.size() );
1435 for(
const auto& [variantName, variant] : variants )
1437 LIB_ID variantFPID = aBaseFpid;
1439 auto fieldIt = variant.m_fields.find( footprintFieldName );
1441 if( fieldIt != variant.m_fields.end() && !fieldIt->second.IsEmpty() )
1445 if( parsedId.
Parse( fieldIt->second,
true ) >= 0 )
1447 msg.Printf(
_(
"Invalid footprint ID '%s' for variant '%s' on %s." ),
1456 variantFPID = parsedId;
1460 variantInfo.push_back( { variantName, &variant, variantFPID } );
1463 for(
FOOTPRINT* footprint : aFootprints )
1473 copy->SetParentGroup(
nullptr );
1476 bool changed =
false;
1478 auto printAttributeMessage =
1479 [&](
bool add,
const wxString& attrName,
const wxString& variantName )
1483 if( aFootprints.size() > 1 )
1485 msg.Printf( add ?
_(
"Add %s '%s' attribute to variant %s (footprint %s)." )
1486 :
_(
"Remove %s '%s' attribute from variant %s (footprint %s)." ),
1487 footprint->GetReference(),
1490 footprint->GetFPIDAsString() );
1494 msg.Printf( add ?
_(
"Add %s '%s' attribute to variant %s." )
1495 :
_(
"Remove %s '%s' attribute from variant %s." ),
1496 footprint->GetReference(),
1503 if( aFootprints.size() > 1 )
1505 msg.Printf( add ?
_(
"Added %s '%s' attribute to variant %s (footprint %s)." )
1506 :
_(
"Removed %s '%s' attribute from variant %s (footprint %s)." ),
1507 footprint->GetReference(),
1510 footprint->GetFPIDAsString() );
1514 msg.Printf( add ?
_(
"Added %s '%s' attribute to variant %s." )
1515 :
_(
"Removed %s '%s' attribute from variant %s." ),
1516 footprint->GetReference(),
1523 bool isBaseFootprint =
fpidsEquivalent( footprint->GetFPID(), aBaseFpid );
1528 const bool baseFootprintDnp = footprint->IsDNP();
1529 bool effectiveFootprintDnp = baseFootprintDnp;
1536 if( !isBaseFootprint && !effectiveFootprintDnp )
1538 msg.Printf(
m_isDryRun ?
_(
"Add %s 'Do not place' fabrication attribute." )
1539 :
_(
"Added %s 'Do not place' fabrication attribute." ),
1540 footprint->GetReference() );
1545 footprint->SetDNP(
true );
1549 effectiveFootprintDnp =
true;
1553 std::set<wxString> excessVariants;
1555 for(
const auto& [variantName,
_] : footprint->GetVariants() )
1556 excessVariants.insert( variantName );
1558 for(
const VARIANT_INFO&
info : variantInfo )
1572 if( !isAssociatedFootprint )
1574 if( aFootprints.size() > 1 )
1576 excessVariants.erase(
info.name );
1577 bool currentDnp = currentVariant ? currentVariant->
GetDNP() : effectiveFootprintDnp;
1581 printAttributeMessage(
true,
_(
"Do not place" ),
info.name );
1586 fpVariant->SetDNP(
true );
1597 excessVariants.erase(
info.name );
1598 bool targetDnp = variant.
m_hasDnp ? variant.
m_dnp : baseFootprintDnp;
1599 bool currentDnp = currentVariant ? currentVariant->
GetDNP() : effectiveFootprintDnp;
1601 if( currentDnp != targetDnp )
1603 printAttributeMessage( targetDnp,
_(
"Do not place" ),
info.name );
1608 fpVariant->SetDNP( targetDnp );
1616 : footprint->IsExcludedFromBOM();
1618 : footprint->IsExcludedFromBOM();
1620 if( currentExcludedFromBOM != targetExcludedFromBOM )
1622 printAttributeMessage( targetExcludedFromBOM,
_(
"exclude from BOM" ),
info.name );
1627 fpVariant->SetExcludedFromBOM( targetExcludedFromBOM );
1635 : footprint->IsExcludedFromSim();
1637 : footprint->IsExcludedFromSim();
1639 if( currentExcludedFromSim != targetExcludedFromSim )
1641 printAttributeMessage( targetExcludedFromSim,
_(
"exclude from simulation" ),
info.name );
1646 fpVariant->SetExcludedFromSim( targetExcludedFromSim );
1654 : footprint->IsExcludedFromPosFiles();
1656 : footprint->IsExcludedFromPosFiles();
1658 if( currentExcludedFromPosFiles != targetExcludedFromPosFiles )
1660 printAttributeMessage( targetExcludedFromPosFiles,
_(
"exclude from position files" ),
info.name );
1665 fpVariant->SetExcludedFromPosFiles( targetExcludedFromPosFiles );
1672 for(
const auto& [fieldName, fieldValue] : variant.
m_fields )
1674 if( fieldName.CmpNoCase( footprintFieldName ) == 0 )
1677 bool hasCurrentValue = currentVariant && currentVariant->
HasFieldValue( fieldName );
1678 wxString currentValue = hasCurrentValue ? currentVariant->
GetFieldValue( fieldName ) : wxString();
1680 if( currentValue != fieldValue )
1684 if( aFootprints.size() > 1 )
1686 msg.Printf(
_(
"Change %s field '%s' to '%s' on variant %s (footprint %s)." ),
1687 footprint->GetReference(),
1691 footprint->GetFPIDAsString() );
1695 msg.Printf(
_(
"Change %s field '%s' to '%s' on variant %s." ),
1696 footprint->GetReference(),
1704 if( aFootprints.size() > 1 )
1706 msg.Printf(
_(
"Changed %s field '%s' to '%s' on variant %s (footprint %s)." ),
1707 footprint->GetReference(),
1711 footprint->GetFPIDAsString() );
1715 msg.Printf(
_(
"Changed %s field '%s' to '%s' on variant %s." ),
1716 footprint->GetReference(),
1723 fpVariant->SetFieldValue( fieldName, fieldValue );
1732 for(
const wxString& excess : excessVariants )
1736 msg.Printf(
_(
"Remove variant %s:%s no longer associated with footprint %s." ),
1737 footprint->GetReference(),
1739 footprint->GetFPIDAsString() );
1743 msg.Printf(
_(
"Removed variant %s:%s no longer associated with footprint %s." ),
1744 footprint->GetReference(),
1746 footprint->GetFPIDAsString() );
1748 footprint->DeleteVariant( excess );
1767 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
1778 std::set<wxString> netlistNetnames;
1780 for(
int ii = 0; ii < (int) aNetlist.
GetCount(); ii++ )
1784 for(
unsigned jj = 0; jj < component->
GetNetCount(); jj++ )
1796 if( netlistNetnames.count(
via->GetNetname() ) == 0 )
1798 wxString updatedNetname = wxEmptyString;
1807 if( !updatedNetname.IsEmpty() )
1811 wxString originalNetname =
via->GetNetname();
1813 msg.Printf(
_(
"Reconnect via from %s to %s." ),
1828 wxString originalNetname =
via->GetNetname();
1831 via->SetNet( netinfo );
1833 msg.Printf(
_(
"Reconnected via from %s to %s." ),
1843 msg.Printf(
_(
"Via connected to unknown net (%s)." ),
1855 auto isInNetlist = [&](
const wxString& aNetName ) ->
bool
1857 if( netlistNetnames.count( aNetName ) )
1862 for(
const wxString& netName : netlistNetnames )
1864 if( aNetName.StartsWith( netName ) )
1874 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
1877 if( !isInNetlist( zone->GetNetname() ) )
1882 wxString updatedNetname = wxEmptyString;
1895 if( updatedNetname.IsEmpty() &&
m_oldToNewNets.count( zone->GetNetname() ) )
1900 if( !updatedNetname.IsEmpty() )
1904 wxString originalNetname = zone->GetNetname();
1906 if( !zone->GetZoneName().IsEmpty() )
1908 msg.Printf(
_(
"Reconnect copper zone '%s' from %s to %s." ),
1909 zone->GetZoneName(),
1915 msg.Printf(
_(
"Reconnect copper zone from %s to %s." ),
1931 wxString originalNetname = zone->GetNetname();
1934 zone->SetNet( netinfo );
1936 if( !zone->GetZoneName().IsEmpty() )
1938 msg.Printf(
_(
"Reconnected copper zone '%s' from %s to %s." ),
1945 msg.Printf(
_(
"Reconnected copper zone from %s to %s." ),
1956 if( !zone->GetZoneName().IsEmpty() )
1958 msg.Printf(
_(
"Copper zone '%s' has no pads connected." ),
1963 wxString layerNames = zone->LayerMaskDescribe();
1968 if(
m_settings->m_Display.m_DisplayInvertXAxis )
1971 if(
m_settings->m_Display.m_DisplayInvertYAxis )
1975 msg.Printf(
_(
"Copper zone on %s at (%s, %s) has no pads connected to net \"%s\"." ),
1985 zone->GetNetname() );
2009 if( netlistGroup ==
nullptr )
2012 if( netlistGroup->
name != pcbGroup->GetName() )
2016 msg.Printf(
_(
"Change group name from '%s' to '%s'." ),
2022 msg.Printf(
_(
"Changed group name from '%s' to '%s'." ),
2026 pcbGroup->SetName( netlistGroup->
name );
2032 if( netlistGroup->
libId != pcbGroup->GetDesignBlockLibId() )
2036 msg.Printf(
_(
"Change group library link from '%s' to '%s'." ),
2037 EscapeHTML( pcbGroup->GetDesignBlockLibId().GetUniStringLibId() ),
2042 msg.Printf(
_(
"Changed group library link from '%s' to '%s'." ),
2043 EscapeHTML( pcbGroup->GetDesignBlockLibId().GetUniStringLibId() ),
2046 pcbGroup->SetDesignBlockLibId( netlistGroup->
libId );
2056 if( member.empty() )
2059 KIID memberGroupUuid =
2066 if( candidate->m_Uuid == memberGroupUuid )
2068 childGroup = candidate;
2073 if( !childGroup || childGroup == pcbGroup || childGroup->
GetParentGroup() == pcbGroup )
2080 msg.Printf(
_(
"Add group '%s' to group '%s'." ),
EscapeHTML( childGroup->
GetName() ),
2085 msg.Printf(
_(
"Added group '%s' to group '%s'." ),
EscapeHTML( childGroup->
GetName() ),
2089 pcbGroup->AddItem( childGroup );
2101 std::map<COMPONENT*, FOOTPRINT*>& aFootprintMap )
2109 for(
int i = 0; i < (int) aNetlist.
GetCount(); i++ )
2112 FOOTPRINT* footprint = aFootprintMap[component];
2118 for(
unsigned jj = 0; jj < component->
GetNetCount(); jj++ )
2122 if( padNumber.IsEmpty() )
2125 msg.Printf(
_(
"Symbol %s has pins with no number. These pins can not be matched "
2135 msg.Printf(
_(
"%s pad %s not found in %s." ),
2151 FOOTPRINT* lastPreexistingFootprint =
nullptr;
2154 std::unordered_set<wxString> sheetPaths;
2155 std::unordered_set<FOOTPRINT*> usedFootprints;
2161 std::map<COMPONENT*, FOOTPRINT*> footprintMap;
2163 if( !
m_board->Footprints().empty() )
2164 lastPreexistingFootprint =
m_board->Footprints().back();
2174 net->SetIsCurrent( net->GetNetCode() == 0 );
2176 m_board->GetComponentClassManager().InitNetlistUpdate();
2180 for(
unsigned ii = 0; ii < aNetlist.
GetCount(); ii++ )
2184 for(
unsigned jj = 0; jj <
comp->GetNetCount(); jj++ )
2191 for(
unsigned i = 0; i < aNetlist.
GetCount(); i++ )
2195 if( component->
GetProperties().count( wxT(
"exclude_from_board" ) ) )
2198 msg.Printf(
_(
"Processing symbol '%s:%s'." ),
2204 const bool hasBaseFpid = !baseFpid.
empty();
2208 msg.Printf(
_(
"Warning: %s footprint '%s' is missing a library name. "
2209 "Use the full 'Library:Footprint' format to avoid repeated update "
2217 std::vector<FOOTPRINT*> matchingFootprints;
2228 base.push_back( uuid );
2230 if( footprint->GetPath() == base )
2239 match = footprint->GetReference().CmpNoCase( component->
GetReference() ) == 0;
2243 matchingFootprints.push_back( footprint );
2245 if( footprint == lastPreexistingFootprint )
2252 std::vector<LIB_ID> expectedFpids;
2253 std::unordered_set<wxString> expectedFpidKeys;
2255 auto addExpectedFpid =
2256 [&](
const LIB_ID& aFpid )
2261 wxString key = aFpid.Format();
2263 if( expectedFpidKeys.insert( key ).second )
2264 expectedFpids.push_back( aFpid );
2267 addExpectedFpid( baseFpid );
2271 for(
const auto& [variantName, variant] : component->
GetVariants() )
2273 auto fieldIt = variant.m_fields.find( footprintFieldName );
2275 if( fieldIt == variant.m_fields.end() || fieldIt->second.IsEmpty() )
2280 if( parsedId.
Parse( fieldIt->second,
true ) >= 0 )
2282 msg.Printf(
_(
"Invalid footprint ID '%s' for variant '%s' on %s." ),
2291 addExpectedFpid( parsedId );
2294 auto isExpectedFpid =
2295 [&](
const LIB_ID& aFpid ) ->
bool
2300 if( expectedFpidKeys.count( aFpid.Format() ) > 0 )
2312 auto takeMatchingFootprint =
2315 for(
FOOTPRINT* footprint : matchingFootprints )
2317 if( usedFootprints.count( footprint ) )
2327 std::vector<FOOTPRINT*> componentFootprints;
2328 componentFootprints.reserve( expectedFpids.size() );
2332 baseFootprint = takeMatchingFootprint( baseFpid );
2333 else if( !matchingFootprints.empty() )
2334 baseFootprint = matchingFootprints.front();
2340 for(
FOOTPRINT* footprint : matchingFootprints )
2342 if( usedFootprints.count( footprint ) )
2345 if( isExpectedFpid( footprint->GetFPID() ) )
2348 replaceCandidate = footprint;
2352 if( replaceCandidate )
2357 baseFootprint = replaced;
2359 baseFootprint = replaceCandidate;
2365 for(
FOOTPRINT* footprint : matchingFootprints )
2367 if( usedFootprints.count( footprint ) )
2370 if( isExpectedFpid( footprint->GetFPID() ) )
2373 baseFootprint = footprint;
2378 if( !baseFootprint && ( hasBaseFpid || expectedFpids.empty() ) )
2383 componentFootprints.push_back( baseFootprint );
2384 usedFootprints.insert( baseFootprint );
2385 footprintMap[ component ] = baseFootprint;
2388 for(
const LIB_ID& fpid : expectedFpids )
2396 FOOTPRINT* footprint = takeMatchingFootprint( fpid );
2403 componentFootprints.push_back( footprint );
2404 usedFootprints.insert( footprint );
2408 for(
FOOTPRINT* footprint : componentFootprints )
2419 sheetPaths.insert( footprint->GetSheetname() );
2422 if( !componentFootprints.empty() )
2434 bool matched =
false;
2440 bool isStaleVariantFootprint =
false;
2442 if( usedFootprints.count( footprint ) )
2453 if( component && component->
GetProperties().count( wxT(
"exclude_from_board" ) ) == 0 )
2461 isStaleVariantFootprint =
true;
2472 if( isStaleVariantFootprint )
2475 if( doDelete && !matched && footprint->IsLocked() && !
m_overrideLocks )
2479 msg.Printf(
_(
"Cannot remove unused footprint %s (footprint is locked)." ),
2480 footprint->GetReference() );
2484 msg.Printf(
_(
"Could not remove unused footprint %s (footprint is locked)." ),
2485 footprint->GetReference() );
2493 if( doDelete && !matched )
2497 msg.Printf(
_(
"Remove unused footprint %s." ),
2498 footprint->GetReference() );
2503 msg.Printf(
_(
"Removed unused footprint %s." ),
2504 footprint->GetReference() );
2514 for(
PAD*
pad : footprint->Pads() )
2517 pad->GetNet()->SetIsCurrent(
true );
2525 m_board->GetComponentClassManager().FinishNetlistUpdate();
2526 m_board->SynchronizeComponentClasses( sheetPaths );
2533 if( !net->IsCurrent() )
2535 msg.Printf(
_(
"Removed unused net %s." ),
2544 const std::vector<wxString>& netlistVariants = aNetlist.
GetVariantNames();
2546 if( !netlistVariants.empty() || !
m_board->GetVariantNames().empty() )
2550 auto findBoardVariantName =
2551 [&](
const wxString& aVariantName ) -> wxString
2553 for(
const wxString&
name :
m_board->GetVariantNames() )
2555 if(
name.CmpNoCase( aVariantName ) == 0 )
2559 return wxEmptyString;
2562 std::vector<wxString> updatedVariantNames;
2563 updatedVariantNames.reserve( netlistVariants.size() );
2565 for(
const wxString& variantName : netlistVariants )
2567 wxString actualName = findBoardVariantName( variantName );
2569 if( actualName.IsEmpty() )
2571 m_board->AddVariant( variantName );
2572 actualName = findBoardVariantName( variantName );
2574 if( !actualName.IsEmpty() )
2576 msg.Printf(
_(
"Added variant '%s'." ), actualName );
2581 if( actualName.IsEmpty() )
2586 wxString oldDescription =
m_board->GetVariantDescription( actualName );
2588 if( newDescription != oldDescription )
2590 m_board->SetVariantDescription( actualName, newDescription );
2591 msg.Printf(
_(
"Updated description for variant '%s'." ), actualName );
2595 updatedVariantNames.push_back( actualName );
2598 std::vector<wxString> variantsToRemove;
2600 for(
const wxString& existingName :
m_board->GetVariantNames() )
2604 for(
const wxString& variantName : netlistVariants )
2606 if( existingName.CmpNoCase( variantName ) == 0 )
2614 variantsToRemove.push_back( existingName );
2617 for(
const wxString& variantName : variantsToRemove )
2619 m_board->DeleteVariant( variantName );
2620 msg.Printf(
_(
"Removed variant '%s'." ), variantName );
2624 if( !updatedVariantNames.empty() )
2625 m_board->SetVariantNames( updatedVariantNames );
2644 if( !colorStr.IsEmpty() )
2657 m_board->SynchronizeNetsAndNetClasses(
true );
2661 PAD* pads[2] = {
nullptr,
nullptr };
2663 for(
size_t i = 0; i < sig.second.size() && i < 2; ++i )
2665 const wxString& ref = sig.second[i].first;
2666 const wxString&
pin = sig.second[i].second;
2672 PAD* candidate =
nullptr;
2673 PAD* best =
nullptr;
2674 int bestDist = std::numeric_limits<int>::max();
2683 if( !best || dist < bestDist || ( dist == bestDist && candidate->
m_Uuid < best->
m_Uuid ) )
2693 for(
int i = 0; i < 2; ++i )
2700 if( !termNet || termNet->
GetNetChain() != sig.first )
2705 if( net != termNet && net->
GetNetChain() == sig.first
2706 && net->GetTerminalPad( i ) )
2708 net->ClearTerminalPad( i );
2724 for(
const std::pair<const wxString, NETINFO_ITEM*>& addedNet :
m_addedNets )
2725 delete addedNet.second;
constexpr EDA_IU_SCALE pcbIUScale
wxString GetNetname() const
NETINFO_ITEM * GetNet() const
Return NETINFO_ITEM object for a given item.
std::shared_ptr< NET_SETTINGS > m_NetSettings
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.
static void ApplyChainNetclasses(BOARD *aBoard, const NETLIST &aNetlist)
Mirror the netlist's chain-to-class and chain-to-netclass maps into the project's NET_SETTINGS.
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
BOARD_DESIGN_SETTINGS & GetDesignSettings() 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()
JUMPER_GROUP_SET & 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
static KIID FromName(const std::string &aName)
Return a KIID derived from a name, the same name always gives the same KIID.
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
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_hasExcludedFromSim
bool m_hasExcludedFromPosFiles
nlohmann::ordered_map< wxString, wxString > m_fields
std::vector< KIID > members
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
@ 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".
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