134 bestPosition.
x = pageSize.
x / 2;
135 bestPosition.
y = pageSize.
y / 2;
152 if( aFootprintId.
empty() )
154 msg.Printf(
_(
"Cannot add %s (no footprint assigned)." ),
163 if( footprint ==
nullptr )
165 msg.Printf(
_(
"Cannot add %s (footprint '%s' not found)." ),
174 m_board->GetComponentClassManager().GetNoneComponentClass() );
178 msg.Printf(
_(
"Add %s (footprint '%s')." ),
190 pad->SetLocalRatsnestVisible(
m_frame->GetPcbNewSettings()->m_Display.m_ShowGlobalRatsnest );
193 pad->SetNetCode( 0 );
208 msg.Printf(
_(
"Added %s (footprint '%s')." ),
221 wxString curClassName, newClassName;
225 curClassName = curClass->
GetName();
235 newClass =
m_board->GetComponentClassManager().GetEffectiveStaticComponentClass(
237 newClassName = newClass->
GetName();
240 if( curClassName == newClassName )
249 copy->SetParentGroup(
nullptr );
256 if( curClassName == wxEmptyString && newClassName != wxEmptyString )
258 msg.Printf(
_(
"Change %s component class to '%s'." ),
262 else if( curClassName != wxEmptyString && newClassName == wxEmptyString )
264 msg.Printf(
_(
"Remove %s component class (currently '%s')." ),
270 msg.Printf(
_(
"Change %s component class from '%s' to '%s'." ),
278 wxASSERT_MSG( newClass !=
nullptr,
"Component class should not be nullptr" );
282 if( curClassName == wxEmptyString && newClassName != wxEmptyString )
284 msg.Printf(
_(
"Changed %s component class to '%s'." ),
288 else if( curClassName != wxEmptyString && newClassName == wxEmptyString )
290 msg.Printf(
_(
"Removed %s component class (was '%s')." ),
296 msg.Printf(
_(
"Changed %s component class from '%s' to '%s'." ),
319 msg.Printf(
_(
"Cannot update %s (no footprint assigned)." ),
328 if( newFootprint ==
nullptr )
330 msg.Printf(
_(
"Cannot update %s (footprint '%s' not found)." ),
342 msg.Printf(
_(
"Cannot change %s footprint from '%s' to '%s' (footprint is locked)."),
353 msg.Printf(
_(
"Change %s footprint from '%s' to '%s'."),
367 msg.Printf(
_(
"Could not change %s footprint from '%s' to '%s' (footprint is locked)."),
381 m_frame->ExchangeFootprint( aFootprint, newFootprint,
m_commit,
true );
383 msg.Printf(
_(
"Changed %s footprint from '%s' to '%s'."),
408 firstAssociatedVariant = &
test;
417 if( !
m_commit.GetStatus( aFootprint ) )
420 copy->SetParentGroup(
nullptr );
423 bool changed =
false;
430 msg.Printf(
_(
"Change %s reference designator to %s." ),
436 msg.Printf(
_(
"Changed %s reference designator to %s." ),
448 wxString netlistValue = aNetlistComponent->
GetValue();
450 if( firstAssociatedVariant !=
nullptr
456 if( aFootprint->
GetValue() != netlistValue )
460 msg.Printf(
_(
"Change %s value from %s to %s." ),
467 msg.Printf(
_(
"Changed %s value from %s to %s." ),
473 aFootprint->
SetValue( netlistValue );
482 if( !aNetlistComponent->
GetKIIDs().empty() )
483 new_path.push_back( aNetlistComponent->
GetKIIDs().front() );
485 if( aFootprint->
GetPath() != new_path )
489 msg.Printf(
_(
"Update %s symbol association from %s to %s." ),
496 msg.Printf(
_(
"Updated %s symbol association from %s to %s." ),
502 aFootprint->
SetPath( new_path );
508 nlohmann::ordered_map<wxString, wxString> fpFieldsAsMap;
513 if( field->IsReference() || field->IsValue() || field->IsComponentClass() )
518 fpFieldsAsMap[field->GetName()] = field->GetText();
522 nlohmann::ordered_map<wxString, wxString> compFields = aNetlistComponent->
GetFields();
528 compFields.erase( wxT(
"Component Class" ) );
530 if( firstAssociatedVariant !=
nullptr )
532 for(
const auto& [
name, value] : firstAssociatedVariant->
m_fields )
533 compFields[
name] = value;
539 bool remove_only =
true;
541 for(
const auto& [
name, value] : compFields )
543 if( fpFieldsAsMap.count(
name ) == 0 || fpFieldsAsMap[
name] != value )
551 for(
const auto& [
name, value] : fpFieldsAsMap )
553 if( compFields.count(
name ) == 0 )
566 msg.Printf(
_(
"Update %s fields." ), aFootprint->
GetReference() );
573 if( field->IsMandatory() )
576 if( compFields.count( field->GetName() ) == 0 )
580 msg.Printf(
_(
"Remove %s footprint fields not in symbol." ), aFootprint->
GetReference() );
592 msg.Printf(
_(
"Updated %s fields." ), aFootprint->
GetReference() );
598 for(
auto& [
name, value] : compFields )
607 aFootprint->
Add( newField );
629 std::vector<PCB_FIELD*> fieldList;
630 aFootprint->
GetFields( fieldList,
false );
634 if( field->IsMandatory() )
637 if( compFields.count( field->GetName() ) == 0 )
642 msg.Printf(
_(
"Removed %s footprint fields not in symbol." ), aFootprint->
GetReference() );
646 aFootprint->
Remove( field );
649 m_frame->GetCanvas()->GetView()->Remove( field );
664 if( !humanSheetPath.empty() )
665 sheetname = humanSheetPath;
666 else if( aNetlistComponent->
GetProperties().count( wxT(
"Sheetname" ) ) > 0 )
667 sheetname = aNetlistComponent->
GetProperties().at( wxT(
"Sheetname" ) );
669 if( aNetlistComponent->
GetProperties().count( wxT(
"Sheetfile" ) ) > 0 )
670 sheetfile = aNetlistComponent->
GetProperties().at( wxT(
"Sheetfile" ) );
672 if( aNetlistComponent->
GetProperties().count( wxT(
"ki_fp_filters" ) ) > 0 )
673 fpFilters = aNetlistComponent->
GetProperties().at( wxT(
"ki_fp_filters" ) );
679 msg.Printf(
_(
"Update %s sheetname to '%s'." ),
686 msg.Printf(
_(
"Updated %s sheetname to '%s'." ),
698 msg.Printf(
_(
"Update %s sheetfile to '%s'." ),
705 msg.Printf(
_(
"Updated %s sheetfile to '%s'." ),
717 msg.Printf(
_(
"Update %s footprint filters to '%s'." ),
724 msg.Printf(
_(
"Updated %s footprint filters to '%s'." ),
732 bool netlistExcludeFromBOM = aNetlistComponent->
GetProperties().count( wxT(
"exclude_from_bom" ) ) > 0;
741 if( netlistExcludeFromBOM )
742 msg.Printf(
_(
"Add %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
744 msg.Printf(
_(
"Remove %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
750 if( netlistExcludeFromBOM )
753 msg.Printf(
_(
"Added %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
758 msg.Printf(
_(
"Removed %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
768 bool netlistDNP = aNetlistComponent->
GetProperties().count( wxT(
"dnp" ) ) > 0;
770 if( firstAssociatedVariant !=
nullptr && firstAssociatedVariant->
m_hasDnp )
771 netlistDNP = firstAssociatedVariant->
m_dnp;
778 msg.Printf(
_(
"Add %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
780 msg.Printf(
_(
"Remove %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
789 msg.Printf(
_(
"Added %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
794 msg.Printf(
_(
"Removed %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
804 bool netlistExcludeFromPosFiles = aNetlistComponent->
GetProperties().count( wxT(
"exclude_from_pos_files" ) ) > 0;
813 if( netlistExcludeFromPosFiles )
815 msg.Printf(
_(
"Add %s 'exclude from position files' fabrication attribute." ),
820 msg.Printf(
_(
"Remove %s 'exclude from position files' fabrication attribute." ),
828 if( netlistExcludeFromPosFiles )
831 msg.Printf(
_(
"Added %s 'exclude from position files' fabrication attribute." ),
837 msg.Printf(
_(
"Removed %s 'exclude from position files' fabrication attribute." ),
860 msg.Printf(
_(
"Added %s 'duplicate pad numbers are jumpers' attribute." ),
865 msg.Printf(
_(
"Removed %s 'duplicate pad numbers are jumpers' attribute." ),
873 msg.Printf(
_(
"Add %s 'duplicate pad numbers are jumpers' attribute." ),
878 msg.Printf(
_(
"Remove %s 'duplicate pad numbers are jumpers' attribute." ),
892 msg.Printf(
_(
"Updated %s jumper pad groups" ), aFootprint->
GetReference() );
896 msg.Printf(
_(
"Update %s jumper pad groups" ), aFootprint->
GetReference() );
902 if( changed &&
copy )
922 if( !
m_commit.GetStatus( aPcbFootprint ) )
925 copy->SetParentGroup(
nullptr );
928 bool changed =
false;
937 KIID existingGroupKIID = existingGroup ? existingGroup->
m_Uuid : 0;
940 auto it = std::find_if(
m_board->Groups().begin(),
m_board->Groups().end(),
942 return group->m_Uuid == newGroupKIID;
946 if( it !=
m_board->Groups().end() )
950 if( newGroupKIID == existingGroupKIID )
954 if( existingGroupKIID != 0 )
958 msg.Printf(
_(
"Remove %s from group '%s'." ),
964 msg.Printf(
_(
"Removed %s from group '%s'." ),
972 if( existingGroup->
GetItems().size() < 2 )
983 if( newGroupKIID != 0 )
987 msg.Printf(
_(
"Add %s to group '%s'." ),
993 msg.Printf(
_(
"Added %s to group '%s'." ),
999 if( newGroup ==
nullptr )
1002 newGroup->
SetUuid( newGroupKIID );
1015 newGroup->
AddItem( aPcbFootprint );
1021 if( changed &&
copy )
1041 copy->SetParentGroup(
nullptr );
1044 bool changed =
false;
1047 std::deque<PAD*> pads = aFootprint->
Pads();
1048 std::set<wxString> padNetnames;
1050 std::sort( pads.begin(), pads.end(),
1053 return a->m_Uuid < b->m_Uuid;
1060 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1061 wxT(
"Processing pad %s of component %s" ),
1065 wxString pinFunction;
1070 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1071 wxT(
" Found valid net: %s" ),
1078 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1079 wxT(
" No net found for pad %s" ),
1085 if(
pad->GetPinFunction() != pinFunction )
1088 pad->SetPinFunction( pinFunction );
1091 if(
pad->GetPinType() != pinType )
1094 pad->SetPinType( pinType );
1103 if( !net.
IsValid() || !
pad->IsOnCopperLayer() )
1105 if( !
pad->GetNetname().IsEmpty() )
1109 msg.Printf(
_(
"Disconnect %s pin %s." ),
1115 msg.Printf(
_(
"Disconnected %s pin %s." ),
1122 else if(
pad->IsOnCopperLayer() && !
pad->GetNumber().IsEmpty() )
1125 msg.Printf(
_(
"No net found for component %s pad %s (no pin %s in symbol)." ),
1140 if(
pad->GetNetname().IsEmpty() )
1141 pad->SetPinFunction( wxEmptyString );
1153 if(
pad->IsNoConnectPad() )
1155 netName = wxString::Format( wxS(
"%s" ), net.
GetNetName() );
1157 for(
int jj = 1; !padNetnames.insert( netName ).second; jj++ )
1159 netName = wxString::Format( wxS(
"%s_%d" ), net.
GetNetName(), jj );
1168 if(
pad->GetNetname() != netName )
1171 if( netinfo ==
nullptr )
1178 if( netinfo ==
nullptr )
1190 msg.Printf(
_(
"Add net %s." ),
1195 if( !
pad->GetNetname().IsEmpty() )
1201 msg.Printf(
_(
"Reconnect %s pin %s from %s to %s."),
1209 msg.Printf(
_(
"Reconnected %s pin %s from %s to %s."),
1220 msg.Printf(
_(
"Connect %s pin %s to %s."),
1227 msg.Printf(
_(
"Connected %s pin %s to %s."),
1239 pad->SetNet( netinfo );
1249 if( changed &&
copy )
1261 std::vector<FOOTPRINT::FP_UNIT_INFO> newUnits;
1264 newUnits.push_back( { u.m_unitName, u.m_pins } );
1266 const std::vector<FOOTPRINT::FP_UNIT_INFO>& curUnits = aFootprint->
GetUnitInfo();
1268 auto unitsEqual = [](
const std::vector<FOOTPRINT::FP_UNIT_INFO>& a,
1269 const std::vector<FOOTPRINT::FP_UNIT_INFO>& b )
1271 if( a.size() != b.size() )
1274 for(
size_t i = 0; i < a.size(); ++i )
1276 if( a[i].m_unitName != b[i].m_unitName )
1279 if( a[i].m_pins != b[i].m_pins )
1286 if( unitsEqual( curUnits, newUnits ) )
1293 msg.Printf(
_(
"Update %s unit metadata." ), aFootprint->
GetReference() );
1301 if( !
m_commit.GetStatus( aFootprint ) )
1304 copy->SetParentGroup(
nullptr );
1309 msg.Printf(
_(
"Updated %s unit metadata." ), aFootprint->
GetReference() );
1320 const std::vector<FOOTPRINT*>& aFootprints,
1321 const LIB_ID& aBaseFpid )
1326 if( aBaseFpid.
empty() )
1338 std::vector<VARIANT_INFO> variantInfo;
1339 variantInfo.reserve( variants.size() );
1341 for(
const auto& [variantName, variant] : variants )
1343 LIB_ID variantFPID = aBaseFpid;
1345 auto fieldIt = variant.m_fields.find( footprintFieldName );
1347 if( fieldIt != variant.m_fields.end() && !fieldIt->second.IsEmpty() )
1351 if( parsedId.
Parse( fieldIt->second,
true ) >= 0 )
1353 msg.Printf(
_(
"Invalid footprint ID '%s' for variant '%s' on %s." ),
1362 variantFPID = parsedId;
1366 variantInfo.push_back( { variantName, &variant, variantFPID } );
1369 for(
FOOTPRINT* footprint : aFootprints )
1379 copy->SetParentGroup(
nullptr );
1382 bool changed =
false;
1384 auto printAttributeMessage =
1385 [&](
bool add,
const wxString& attrName,
const wxString& variantName )
1389 if( aFootprints.size() > 1 )
1391 msg.Printf( add ?
_(
"Add %s '%s' attribute to variant %s (footprint %s)." )
1392 :
_(
"Remove %s '%s' attribute from variant %s (footprint %s)." ),
1393 footprint->GetReference(),
1396 footprint->GetFPIDAsString() );
1400 msg.Printf( add ?
_(
"Add %s '%s' attribute to variant %s." )
1401 :
_(
"Remove %s '%s' attribute from variant %s." ),
1402 footprint->GetReference(),
1409 if( aFootprints.size() > 1 )
1411 msg.Printf( add ?
_(
"Added %s '%s' attribute to variant %s (footprint %s)." )
1412 :
_(
"Removed %s '%s' attribute from variant %s (footprint %s)." ),
1413 footprint->GetReference(),
1416 footprint->GetFPIDAsString() );
1420 msg.Printf( add ?
_(
"Added %s '%s' attribute to variant %s." )
1421 :
_(
"Removed %s '%s' attribute from variant %s." ),
1422 footprint->GetReference(),
1429 std::set<wxString> excessVariants;
1431 for(
const auto& [variantName,
_] : footprint->GetVariants() )
1432 excessVariants.insert( variantName );
1434 for(
const VARIANT_INFO&
info : variantInfo )
1442 bool isAssociatedFootprint = ( footprint->GetFPID() ==
info.variantFPID );
1447 if( !isAssociatedFootprint )
1450 excessVariants.erase(
info.name );
1451 bool targetDnp = variant.
m_hasDnp ? variant.
m_dnp : footprint->IsDNP();
1452 bool currentDnp = currentVariant ? currentVariant->
GetDNP() : footprint->IsDNP();
1454 if( currentDnp != targetDnp )
1456 printAttributeMessage( targetDnp,
_(
"Do not place" ),
info.name );
1461 fpVariant->SetDNP( targetDnp );
1469 : footprint->IsExcludedFromBOM();
1471 : footprint->IsExcludedFromBOM();
1473 if( currentExcludedFromBOM != targetExcludedFromBOM )
1475 printAttributeMessage( targetExcludedFromBOM,
_(
"exclude from BOM" ),
info.name );
1480 fpVariant->SetExcludedFromBOM( targetExcludedFromBOM );
1488 : footprint->IsExcludedFromPosFiles();
1490 : footprint->IsExcludedFromPosFiles();
1492 if( currentExcludedFromPosFiles != targetExcludedFromPosFiles )
1494 printAttributeMessage( targetExcludedFromPosFiles,
_(
"exclude from position files" ),
info.name );
1499 fpVariant->SetExcludedFromPosFiles( targetExcludedFromPosFiles );
1506 for(
const auto& [fieldName, fieldValue] : variant.
m_fields )
1508 if( fieldName.CmpNoCase( footprintFieldName ) == 0 )
1511 bool hasCurrentValue = currentVariant && currentVariant->
HasFieldValue( fieldName );
1512 wxString currentValue = hasCurrentValue ? currentVariant->
GetFieldValue( fieldName ) : wxString();
1514 if( currentValue != fieldValue )
1518 if( aFootprints.size() > 1 )
1520 msg.Printf(
_(
"Change %s field '%s' to '%s' on variant %s (footprint %s)." ),
1521 footprint->GetReference(),
1525 footprint->GetFPIDAsString() );
1529 msg.Printf(
_(
"Change %s field '%s' to '%s' on variant %s." ),
1530 footprint->GetReference(),
1538 if( aFootprints.size() > 1 )
1540 msg.Printf(
_(
"Changed %s field '%s' to '%s' on variant %s (footprint %s)." ),
1541 footprint->GetReference(),
1545 footprint->GetFPIDAsString() );
1549 msg.Printf(
_(
"Changed %s field '%s' to '%s' on variant %s." ),
1550 footprint->GetReference(),
1557 fpVariant->SetFieldValue( fieldName, fieldValue );
1566 for(
const wxString& excess : excessVariants )
1570 msg.Printf(
_(
"Remove variant %s:%s no longer associated with footprint %s." ),
1571 footprint->GetReference(),
1573 footprint->GetFPIDAsString() );
1577 msg.Printf(
_(
"Removed variant %s:%s no longer associated with footprint %s." ),
1578 footprint->GetReference(),
1580 footprint->GetFPIDAsString() );
1582 footprint->DeleteVariant( excess );
1591 bool isBaseFootprint = ( footprint->GetFPID() == aBaseFpid );
1593 if( !isBaseFootprint && !footprint->IsDNP() )
1595 msg.Printf(
m_isDryRun ?
_(
"Add %s 'Do not place' fabrication attribute." )
1596 :
_(
"Added %s 'Do not place' fabrication attribute." ),
1597 footprint->GetReference() );
1602 footprint->SetDNP(
true );
1619 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
1630 std::set<wxString> netlistNetnames;
1632 for(
int ii = 0; ii < (int) aNetlist.
GetCount(); ii++ )
1636 for(
unsigned jj = 0; jj < component->
GetNetCount(); jj++ )
1648 if( netlistNetnames.count(
via->GetNetname() ) == 0 )
1650 wxString updatedNetname = wxEmptyString;
1659 if( !updatedNetname.IsEmpty() )
1663 wxString originalNetname =
via->GetNetname();
1665 msg.Printf(
_(
"Reconnect via from %s to %s." ),
1680 wxString originalNetname =
via->GetNetname();
1683 via->SetNet( netinfo );
1685 msg.Printf(
_(
"Reconnected via from %s to %s." ),
1695 msg.Printf(
_(
"Via connected to unknown net (%s)." ),
1707 auto isInNetlist = [&](
const wxString& aNetName ) ->
bool
1709 if( netlistNetnames.count( aNetName ) )
1714 for(
const wxString& netName : netlistNetnames )
1716 if( aNetName.StartsWith( netName ) )
1726 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
1729 if( !isInNetlist( zone->GetNetname() ) )
1734 wxString updatedNetname = wxEmptyString;
1747 if( updatedNetname.IsEmpty() &&
m_oldToNewNets.count( zone->GetNetname() ) )
1752 if( !updatedNetname.IsEmpty() )
1756 wxString originalNetname = zone->GetNetname();
1758 if( !zone->GetZoneName().IsEmpty() )
1760 msg.Printf(
_(
"Reconnect copper zone '%s' from %s to %s." ),
1761 zone->GetZoneName(),
1767 msg.Printf(
_(
"Reconnect copper zone from %s to %s." ),
1783 wxString originalNetname = zone->GetNetname();
1786 zone->SetNet( netinfo );
1788 if( !zone->GetZoneName().IsEmpty() )
1790 msg.Printf(
_(
"Reconnected copper zone '%s' from %s to %s." ),
1797 msg.Printf(
_(
"Reconnected copper zone from %s to %s." ),
1808 if( !zone->GetZoneName().IsEmpty() )
1810 msg.Printf(
_(
"Copper zone '%s' has no pads connected." ),
1815 wxString layerNames = zone->LayerMaskDescribe();
1820 if(
m_frame->GetPcbNewSettings()->m_Display.m_DisplayInvertXAxis )
1823 if(
m_frame->GetPcbNewSettings()->m_Display.m_DisplayInvertYAxis )
1827 msg.Printf(
_(
"Copper zone on %s at (%s, %s) has no pads connected to net \"%s\"." ),
1833 zone->GetNetname() );
1857 if( netlistGroup ==
nullptr )
1860 if( netlistGroup->
name != pcbGroup->GetName() )
1864 msg.Printf(
_(
"Change group name from '%s' to '%s'." ),
1870 msg.Printf(
_(
"Changed group name from '%s' to '%s'." ),
1874 pcbGroup->SetName( netlistGroup->
name );
1880 if( netlistGroup->
libId != pcbGroup->GetDesignBlockLibId() )
1884 msg.Printf(
_(
"Change group library link from '%s' to '%s'." ),
1885 EscapeHTML( pcbGroup->GetDesignBlockLibId().GetUniStringLibId() ),
1890 msg.Printf(
_(
"Changed group library link from '%s' to '%s'." ),
1891 EscapeHTML( pcbGroup->GetDesignBlockLibId().GetUniStringLibId() ),
1894 pcbGroup->SetDesignBlockLibId( netlistGroup->
libId );
1906 std::map<COMPONENT*, FOOTPRINT*>& aFootprintMap )
1914 for(
int i = 0; i < (int) aNetlist.
GetCount(); i++ )
1917 FOOTPRINT* footprint = aFootprintMap[component];
1923 for(
unsigned jj = 0; jj < component->
GetNetCount(); jj++ )
1927 if( padNumber.IsEmpty() )
1930 msg.Printf(
_(
"Symbol %s has pins with no number. These pins can not be matched "
1940 msg.Printf(
_(
"%s pad %s not found in %s." ),
1956 FOOTPRINT* lastPreexistingFootprint =
nullptr;
1959 std::unordered_set<wxString> sheetPaths;
1960 std::unordered_set<FOOTPRINT*> usedFootprints;
1966 std::map<COMPONENT*, FOOTPRINT*> footprintMap;
1968 if( !
m_board->Footprints().empty() )
1969 lastPreexistingFootprint =
m_board->Footprints().back();
1979 net->SetIsCurrent( net->GetNetCode() == 0 );
1981 m_board->GetComponentClassManager().InitNetlistUpdate();
1987 for(
unsigned i = 0; i < aNetlist.
GetCount(); i++ )
1991 if( component->
GetProperties().count( wxT(
"exclude_from_board" ) ) )
1994 msg.Printf(
_(
"Processing symbol '%s:%s'." ),
2000 const bool hasBaseFpid = !baseFpid.
empty();
2004 msg.Printf(
_(
"Warning: %s footprint '%s' is missing a library name. "
2005 "Use the full 'Library:Footprint' format to avoid repeated update "
2013 std::vector<FOOTPRINT*> matchingFootprints;
2024 base.push_back( uuid );
2026 if( footprint->GetPath() == base )
2035 match = footprint->GetReference().CmpNoCase( component->
GetReference() ) == 0;
2039 matchingFootprints.push_back( footprint );
2041 if( footprint == lastPreexistingFootprint )
2048 std::vector<LIB_ID> expectedFpids;
2049 std::unordered_set<wxString> expectedFpidKeys;
2051 auto addExpectedFpid =
2052 [&](
const LIB_ID& aFpid )
2057 wxString key = aFpid.Format();
2059 if( expectedFpidKeys.insert( key ).second )
2060 expectedFpids.push_back( aFpid );
2063 addExpectedFpid( baseFpid );
2067 for(
const auto& [variantName, variant] : component->
GetVariants() )
2069 auto fieldIt = variant.m_fields.find( footprintFieldName );
2071 if( fieldIt == variant.m_fields.end() || fieldIt->second.IsEmpty() )
2076 if( parsedId.
Parse( fieldIt->second,
true ) >= 0 )
2078 msg.Printf(
_(
"Invalid footprint ID '%s' for variant '%s' on %s." ),
2087 addExpectedFpid( parsedId );
2095 [&](
const LIB_ID& aBoardFpid,
const LIB_ID& aExpectedFpid ) ->
bool
2097 if( aExpectedFpid.IsLegacy() )
2098 return aBoardFpid.
GetLibItemName() == aExpectedFpid.GetLibItemName();
2100 return aBoardFpid == aExpectedFpid;
2103 auto isExpectedFpid =
2104 [&](
const LIB_ID& aFpid ) ->
bool
2109 if( expectedFpidKeys.count( aFpid.Format() ) > 0 )
2114 if( fpidMatches( aFpid,
expected ) )
2121 auto takeMatchingFootprint =
2124 for(
FOOTPRINT* footprint : matchingFootprints )
2126 if( usedFootprints.count( footprint ) )
2129 if( fpidMatches( footprint->GetFPID(), aFpid ) )
2136 std::vector<FOOTPRINT*> componentFootprints;
2137 componentFootprints.reserve( expectedFpids.size() );
2141 baseFootprint = takeMatchingFootprint( baseFpid );
2142 else if( !matchingFootprints.empty() )
2143 baseFootprint = matchingFootprints.front();
2149 for(
FOOTPRINT* footprint : matchingFootprints )
2151 if( usedFootprints.count( footprint ) )
2154 if( isExpectedFpid( footprint->GetFPID() ) )
2157 replaceCandidate = footprint;
2161 if( replaceCandidate )
2166 baseFootprint = replaced;
2168 baseFootprint = replaceCandidate;
2172 if( !baseFootprint && hasBaseFpid )
2177 componentFootprints.push_back( baseFootprint );
2178 usedFootprints.insert( baseFootprint );
2179 footprintMap[ component ] = baseFootprint;
2182 for(
const LIB_ID& fpid : expectedFpids )
2184 if( fpid == baseFpid )
2187 FOOTPRINT* footprint = takeMatchingFootprint( fpid );
2194 componentFootprints.push_back( footprint );
2195 usedFootprints.insert( footprint );
2199 for(
FOOTPRINT* footprint : componentFootprints )
2210 sheetPaths.insert( footprint->GetSheetname() );
2213 if( !componentFootprints.empty() )
2225 bool matched =
false;
2231 bool isStaleVariantFootprint =
false;
2233 if( usedFootprints.count( footprint ) )
2244 if( component && component->
GetProperties().count( wxT(
"exclude_from_board" ) ) == 0 )
2252 isStaleVariantFootprint =
true;
2263 if( isStaleVariantFootprint )
2266 if( doDelete && !matched && footprint->IsLocked() && !
m_overrideLocks )
2270 msg.Printf(
_(
"Cannot remove unused footprint %s (footprint is locked)." ),
2271 footprint->GetReference() );
2275 msg.Printf(
_(
"Could not remove unused footprint %s (footprint is locked)." ),
2276 footprint->GetReference() );
2284 if( doDelete && !matched )
2288 msg.Printf(
_(
"Remove unused footprint %s." ),
2289 footprint->GetReference() );
2294 msg.Printf(
_(
"Removed unused footprint %s." ),
2295 footprint->GetReference() );
2305 for(
PAD*
pad : footprint->Pads() )
2308 pad->GetNet()->SetIsCurrent(
true );
2316 m_board->GetComponentClassManager().FinishNetlistUpdate();
2317 m_board->SynchronizeComponentClasses( sheetPaths );
2324 if( !net->IsCurrent() )
2326 msg.Printf(
_(
"Removed unused net %s." ),
2335 const std::vector<wxString>& netlistVariants = aNetlist.
GetVariantNames();
2337 if( !netlistVariants.empty() || !
m_board->GetVariantNames().empty() )
2341 auto findBoardVariantName =
2342 [&](
const wxString& aVariantName ) -> wxString
2344 for(
const wxString&
name :
m_board->GetVariantNames() )
2346 if(
name.CmpNoCase( aVariantName ) == 0 )
2350 return wxEmptyString;
2353 std::vector<wxString> updatedVariantNames;
2354 updatedVariantNames.reserve( netlistVariants.size() );
2356 for(
const wxString& variantName : netlistVariants )
2358 wxString actualName = findBoardVariantName( variantName );
2360 if( actualName.IsEmpty() )
2362 m_board->AddVariant( variantName );
2363 actualName = findBoardVariantName( variantName );
2365 if( !actualName.IsEmpty() )
2367 msg.Printf(
_(
"Added variant '%s'." ), actualName );
2372 if( actualName.IsEmpty() )
2377 wxString oldDescription =
m_board->GetVariantDescription( actualName );
2379 if( newDescription != oldDescription )
2381 m_board->SetVariantDescription( actualName, newDescription );
2382 msg.Printf(
_(
"Updated description for variant '%s'." ), actualName );
2386 updatedVariantNames.push_back( actualName );
2389 std::vector<wxString> variantsToRemove;
2391 for(
const wxString& existingName :
m_board->GetVariantNames() )
2395 for(
const wxString& variantName : netlistVariants )
2397 if( existingName.CmpNoCase( variantName ) == 0 )
2405 variantsToRemove.push_back( existingName );
2408 for(
const wxString& variantName : variantsToRemove )
2410 m_board->DeleteVariant( variantName );
2411 msg.Printf(
_(
"Removed variant '%s'." ), variantName );
2415 if( !updatedVariantNames.empty() )
2416 m_board->SetVariantNames( updatedVariantNames );
2426 m_board->SynchronizeNetsAndNetClasses(
true );
2437 for(
const std::pair<const wxString, NETINFO_ITEM*>& addedNet :
m_addedNets )
2438 delete addedNet.second;
constexpr EDA_IU_SCALE pcbIUScale
wxString GetNetname() const
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
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
bool updateFootprintGroup(FOOTPRINT *aPcbFootprint, COMPONENT *aNetlistComponent)
std::map< wxString, NETINFO_ITEM * > m_addedNets
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)
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)
Information pertinent to a Pcbnew printed circuit board.
constexpr size_type GetWidth() const
constexpr Vec Centre() const
constexpr size_type GetHeight() 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)
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.
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::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.
NETLIST_GROUP * GetGroupByUuid(const KIID &aUuid)
Return a NETLIST_GROUP by aUuid.
COMPONENT * GetComponent(unsigned aIndex)
Return the COMPONENT at aIndex.
wxString GetVariantDescription(const wxString &aVariantName) const
static REPORTER & GetInstance()
const wxString & GetPinFunction() const
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.
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.
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
@ 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)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
VECTOR2< int32_t > VECTOR2I