Preserve Uuids when editing board footprints.

One way to do this would have been to keep the Uuids in the editor
copy.  However, this opens us up to errors if we forget a Save As or
export path and end up writing the Uuids out somewhere else.

In the end, it felt safer to store a map of the original Uuids and
restore them if we happen to save the editor footprint back to the
board.

Fixes https://gitlab.com/kicad/code/kicad/issues/7312
This commit is contained in:
Jeff Young 2021-01-31 14:08:05 +00:00
parent 9ddfd82b91
commit a868fb97b6
8 changed files with 58 additions and 20 deletions

View File

@ -520,7 +520,6 @@ void FOOTPRINT_EDIT_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
GetDesignSettings() = cfg->m_DesignSettings;
m_displayOptions = cfg->m_Display;
m_defaultLibWidth = cfg->m_LibWidth;
GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->GetFilter() = cfg->m_SelectionFilter;
m_selectionFilterPanel->SetCheckboxesFromFilter( cfg->m_SelectionFilter );

View File

@ -349,9 +349,7 @@ private:
std::unique_ptr<FOOTPRINT> m_revertModule;
wxString m_footprintNameWhenLoaded;
int m_defaultLibWidth;
std::map<KIID, KIID> m_boardFootprintUuids;
};
#endif // FOOTPRINT_EDIT_FRAME_H

View File

@ -46,7 +46,7 @@ void FOOTPRINT_EDIT_FRAME::LoadFootprintFromBoard( wxCommandEvent& event )
}
void FOOTPRINT_EDIT_FRAME::LoadFootprintFromLibrary( LIB_ID aFPID)
void FOOTPRINT_EDIT_FRAME::LoadFootprintFromLibrary( LIB_ID aFPID )
{
bool is_last_fp_from_brd = IsCurrentFPFromBoard();
@ -243,8 +243,8 @@ void FOOTPRINT_EDIT_FRAME::SetActiveLayer( PCB_LAYER_ID aLayer )
bool FOOTPRINT_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
{
if( ! Clear_Pcb( true ) )
return false; // //this command is aborted
if( !Clear_Pcb( true ) )
return false; // this command is aborted
GetCanvas()->GetViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
ImportFootprint( aFileSet[ 0 ] );

View File

@ -862,20 +862,34 @@ bool FOOTPRINT_EDIT_FRAME::SaveFootprintToBoard( bool aAddNew )
pcbframe->GetToolManager()->RunAction( PCB_ACTIONS::selectionClear, true );
BOARD_COMMIT commit( pcbframe );
// Create the "new" footprint
FOOTPRINT* newFootprint = new FOOTPRINT( *editorFootprint );
const_cast<KIID&>( newFootprint->m_Uuid ) = KIID();
// Create a copy for the board, first using Clone() to keep existing Uuids, and then either
// resetting the uuids to the board values or assigning new Uuids.
FOOTPRINT* newFootprint = static_cast<FOOTPRINT*>( editorFootprint->Clone() );
newFootprint->SetParent( mainpcb );
newFootprint->SetLink( niluuid );
auto fixUuid =
[&]( KIID& aUuid )
{
if( editorFootprint->GetLink() != niluuid && m_boardFootprintUuids.count( aUuid ) )
aUuid = m_boardFootprintUuids[ aUuid ];
else
aUuid = KIID();
};
fixUuid( const_cast<KIID&>( newFootprint->m_Uuid ) );
newFootprint->RunOnChildren(
[&]( BOARD_ITEM* aChild )
{
fixUuid( const_cast<KIID&>( aChild->m_Uuid ) );
} );
if( sourceFootprint ) // this is an update command
{
// In the main board the new footprint replaces the old one (pos, orient, ref, value,
// connections and properties are kept) and the sourceFootprint (old footprint) is
// deleted
pcbframe->ExchangeFootprint( sourceFootprint, newFootprint, commit );
const_cast<KIID&>( newFootprint->m_Uuid ) = editorFootprint->GetLink();
commit.Push( wxT( "Update footprint" ) );
}
else // This is an insert command

View File

@ -96,6 +96,8 @@ bool FOOTPRINT_EDIT_FRAME::Clear_Pcb( bool aQuery )
if( GetBoard() == NULL )
return false;
bool is_last_fp_from_brd = IsCurrentFPFromBoard();
if( aQuery && IsContentModified() )
{
wxSafeYield( this, true ); // Allow frame to come to front before showing warning.
@ -111,6 +113,9 @@ bool FOOTPRINT_EDIT_FRAME::Clear_Pcb( bool aQuery )
}
}
if( is_last_fp_from_brd )
m_boardFootprintUuids.clear();
// Clear undo and redo lists because we want a full deletion
ClearUndoRedoList();
GetScreen()->ClrModify();

View File

@ -106,18 +106,31 @@ bool FOOTPRINT_EDIT_FRAME::LoadFootprintFromBoard( FOOTPRINT* aFootprint )
if( !Clear_Pcb( true ) )
return false;
newFootprint = (FOOTPRINT*) aFootprint->Duplicate();
m_boardFootprintUuids.clear();
auto recordAndUpdateUuid =
[&]( BOARD_ITEM* aItem )
{
KIID newId;
m_boardFootprintUuids[ newId ] = aItem->m_Uuid;
const_cast<KIID&>( aItem->m_Uuid ) = newId;
};
newFootprint = (FOOTPRINT*) aFootprint->Clone(); // Keep existing uuids
newFootprint->SetParent( GetBoard() );
newFootprint->SetLink( aFootprint->m_Uuid );
newFootprint->ClearFlags();
newFootprint->RunOnChildren( []( BOARD_ITEM* aItem )
{
if( aItem->Type() == PCB_PAD_T )
aItem->SetLocked( false );
recordAndUpdateUuid( newFootprint );
newFootprint->RunOnChildren(
[&]( BOARD_ITEM* aItem )
{
if( aItem->Type() == PCB_PAD_T )
aItem->SetLocked( false );
aItem->ClearFlags();
} );
aItem->ClearFlags();
recordAndUpdateUuid( aItem );
} );
AddFootprintToBoard( newFootprint );

View File

@ -1399,7 +1399,7 @@ void BOARD_EDITOR_CONTROL::setTransitions()
// Placing tools
Go( &BOARD_EDITOR_CONTROL::PlaceTarget, PCB_ACTIONS::placeTarget.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::PlaceFootprint, PCB_ACTIONS::placeFootprint.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::PlaceFootprint, PCB_ACTIONS::placeFootprint.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::DrillOrigin, PCB_ACTIONS::drillOrigin.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::EditFpInFpEditor, PCB_ACTIONS::editFpInFpEditor.MakeEvent() );

View File

@ -357,6 +357,8 @@ int FOOTPRINT_EDITOR_CONTROL::DeleteFootprint( const TOOL_EVENT& aEvent )
int FOOTPRINT_EDITOR_CONTROL::ImportFootprint( const TOOL_EVENT& aEvent )
{
bool is_last_fp_from_brd = m_frame->IsCurrentFPFromBoard();
if( !m_frame->Clear_Pcb( true ) )
return -1; // this command is aborted
@ -368,6 +370,13 @@ int FOOTPRINT_EDITOR_CONTROL::ImportFootprint( const TOOL_EVENT& aEvent )
frame()->ClearUndoRedoList();
// Update the save items if needed.
if( is_last_fp_from_brd )
{
m_frame->ReCreateMenuBar();
m_frame->ReCreateHToolbar();
}
m_toolMgr->RunAction( ACTIONS::zoomFitScreen, true );
m_frame->OnModify();
return 0;