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 );
119 netSettings->ClearNetChainClasses();
120 netSettings->ClearNetChainNetClasses();
123 netSettings->SetNetChainClass(
chain, className );
126 netSettings->SetNetChainNetClass(
chain, netclass );
188 bestPosition.
x = pageSize.
x / 2;
189 bestPosition.
y = pageSize.
y / 2;
206 if( aFootprintId.
empty() )
208 msg.Printf(
_(
"Cannot add %s (no footprint assigned)." ),
217 if( footprint ==
nullptr )
219 msg.Printf(
_(
"Cannot add %s (footprint '%s' not found)." ),
228 m_board->GetComponentClassManager().GetNoneComponentClass() );
232 msg.Printf(
_(
"Add %s (footprint '%s')." ),
243 bool showRatsnest =
true;
246 showRatsnest =
m_settings->m_Display.m_ShowGlobalRatsnest;
248 pad->SetLocalRatsnestVisible( showRatsnest );
251 pad->SetNetCode( 0 );
266 msg.Printf(
_(
"Added %s (footprint '%s')." ),
279 wxString curClassName, newClassName;
283 curClassName = curClass->
GetName();
293 newClass =
m_board->GetComponentClassManager().GetEffectiveStaticComponentClass(
295 newClassName = newClass->
GetName();
298 if( curClassName == newClassName )
307 copy->SetParentGroup(
nullptr );
314 if( curClassName == wxEmptyString && newClassName != wxEmptyString )
316 msg.Printf(
_(
"Change %s component class to '%s'." ),
320 else if( curClassName != wxEmptyString && newClassName == wxEmptyString )
322 msg.Printf(
_(
"Remove %s component class (currently '%s')." ),
328 msg.Printf(
_(
"Change %s component class from '%s' to '%s'." ),
336 wxASSERT_MSG( newClass !=
nullptr,
"Component class should not be nullptr" );
340 if( curClassName == wxEmptyString && newClassName != wxEmptyString )
342 msg.Printf(
_(
"Changed %s component class to '%s'." ),
346 else if( curClassName != wxEmptyString && newClassName == wxEmptyString )
348 msg.Printf(
_(
"Removed %s component class (was '%s')." ),
354 msg.Printf(
_(
"Changed %s component class from '%s' to '%s'." ),
377 msg.Printf(
_(
"Cannot update %s (no footprint assigned)." ),
386 if( newFootprint ==
nullptr )
388 msg.Printf(
_(
"Cannot update %s (footprint '%s' not found)." ),
400 msg.Printf(
_(
"Cannot change %s footprint from '%s' to '%s' (footprint is locked)."),
411 msg.Printf(
_(
"Change %s footprint from '%s' to '%s'."),
425 msg.Printf(
_(
"Could not change %s footprint from '%s' to '%s' (footprint is locked)."),
439 m_board->ExchangeFootprint( aFootprint, newFootprint,
m_commit,
true );
441 msg.Printf(
_(
"Changed %s footprint from '%s' to '%s'."),
466 firstAssociatedVariant = &
test;
475 if( !
m_commit.GetStatus( aFootprint ) )
478 copy->SetParentGroup(
nullptr );
481 bool changed =
false;
488 msg.Printf(
_(
"Change %s reference designator to %s." ),
494 msg.Printf(
_(
"Changed %s reference designator to %s." ),
506 wxString netlistValue = aNetlistComponent->
GetValue();
508 if( firstAssociatedVariant !=
nullptr
514 if( aFootprint->
GetValue() != netlistValue )
518 msg.Printf(
_(
"Change %s value from %s to %s." ),
525 msg.Printf(
_(
"Changed %s value from %s to %s." ),
531 aFootprint->
SetValue( netlistValue );
540 if( !aNetlistComponent->
GetKIIDs().empty() )
541 new_path.push_back( aNetlistComponent->
GetKIIDs().front() );
543 if( aFootprint->
GetPath() != new_path )
547 msg.Printf(
_(
"Update %s symbol association from %s to %s." ),
554 msg.Printf(
_(
"Updated %s symbol association from %s to %s." ),
560 aFootprint->
SetPath( new_path );
566 nlohmann::ordered_map<wxString, wxString> fpFieldsAsMap;
571 if( field->IsReference() || field->IsValue() || field->IsComponentClass() )
576 fpFieldsAsMap[field->GetName()] = field->GetText();
580 nlohmann::ordered_map<wxString, wxString> compFields = aNetlistComponent->
GetFields();
586 compFields.erase( wxT(
"Component Class" ) );
588 if( firstAssociatedVariant !=
nullptr )
590 for(
const auto& [
name, value] : firstAssociatedVariant->
m_fields )
591 compFields[
name] = value;
597 bool remove_only =
true;
599 for(
const auto& [
name, value] : compFields )
601 if( fpFieldsAsMap.count(
name ) == 0 || fpFieldsAsMap[
name] != value )
609 for(
const auto& [
name, value] : fpFieldsAsMap )
611 if( compFields.count(
name ) == 0 )
624 msg.Printf(
_(
"Update %s fields." ), aFootprint->
GetReference() );
631 if( field->IsMandatory() )
634 if( compFields.count( field->GetName() ) == 0 )
638 msg.Printf(
_(
"Remove %s footprint fields not in symbol." ), aFootprint->
GetReference() );
650 msg.Printf(
_(
"Updated %s fields." ), aFootprint->
GetReference() );
656 for(
auto& [
name, value] : compFields )
665 aFootprint->
Add( newField );
686 std::vector<PCB_FIELD*> fieldList;
687 aFootprint->
GetFields( fieldList,
false );
691 if( field->IsMandatory() )
694 if( compFields.count( field->GetName() ) == 0 )
699 msg.Printf(
_(
"Removed %s footprint fields not in symbol." ), aFootprint->
GetReference() );
703 aFootprint->
Remove( field );
706 m_frame->GetCanvas()->GetView()->Remove( field );
721 if( !humanSheetPath.empty() )
722 sheetname = humanSheetPath;
723 else if( aNetlistComponent->
GetProperties().count( wxT(
"Sheetname" ) ) > 0 )
724 sheetname = aNetlistComponent->
GetProperties().at( wxT(
"Sheetname" ) );
726 if( aNetlistComponent->
GetProperties().count( wxT(
"Sheetfile" ) ) > 0 )
727 sheetfile = aNetlistComponent->
GetProperties().at( wxT(
"Sheetfile" ) );
729 if( aNetlistComponent->
GetProperties().count( wxT(
"ki_fp_filters" ) ) > 0 )
730 fpFilters = aNetlistComponent->
GetProperties().at( wxT(
"ki_fp_filters" ) );
736 msg.Printf(
_(
"Update %s sheetname to '%s'." ),
743 msg.Printf(
_(
"Updated %s sheetname to '%s'." ),
755 msg.Printf(
_(
"Update %s sheetfile to '%s'." ),
762 msg.Printf(
_(
"Updated %s sheetfile to '%s'." ),
774 msg.Printf(
_(
"Update %s footprint filters to '%s'." ),
781 msg.Printf(
_(
"Updated %s footprint filters to '%s'." ),
789 bool netlistExcludeFromBOM = aNetlistComponent->
GetProperties().count( wxT(
"exclude_from_bom" ) ) > 0;
798 if( netlistExcludeFromBOM )
799 msg.Printf(
_(
"Add %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
801 msg.Printf(
_(
"Remove %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
807 if( netlistExcludeFromBOM )
810 msg.Printf(
_(
"Added %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
815 msg.Printf(
_(
"Removed %s 'exclude from BOM' fabrication attribute." ), aFootprint->
GetReference() );
825 bool netlistDNP = aNetlistComponent->
GetProperties().count( wxT(
"dnp" ) ) > 0;
827 if( firstAssociatedVariant !=
nullptr && firstAssociatedVariant->
m_hasDnp )
828 netlistDNP = firstAssociatedVariant->
m_dnp;
835 msg.Printf(
_(
"Add %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
837 msg.Printf(
_(
"Remove %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
846 msg.Printf(
_(
"Added %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
851 msg.Printf(
_(
"Removed %s 'Do not place' fabrication attribute." ), aFootprint->
GetReference() );
861 bool netlistExcludeFromPosFiles = aNetlistComponent->
GetProperties().count( wxT(
"exclude_from_pos_files" ) ) > 0;
871 if( netlistExcludeFromPosFiles )
873 msg.Printf(
_(
"Add %s 'exclude from position files' fabrication attribute." ),
878 msg.Printf(
_(
"Remove %s 'exclude from position files' fabrication attribute." ),
886 if( netlistExcludeFromPosFiles )
889 msg.Printf(
_(
"Added %s 'exclude from position files' fabrication attribute." ),
895 msg.Printf(
_(
"Removed %s 'exclude from position files' fabrication attribute." ),
918 msg.Printf(
_(
"Added %s 'duplicate pad numbers are jumpers' attribute." ),
923 msg.Printf(
_(
"Removed %s 'duplicate pad numbers are jumpers' attribute." ),
931 msg.Printf(
_(
"Add %s 'duplicate pad numbers are jumpers' attribute." ),
936 msg.Printf(
_(
"Remove %s 'duplicate pad numbers are jumpers' attribute." ),
950 msg.Printf(
_(
"Updated %s jumper pad groups" ), aFootprint->
GetReference() );
954 msg.Printf(
_(
"Update %s jumper pad groups" ), aFootprint->
GetReference() );
960 if( changed &&
copy )
980 if( !
m_commit.GetStatus( aPcbFootprint ) )
983 copy->SetParentGroup(
nullptr );
986 bool changed =
false;
995 KIID existingGroupKIID = existingGroup ? existingGroup->
m_Uuid : 0;
998 auto it = std::find_if(
m_board->Groups().begin(),
m_board->Groups().end(),
1000 return group->m_Uuid == newGroupKIID;
1004 if( it !=
m_board->Groups().end() )
1008 if( newGroupKIID == existingGroupKIID )
1012 if( existingGroupKIID != 0 )
1016 msg.Printf(
_(
"Remove %s from group '%s'." ),
1022 msg.Printf(
_(
"Removed %s from group '%s'." ),
1030 if( existingGroup->
GetItems().size() < 2 )
1041 if( newGroupKIID != 0 )
1045 msg.Printf(
_(
"Add %s to group '%s'." ),
1051 msg.Printf(
_(
"Added %s to group '%s'." ),
1057 if( newGroup ==
nullptr )
1060 newGroup->
SetUuid( newGroupKIID );
1074 newGroup->
AddItem( aPcbFootprint );
1080 if( changed &&
copy )
1100 copy->SetParentGroup(
nullptr );
1103 bool changed =
false;
1106 std::deque<PAD*> pads = aFootprint->
Pads();
1107 std::set<wxString> padNetnames;
1109 std::sort( pads.begin(), pads.end(),
1112 return a->m_Uuid < b->m_Uuid;
1119 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1120 wxT(
"Processing pad %s of component %s" ),
1124 wxString pinFunction;
1129 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1130 wxT(
" Found valid net: %s" ),
1137 wxLogTrace( wxT(
"NETLIST_UPDATE" ),
1138 wxT(
" No net found for pad %s" ),
1144 if(
pad->GetPinFunction() != pinFunction )
1147 pad->SetPinFunction( pinFunction );
1150 if(
pad->GetPinType() != pinType )
1153 pad->SetPinType( pinType );
1162 if( !net.
IsValid() || !
pad->IsOnCopperLayer() )
1164 if( !
pad->GetNetname().IsEmpty() )
1168 msg.Printf(
_(
"Disconnect %s pin %s." ),
1174 msg.Printf(
_(
"Disconnected %s pin %s." ),
1181 else if(
pad->IsOnCopperLayer() && !
pad->GetNumber().IsEmpty() )
1184 msg.Printf(
_(
"No net found for component %s pad %s (no pin %s in symbol)." ),
1199 if(
pad->GetNetname().IsEmpty() )
1200 pad->SetPinFunction( wxEmptyString );
1212 if(
pad->IsNoConnectPad() )
1214 netName = wxString::Format( wxS(
"%s" ), net.
GetNetName() );
1216 for(
int jj = 1; !padNetnames.insert( netName ).second
1220 netName = wxString::Format( wxS(
"%s_%d" ), net.
GetNetName(), jj );
1229 if(
pad->GetNetname() != netName )
1232 if( netinfo ==
nullptr )
1239 if( netinfo ==
nullptr )
1251 msg.Printf(
_(
"Add net %s." ),
1256 if( !
pad->GetNetname().IsEmpty() )
1262 msg.Printf(
_(
"Reconnect %s pin %s from %s to %s."),
1270 msg.Printf(
_(
"Reconnected %s pin %s from %s to %s."),
1281 msg.Printf(
_(
"Connect %s pin %s to %s."),
1288 msg.Printf(
_(
"Connected %s pin %s to %s."),
1300 pad->SetNet( netinfo );
1310 if( changed &&
copy )
1322 std::vector<FOOTPRINT::FP_UNIT_INFO> newUnits;
1325 newUnits.push_back( { u.m_unitName, u.m_pins } );
1327 const std::vector<FOOTPRINT::FP_UNIT_INFO>& curUnits = aFootprint->
GetUnitInfo();
1329 auto unitsEqual = [](
const std::vector<FOOTPRINT::FP_UNIT_INFO>& a,
1330 const std::vector<FOOTPRINT::FP_UNIT_INFO>& b )
1332 if( a.size() != b.size() )
1335 for(
size_t i = 0; i < a.size(); ++i )
1337 if( a[i].m_unitName != b[i].m_unitName )
1340 if( a[i].m_pins != b[i].m_pins )
1347 if( unitsEqual( curUnits, newUnits ) )
1354 msg.Printf(
_(
"Update %s unit metadata." ), aFootprint->
GetReference() );
1362 if( !
m_commit.GetStatus( aFootprint ) )
1365 copy->SetParentGroup(
nullptr );
1370 msg.Printf(
_(
"Updated %s unit metadata." ), aFootprint->
GetReference() );
1385 return aBoardFpid == aSchematicFpid;
1390 const std::vector<FOOTPRINT*>& aFootprints,
1391 const LIB_ID& aBaseFpid )
1396 if( aBaseFpid.
empty() )
1408 std::vector<VARIANT_INFO> variantInfo;
1409 variantInfo.reserve( variants.size() );
1411 for(
const auto& [variantName, variant] : variants )
1413 LIB_ID variantFPID = aBaseFpid;
1415 auto fieldIt = variant.m_fields.find( footprintFieldName );
1417 if( fieldIt != variant.m_fields.end() && !fieldIt->second.IsEmpty() )
1421 if( parsedId.
Parse( fieldIt->second,
true ) >= 0 )
1423 msg.Printf(
_(
"Invalid footprint ID '%s' for variant '%s' on %s." ),
1432 variantFPID = parsedId;
1436 variantInfo.push_back( { variantName, &variant, variantFPID } );
1439 for(
FOOTPRINT* footprint : aFootprints )
1449 copy->SetParentGroup(
nullptr );
1452 bool changed =
false;
1454 auto printAttributeMessage =
1455 [&](
bool add,
const wxString& attrName,
const wxString& variantName )
1459 if( aFootprints.size() > 1 )
1461 msg.Printf( add ?
_(
"Add %s '%s' attribute to variant %s (footprint %s)." )
1462 :
_(
"Remove %s '%s' attribute from variant %s (footprint %s)." ),
1463 footprint->GetReference(),
1466 footprint->GetFPIDAsString() );
1470 msg.Printf( add ?
_(
"Add %s '%s' attribute to variant %s." )
1471 :
_(
"Remove %s '%s' attribute from variant %s." ),
1472 footprint->GetReference(),
1479 if( aFootprints.size() > 1 )
1481 msg.Printf( add ?
_(
"Added %s '%s' attribute to variant %s (footprint %s)." )
1482 :
_(
"Removed %s '%s' attribute from variant %s (footprint %s)." ),
1483 footprint->GetReference(),
1486 footprint->GetFPIDAsString() );
1490 msg.Printf( add ?
_(
"Added %s '%s' attribute to variant %s." )
1491 :
_(
"Removed %s '%s' attribute from variant %s." ),
1492 footprint->GetReference(),
1499 bool isBaseFootprint =
fpidsEquivalent( footprint->GetFPID(), aBaseFpid );
1504 const bool baseFootprintDnp = footprint->IsDNP();
1505 bool effectiveFootprintDnp = baseFootprintDnp;
1512 if( !isBaseFootprint && !effectiveFootprintDnp )
1514 msg.Printf(
m_isDryRun ?
_(
"Add %s 'Do not place' fabrication attribute." )
1515 :
_(
"Added %s 'Do not place' fabrication attribute." ),
1516 footprint->GetReference() );
1521 footprint->SetDNP(
true );
1525 effectiveFootprintDnp =
true;
1529 std::set<wxString> excessVariants;
1531 for(
const auto& [variantName,
_] : footprint->GetVariants() )
1532 excessVariants.insert( variantName );
1534 for(
const VARIANT_INFO&
info : variantInfo )
1548 if( !isAssociatedFootprint )
1550 if( aFootprints.size() > 1 )
1552 excessVariants.erase(
info.name );
1553 bool currentDnp = currentVariant ? currentVariant->
GetDNP() : effectiveFootprintDnp;
1557 printAttributeMessage(
true,
_(
"Do not place" ),
info.name );
1562 fpVariant->SetDNP(
true );
1573 excessVariants.erase(
info.name );
1574 bool targetDnp = variant.
m_hasDnp ? variant.
m_dnp : baseFootprintDnp;
1575 bool currentDnp = currentVariant ? currentVariant->
GetDNP() : effectiveFootprintDnp;
1577 if( currentDnp != targetDnp )
1579 printAttributeMessage( targetDnp,
_(
"Do not place" ),
info.name );
1584 fpVariant->SetDNP( targetDnp );
1592 : footprint->IsExcludedFromBOM();
1594 : footprint->IsExcludedFromBOM();
1596 if( currentExcludedFromBOM != targetExcludedFromBOM )
1598 printAttributeMessage( targetExcludedFromBOM,
_(
"exclude from BOM" ),
info.name );
1603 fpVariant->SetExcludedFromBOM( targetExcludedFromBOM );
1611 : footprint->IsExcludedFromPosFiles();
1613 : footprint->IsExcludedFromPosFiles();
1615 if( currentExcludedFromPosFiles != targetExcludedFromPosFiles )
1617 printAttributeMessage( targetExcludedFromPosFiles,
_(
"exclude from position files" ),
info.name );
1622 fpVariant->SetExcludedFromPosFiles( targetExcludedFromPosFiles );
1629 for(
const auto& [fieldName, fieldValue] : variant.
m_fields )
1631 if( fieldName.CmpNoCase( footprintFieldName ) == 0 )
1634 bool hasCurrentValue = currentVariant && currentVariant->
HasFieldValue( fieldName );
1635 wxString currentValue = hasCurrentValue ? currentVariant->
GetFieldValue( fieldName ) : wxString();
1637 if( currentValue != fieldValue )
1641 if( aFootprints.size() > 1 )
1643 msg.Printf(
_(
"Change %s field '%s' to '%s' on variant %s (footprint %s)." ),
1644 footprint->GetReference(),
1648 footprint->GetFPIDAsString() );
1652 msg.Printf(
_(
"Change %s field '%s' to '%s' on variant %s." ),
1653 footprint->GetReference(),
1661 if( aFootprints.size() > 1 )
1663 msg.Printf(
_(
"Changed %s field '%s' to '%s' on variant %s (footprint %s)." ),
1664 footprint->GetReference(),
1668 footprint->GetFPIDAsString() );
1672 msg.Printf(
_(
"Changed %s field '%s' to '%s' on variant %s." ),
1673 footprint->GetReference(),
1680 fpVariant->SetFieldValue( fieldName, fieldValue );
1689 for(
const wxString& excess : excessVariants )
1693 msg.Printf(
_(
"Remove variant %s:%s no longer associated with footprint %s." ),
1694 footprint->GetReference(),
1696 footprint->GetFPIDAsString() );
1700 msg.Printf(
_(
"Removed variant %s:%s no longer associated with footprint %s." ),
1701 footprint->GetReference(),
1703 footprint->GetFPIDAsString() );
1705 footprint->DeleteVariant( excess );
1724 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
1735 std::set<wxString> netlistNetnames;
1737 for(
int ii = 0; ii < (int) aNetlist.
GetCount(); ii++ )
1741 for(
unsigned jj = 0; jj < component->
GetNetCount(); jj++ )
1753 if( netlistNetnames.count(
via->GetNetname() ) == 0 )
1755 wxString updatedNetname = wxEmptyString;
1764 if( !updatedNetname.IsEmpty() )
1768 wxString originalNetname =
via->GetNetname();
1770 msg.Printf(
_(
"Reconnect via from %s to %s." ),
1785 wxString originalNetname =
via->GetNetname();
1788 via->SetNet( netinfo );
1790 msg.Printf(
_(
"Reconnected via from %s to %s." ),
1800 msg.Printf(
_(
"Via connected to unknown net (%s)." ),
1812 auto isInNetlist = [&](
const wxString& aNetName ) ->
bool
1814 if( netlistNetnames.count( aNetName ) )
1819 for(
const wxString& netName : netlistNetnames )
1821 if( aNetName.StartsWith( netName ) )
1831 if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
1834 if( !isInNetlist( zone->GetNetname() ) )
1839 wxString updatedNetname = wxEmptyString;
1852 if( updatedNetname.IsEmpty() &&
m_oldToNewNets.count( zone->GetNetname() ) )
1857 if( !updatedNetname.IsEmpty() )
1861 wxString originalNetname = zone->GetNetname();
1863 if( !zone->GetZoneName().IsEmpty() )
1865 msg.Printf(
_(
"Reconnect copper zone '%s' from %s to %s." ),
1866 zone->GetZoneName(),
1872 msg.Printf(
_(
"Reconnect copper zone from %s to %s." ),
1888 wxString originalNetname = zone->GetNetname();
1891 zone->SetNet( netinfo );
1893 if( !zone->GetZoneName().IsEmpty() )
1895 msg.Printf(
_(
"Reconnected copper zone '%s' from %s to %s." ),
1902 msg.Printf(
_(
"Reconnected copper zone from %s to %s." ),
1913 if( !zone->GetZoneName().IsEmpty() )
1915 msg.Printf(
_(
"Copper zone '%s' has no pads connected." ),
1920 wxString layerNames = zone->LayerMaskDescribe();
1925 if(
m_settings->m_Display.m_DisplayInvertXAxis )
1928 if(
m_settings->m_Display.m_DisplayInvertYAxis )
1932 msg.Printf(
_(
"Copper zone on %s at (%s, %s) has no pads connected to net \"%s\"." ),
1942 zone->GetNetname() );
1966 if( netlistGroup ==
nullptr )
1969 if( netlistGroup->
name != pcbGroup->GetName() )
1973 msg.Printf(
_(
"Change group name from '%s' to '%s'." ),
1979 msg.Printf(
_(
"Changed group name from '%s' to '%s'." ),
1983 pcbGroup->SetName( netlistGroup->
name );
1989 if( netlistGroup->
libId != pcbGroup->GetDesignBlockLibId() )
1993 msg.Printf(
_(
"Change group library link from '%s' to '%s'." ),
1994 EscapeHTML( pcbGroup->GetDesignBlockLibId().GetUniStringLibId() ),
1999 msg.Printf(
_(
"Changed group library link from '%s' to '%s'." ),
2000 EscapeHTML( pcbGroup->GetDesignBlockLibId().GetUniStringLibId() ),
2003 pcbGroup->SetDesignBlockLibId( netlistGroup->
libId );
2013 if( member.empty() )
2016 KIID memberGroupUuid =
2023 if( candidate->m_Uuid == memberGroupUuid )
2025 childGroup = candidate;
2030 if( !childGroup || childGroup == pcbGroup || childGroup->
GetParentGroup() == pcbGroup )
2037 msg.Printf(
_(
"Add group '%s' to group '%s'." ),
EscapeHTML( childGroup->
GetName() ),
2042 msg.Printf(
_(
"Added group '%s' to group '%s'." ),
EscapeHTML( childGroup->
GetName() ),
2046 pcbGroup->AddItem( childGroup );
2058 std::map<COMPONENT*, FOOTPRINT*>& aFootprintMap )
2066 for(
int i = 0; i < (int) aNetlist.
GetCount(); i++ )
2069 FOOTPRINT* footprint = aFootprintMap[component];
2075 for(
unsigned jj = 0; jj < component->
GetNetCount(); jj++ )
2079 if( padNumber.IsEmpty() )
2082 msg.Printf(
_(
"Symbol %s has pins with no number. These pins can not be matched "
2092 msg.Printf(
_(
"%s pad %s not found in %s." ),
2108 FOOTPRINT* lastPreexistingFootprint =
nullptr;
2111 std::unordered_set<wxString> sheetPaths;
2112 std::unordered_set<FOOTPRINT*> usedFootprints;
2118 std::map<COMPONENT*, FOOTPRINT*> footprintMap;
2120 if( !
m_board->Footprints().empty() )
2121 lastPreexistingFootprint =
m_board->Footprints().back();
2131 net->SetIsCurrent( net->GetNetCode() == 0 );
2133 m_board->GetComponentClassManager().InitNetlistUpdate();
2137 for(
unsigned ii = 0; ii < aNetlist.
GetCount(); ii++ )
2141 for(
unsigned jj = 0; jj <
comp->GetNetCount(); jj++ )
2148 for(
unsigned i = 0; i < aNetlist.
GetCount(); i++ )
2152 if( component->
GetProperties().count( wxT(
"exclude_from_board" ) ) )
2155 msg.Printf(
_(
"Processing symbol '%s:%s'." ),
2161 const bool hasBaseFpid = !baseFpid.
empty();
2165 msg.Printf(
_(
"Warning: %s footprint '%s' is missing a library name. "
2166 "Use the full 'Library:Footprint' format to avoid repeated update "
2174 std::vector<FOOTPRINT*> matchingFootprints;
2185 base.push_back( uuid );
2187 if( footprint->GetPath() == base )
2196 match = footprint->GetReference().CmpNoCase( component->
GetReference() ) == 0;
2200 matchingFootprints.push_back( footprint );
2202 if( footprint == lastPreexistingFootprint )
2209 std::vector<LIB_ID> expectedFpids;
2210 std::unordered_set<wxString> expectedFpidKeys;
2212 auto addExpectedFpid =
2213 [&](
const LIB_ID& aFpid )
2218 wxString key = aFpid.Format();
2220 if( expectedFpidKeys.insert( key ).second )
2221 expectedFpids.push_back( aFpid );
2224 addExpectedFpid( baseFpid );
2228 for(
const auto& [variantName, variant] : component->
GetVariants() )
2230 auto fieldIt = variant.m_fields.find( footprintFieldName );
2232 if( fieldIt == variant.m_fields.end() || fieldIt->second.IsEmpty() )
2237 if( parsedId.
Parse( fieldIt->second,
true ) >= 0 )
2239 msg.Printf(
_(
"Invalid footprint ID '%s' for variant '%s' on %s." ),
2248 addExpectedFpid( parsedId );
2251 auto isExpectedFpid =
2252 [&](
const LIB_ID& aFpid ) ->
bool
2257 if( expectedFpidKeys.count( aFpid.Format() ) > 0 )
2269 auto takeMatchingFootprint =
2272 for(
FOOTPRINT* footprint : matchingFootprints )
2274 if( usedFootprints.count( footprint ) )
2284 std::vector<FOOTPRINT*> componentFootprints;
2285 componentFootprints.reserve( expectedFpids.size() );
2289 baseFootprint = takeMatchingFootprint( baseFpid );
2290 else if( !matchingFootprints.empty() )
2291 baseFootprint = matchingFootprints.front();
2297 for(
FOOTPRINT* footprint : matchingFootprints )
2299 if( usedFootprints.count( footprint ) )
2302 if( isExpectedFpid( footprint->GetFPID() ) )
2305 replaceCandidate = footprint;
2309 if( replaceCandidate )
2314 baseFootprint = replaced;
2316 baseFootprint = replaceCandidate;
2322 for(
FOOTPRINT* footprint : matchingFootprints )
2324 if( usedFootprints.count( footprint ) )
2327 if( isExpectedFpid( footprint->GetFPID() ) )
2330 baseFootprint = footprint;
2335 if( !baseFootprint && ( hasBaseFpid || expectedFpids.empty() ) )
2340 componentFootprints.push_back( baseFootprint );
2341 usedFootprints.insert( baseFootprint );
2342 footprintMap[ component ] = baseFootprint;
2345 for(
const LIB_ID& fpid : expectedFpids )
2353 FOOTPRINT* footprint = takeMatchingFootprint( fpid );
2360 componentFootprints.push_back( footprint );
2361 usedFootprints.insert( footprint );
2365 for(
FOOTPRINT* footprint : componentFootprints )
2376 sheetPaths.insert( footprint->GetSheetname() );
2379 if( !componentFootprints.empty() )
2391 bool matched =
false;
2397 bool isStaleVariantFootprint =
false;
2399 if( usedFootprints.count( footprint ) )
2410 if( component && component->
GetProperties().count( wxT(
"exclude_from_board" ) ) == 0 )
2418 isStaleVariantFootprint =
true;
2429 if( isStaleVariantFootprint )
2432 if( doDelete && !matched && footprint->IsLocked() && !
m_overrideLocks )
2436 msg.Printf(
_(
"Cannot remove unused footprint %s (footprint is locked)." ),
2437 footprint->GetReference() );
2441 msg.Printf(
_(
"Could not remove unused footprint %s (footprint is locked)." ),
2442 footprint->GetReference() );
2450 if( doDelete && !matched )
2454 msg.Printf(
_(
"Remove unused footprint %s." ),
2455 footprint->GetReference() );
2460 msg.Printf(
_(
"Removed unused footprint %s." ),
2461 footprint->GetReference() );
2471 for(
PAD*
pad : footprint->Pads() )
2474 pad->GetNet()->SetIsCurrent(
true );
2482 m_board->GetComponentClassManager().FinishNetlistUpdate();
2483 m_board->SynchronizeComponentClasses( sheetPaths );
2490 if( !net->IsCurrent() )
2492 msg.Printf(
_(
"Removed unused net %s." ),
2501 const std::vector<wxString>& netlistVariants = aNetlist.
GetVariantNames();
2503 if( !netlistVariants.empty() || !
m_board->GetVariantNames().empty() )
2507 auto findBoardVariantName =
2508 [&](
const wxString& aVariantName ) -> wxString
2510 for(
const wxString&
name :
m_board->GetVariantNames() )
2512 if(
name.CmpNoCase( aVariantName ) == 0 )
2516 return wxEmptyString;
2519 std::vector<wxString> updatedVariantNames;
2520 updatedVariantNames.reserve( netlistVariants.size() );
2522 for(
const wxString& variantName : netlistVariants )
2524 wxString actualName = findBoardVariantName( variantName );
2526 if( actualName.IsEmpty() )
2528 m_board->AddVariant( variantName );
2529 actualName = findBoardVariantName( variantName );
2531 if( !actualName.IsEmpty() )
2533 msg.Printf(
_(
"Added variant '%s'." ), actualName );
2538 if( actualName.IsEmpty() )
2543 wxString oldDescription =
m_board->GetVariantDescription( actualName );
2545 if( newDescription != oldDescription )
2547 m_board->SetVariantDescription( actualName, newDescription );
2548 msg.Printf(
_(
"Updated description for variant '%s'." ), actualName );
2552 updatedVariantNames.push_back( actualName );
2555 std::vector<wxString> variantsToRemove;
2557 for(
const wxString& existingName :
m_board->GetVariantNames() )
2561 for(
const wxString& variantName : netlistVariants )
2563 if( existingName.CmpNoCase( variantName ) == 0 )
2571 variantsToRemove.push_back( existingName );
2574 for(
const wxString& variantName : variantsToRemove )
2576 m_board->DeleteVariant( variantName );
2577 msg.Printf(
_(
"Removed variant '%s'." ), variantName );
2581 if( !updatedVariantNames.empty() )
2582 m_board->SetVariantNames( updatedVariantNames );
2601 if( !colorStr.IsEmpty() )
2614 m_board->SynchronizeNetsAndNetClasses(
true );
2618 PAD* pads[2] = {
nullptr,
nullptr };
2620 for(
size_t i = 0; i < sig.second.size() && i < 2; ++i )
2622 const wxString& ref = sig.second[i].first;
2623 const wxString&
pin = sig.second[i].second;
2629 PAD* candidate =
nullptr;
2630 PAD* best =
nullptr;
2631 int bestDist = std::numeric_limits<int>::max();
2640 if( !best || dist < bestDist || ( dist == bestDist && candidate->
m_Uuid < best->
m_Uuid ) )
2650 for(
int i = 0; i < 2; ++i )
2657 if( !termNet || termNet->
GetNetChain() != sig.first )
2662 if( net != termNet && net->
GetNetChain() == sig.first
2663 && net->GetTerminalPad( i ) )
2665 net->ClearTerminalPad( i );
2681 for(
const std::pair<const wxString, NETINFO_ITEM*>& addedNet :
m_addedNets )
2682 delete addedNet.second;
constexpr EDA_IU_SCALE pcbIUScale
wxString GetNetname() const
NETINFO_ITEM * GetNet() const
Return #NET_INFO 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()
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
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
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