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() );
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() );
// 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
if( !pad->IsOnCopperLayer() )
// Pads with no numbers can't be matched. (Then again, they're never connected to a
// 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;
}
// Pads with no numbers are never connected to a net
if( pad->GetNumber().IsEmpty() )
{
pad->SetNetCode( NETINFO_LIST::UNCONNECTED );
continue;
}
// Search for a similar pad on a copper layer, to reuse net info
// Search for a similar pad to reuse UUID and net info
PAD* last_pad = nullptr;
while( true )
{
pad_model = aExisting->FindPadByNumber( pad->GetNumber(), last_pad );
oldPad = aExisting->FindPadByNumber( newPad->GetNumber(), last_pad );
if( !pad_model )
if( !oldPad )
break;
if( pad_model->IsOnCopperLayer() ) // a candidate is found
if( newPad->IsOnCopperLayer() == oldPad->IsOnCopperLayer() ) // a candidate is found
break;
last_pad = pad_model;
last_pad = oldPad;
}
if( pad_model )
if( oldPad )
{
pad->SetLocalRatsnestVisible( pad_model->GetLocalRatsnestVisible() );
pad->SetPinFunction( pad_model->GetPinFunction() );
pad->SetPinType( pad_model->GetPinType() );
const_cast<KIID&>( newPad->m_Uuid ) = oldPad->m_Uuid;
newPad->SetLocalRatsnestVisible( oldPad->GetLocalRatsnestVisible() );
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
if( dynamic_cast<PCB_DIMENSION_BASE*>( srcItem ) )
if( dynamic_cast<PCB_DIMENSION_BASE*>( oldTextItem ) )
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 );
}
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
processTextItem( aExisting->Reference(), aNew->Reference(),
false,
resetTextLayers, resetTextEffects, aUpdated );
processTextItem( aExisting->Reference(), aNew->Reference(), false, resetTextLayers,
resetTextEffects, aUpdated );
// Copy value
processTextItem( aExisting->Value(), aNew->Value(),
@ -2359,24 +2357,24 @@ void PCB_EDIT_FRAME::ExchangeFootprint( FOOTPRINT* aExisting, FOOTPRINT* aNew,
resetTextLayers, resetTextEffects, aUpdated );
// 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
if( field->IsReference() || field->IsValue() )
if( oldField->IsReference() || oldField->IsValue() )
continue;
PCB_FIELD* newField = aNew->GetFieldByName( field->GetName() );
PCB_FIELD* newField = aNew->GetFieldByName( oldField->GetName() );
if( !newField )
{
newField = new PCB_FIELD( *field );
newField = new PCB_FIELD( *oldField );
aNew->Add( newField );
processTextItem( *field, *newField, true, true, true, aUpdated );
processTextItem( *oldField, *newField, true, true, true, aUpdated );
}
else
{
processTextItem( *field, *newField, resetTextContent, resetTextLayers, resetTextEffects,
aUpdated );
processTextItem( *oldField, *newField, resetTextContent, resetTextLayers,
resetTextEffects, aUpdated );
}
}