Re-implement undo/redo of group ops in a pointer-safe way.

This commit is contained in:
Jeff Young 2020-09-26 01:52:03 +01:00
parent 92c8ed2943
commit 44af3978af
4 changed files with 46 additions and 15 deletions

View File

@ -69,7 +69,9 @@ enum class UNDO_REDO {
// data structure is insufficient to restore the change.
DRILLORIGIN, // origin changed (like CHANGED, contains the origin and a copy)
GRIDORIGIN, // origin changed (like CHANGED, contains the origin and a copy)
PAGESETTINGS // page settings or title block changes
PAGESETTINGS, // page settings or title block changes
GROUP,
UNGROUP
};

View File

@ -223,7 +223,6 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
case PCB_DIM_LEADER_T: // a leader dimension
case PCB_TARGET_T: // a target (graphic item)
case PCB_MARKER_T: // a marker used to show something
case PCB_GROUP_T: // a group of items
case PCB_ZONE_AREA_T:
view->Remove( boardItem );
@ -248,6 +247,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
// Metadata items
case PCB_NETINFO_T:
case PCB_GROUP_T:
if( !( changeFlags & CHT_DONE ) )
board->Remove( boardItem );
break;

View File

@ -1007,18 +1007,23 @@ int PCB_EDITOR_CONTROL::Group( const TOOL_EVENT& aEvent )
SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
const PCBNEW_SELECTION& selection = selTool->GetSelection();
BOARD* board = getModel<BOARD>();
BOARD_COMMIT commit( m_frame );
PICKED_ITEMS_LIST undoList;
if( selection.Empty() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true );
PCB_GROUP* group = new PCB_GROUP( board );
board->Add( group );
undoList.PushItem( ITEM_PICKER( nullptr, group, UNDO_REDO::NEWITEM ) );
for( EDA_ITEM* item : selection )
{
group->AddItem( static_cast<BOARD_ITEM*>( item ) );
undoList.PushItem( ITEM_PICKER( nullptr, item, UNDO_REDO::GROUP ) );
}
commit.Add( group );
commit.Push( _( "Group Items" ) );
m_frame->SaveCopyInUndoList( undoList, UNDO_REDO::GROUP );
selTool->ClearSelection();
selTool->select( group );
@ -1032,16 +1037,15 @@ int PCB_EDITOR_CONTROL::Group( const TOOL_EVENT& aEvent )
int PCB_EDITOR_CONTROL::Ungroup( const TOOL_EVENT& aEvent )
{
SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
const PCBNEW_SELECTION& selection = selTool->GetSelection();
BOARD_COMMIT commit( m_frame );
const PCBNEW_SELECTION& selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
PICKED_ITEMS_LIST undoList;
std::vector<BOARD_ITEM*> members;
if( selection.Empty() )
m_toolMgr->RunAction( PCB_ACTIONS::selectionCursor, true );
PCBNEW_SELECTION selCopy = selection;
selTool->ClearSelection();
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
for( EDA_ITEM* item : selCopy )
{
@ -1050,14 +1054,22 @@ int PCB_EDITOR_CONTROL::Ungroup( const TOOL_EVENT& aEvent )
if( group )
{
for( BOARD_ITEM* member : group->GetItems() )
selTool->select( member );
{
undoList.PushItem( ITEM_PICKER( nullptr, member, UNDO_REDO::UNGROUP ) );
members.push_back( member );
}
group->RemoveAll();
commit.Remove( group );
m_frame->GetBoard()->Remove( group );
group->SetSelected();
undoList.PushItem( ITEM_PICKER( nullptr, group, UNDO_REDO::DELETED ) );
}
}
commit.Push( "Ungroup Items" );
m_frame->SaveCopyInUndoList( undoList, UNDO_REDO::UNGROUP );
m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &members );
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
m_frame->OnModify();

View File

@ -160,6 +160,7 @@ static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem )
return false;
}
static void SwapItemData( BOARD_ITEM* aItem, BOARD_ITEM* aImage )
{
if( aImage == NULL )
@ -181,6 +182,7 @@ static void SwapItemData( BOARD_ITEM* aItem, BOARD_ITEM* aImage )
aItem->SetParent( parent );
}
void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( EDA_ITEM* aItem, UNDO_REDO aCommandType,
const wxPoint& aTransformPoint )
{
@ -303,6 +305,8 @@ void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsLis
case UNDO_REDO::NEWITEM:
case UNDO_REDO::DELETED:
case UNDO_REDO::PAGESETTINGS:
case UNDO_REDO::GROUP:
case UNDO_REDO::UNGROUP:
break;
default:
@ -400,6 +404,8 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
auto view = GetCanvas()->GetView();
auto connectivity = GetBoard()->GetConnectivity();
PCB_GROUP* group = nullptr;
// Undo in the reverse order of list creation: (this can allow stacked changes
// like the same item can be changes and deleted in the same complex command
@ -488,7 +494,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
aList->SetPickedItemStatus( UNDO_REDO::DELETED, ii );
GetModel()->Remove( (BOARD_ITEM*) eda_item );
if( eda_item->Type() != PCB_NETINFO_T )
if( eda_item->Type() != PCB_NETINFO_T && eda_item->Type() != PCB_GROUP_T )
view->Remove( eda_item );
break;
@ -497,9 +503,20 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
aList->SetPickedItemStatus( UNDO_REDO::NEWITEM, ii );
GetModel()->Add( (BOARD_ITEM*) eda_item );
if( eda_item->Type() != PCB_NETINFO_T )
if( eda_item->Type() != PCB_NETINFO_T && eda_item->Type() != PCB_GROUP_T )
view->Add( eda_item );
if( eda_item->Type() == PCB_GROUP_T )
group = static_cast<PCB_GROUP*>( eda_item );
break;
case UNDO_REDO::GROUP:
static_cast<BOARD_ITEM*>( eda_item )->SetParentGroup( nullptr );
break;
case UNDO_REDO::UNGROUP:
group->AddItem( static_cast<BOARD_ITEM*>( eda_item ) );
break;
case UNDO_REDO::MOVED: