Retain UUIDs where possible when updating footprints.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17451
This commit is contained in:
Jeff Young 2024-06-01 11:55:24 +01:00
parent 11193d2cda
commit 53ec5d2c19
1 changed files with 38 additions and 40 deletions

View File

@ -2192,6 +2192,7 @@ static void processTextItem( const PCB_TEXT& aSrc, PCB_TEXT& aDest,
} }
aDest.SetLocked( aSrc.IsLocked() ); aDest.SetLocked( aSrc.IsLocked() );
const_cast<KIID&>( aDest.m_Uuid ) = aSrc.m_Uuid;
} }
@ -2278,78 +2279,75 @@ void PCB_EDIT_FRAME::ExchangeFootprint( FOOTPRINT* aExisting, FOOTPRINT* aNew,
aNew->SetLocked( aExisting->IsLocked() ); aNew->SetLocked( aExisting->IsLocked() );
// Now transfer the net info from "old" pads to the new footprint // Now transfer the net info from "old" pads to the new footprint
for( PAD* pad : aNew->Pads() ) for( PAD* newPad : aNew->Pads() )
{ {
PAD* pad_model = nullptr; PAD* oldPad = nullptr;
// Pads with no copper are never connected to a net // Pads with no numbers can't be matched. (Then again, they're never connected to a
if( !pad->IsOnCopperLayer() ) // net either, so it's just the UUID retention that we can't perform.)
if( newPad->GetNumber().IsEmpty() )
{ {
pad->SetNetCode( NETINFO_LIST::UNCONNECTED ); newPad->SetNetCode( NETINFO_LIST::UNCONNECTED );
continue; continue;
} }
// Pads with no numbers are never connected to a net // Search for a similar pad to reuse UUID and net info
if( pad->GetNumber().IsEmpty() )
{
pad->SetNetCode( NETINFO_LIST::UNCONNECTED );
continue;
}
// Search for a similar pad on a copper layer, to reuse net info
PAD* last_pad = nullptr; PAD* last_pad = nullptr;
while( true ) while( true )
{ {
pad_model = aExisting->FindPadByNumber( pad->GetNumber(), last_pad ); oldPad = aExisting->FindPadByNumber( newPad->GetNumber(), last_pad );
if( !pad_model ) if( !oldPad )
break; break;
if( pad_model->IsOnCopperLayer() ) // a candidate is found if( newPad->IsOnCopperLayer() == oldPad->IsOnCopperLayer() ) // a candidate is found
break; break;
last_pad = pad_model; last_pad = oldPad;
} }
if( pad_model ) if( oldPad )
{ {
pad->SetLocalRatsnestVisible( pad_model->GetLocalRatsnestVisible() ); const_cast<KIID&>( newPad->m_Uuid ) = oldPad->m_Uuid;
pad->SetPinFunction( pad_model->GetPinFunction() ); newPad->SetLocalRatsnestVisible( oldPad->GetLocalRatsnestVisible() );
pad->SetPinType( pad_model->GetPinType() ); newPad->SetPinFunction( oldPad->GetPinFunction() );
newPad->SetPinType( oldPad->GetPinType() );
} }
pad->SetNetCode( pad_model ? pad_model->GetNetCode() : NETINFO_LIST::UNCONNECTED ); if( newPad->IsOnCopperLayer() )
newPad->SetNetCode( oldPad ? oldPad->GetNetCode() : NETINFO_LIST::UNCONNECTED );
else
newPad->SetNetCode( NETINFO_LIST::UNCONNECTED );
} }
for( BOARD_ITEM* item : aExisting->GraphicalItems() ) for( BOARD_ITEM* oldItem : aExisting->GraphicalItems() )
{ {
PCB_TEXT* srcItem = dynamic_cast<PCB_TEXT*>( item ); PCB_TEXT* oldTextItem = dynamic_cast<PCB_TEXT*>( oldItem );
if( srcItem ) if( oldTextItem )
{ {
// Dimensions have PCB_TEXT base but are not treated like texts in the updater // Dimensions have PCB_TEXT base but are not treated like texts in the updater
if( dynamic_cast<PCB_DIMENSION_BASE*>( srcItem ) ) if( dynamic_cast<PCB_DIMENSION_BASE*>( oldTextItem ) )
continue; continue;
PCB_TEXT* destItem = getMatchingTextItem( srcItem, aNew ); PCB_TEXT* newTextItem = getMatchingTextItem( oldTextItem, aNew );
if( destItem ) if( newTextItem )
{ {
processTextItem( *srcItem, *destItem, resetTextContent, resetTextLayers, processTextItem( *oldTextItem, *newTextItem, resetTextContent, resetTextLayers,
resetTextEffects, aUpdated ); resetTextEffects, aUpdated );
} }
else if( !deleteExtraTexts ) else if( !deleteExtraTexts )
{ {
aNew->Add( static_cast<BOARD_ITEM*>( srcItem->Clone() ) ); aNew->Add( static_cast<BOARD_ITEM*>( oldTextItem->Clone() ) );
} }
} }
} }
// Copy reference. The initial text is always used, never resetted // Copy reference. The initial text is always used, never resetted
processTextItem( aExisting->Reference(), aNew->Reference(), processTextItem( aExisting->Reference(), aNew->Reference(), false, resetTextLayers,
false, resetTextEffects, aUpdated );
resetTextLayers, resetTextEffects, aUpdated );
// Copy value // Copy value
processTextItem( aExisting->Value(), aNew->Value(), processTextItem( aExisting->Value(), aNew->Value(),
@ -2359,24 +2357,24 @@ void PCB_EDIT_FRAME::ExchangeFootprint( FOOTPRINT* aExisting, FOOTPRINT* aNew,
resetTextLayers, resetTextEffects, aUpdated ); resetTextLayers, resetTextEffects, aUpdated );
// Copy fields in accordance with the reset* flags // Copy fields in accordance with the reset* flags
for( PCB_FIELD* field : aExisting->GetFields() ) for( PCB_FIELD* oldField : aExisting->GetFields() )
{ {
// Reference and value are already handled // Reference and value are already handled
if( field->IsReference() || field->IsValue() ) if( oldField->IsReference() || oldField->IsValue() )
continue; continue;
PCB_FIELD* newField = aNew->GetFieldByName( field->GetName() ); PCB_FIELD* newField = aNew->GetFieldByName( oldField->GetName() );
if( !newField ) if( !newField )
{ {
newField = new PCB_FIELD( *field ); newField = new PCB_FIELD( *oldField );
aNew->Add( newField ); aNew->Add( newField );
processTextItem( *field, *newField, true, true, true, aUpdated ); processTextItem( *oldField, *newField, true, true, true, aUpdated );
} }
else else
{ {
processTextItem( *field, *newField, resetTextContent, resetTextLayers, resetTextEffects, processTextItem( *oldField, *newField, resetTextContent, resetTextLayers,
aUpdated ); resetTextEffects, aUpdated );
} }
} }