Commit 5e3ca2e7 authored by jean-pierre charras's avatar jean-pierre charras

Pcbnew: Fix issue in Undo/Redo command: for very large boards ( > 20000 items)...

Pcbnew: Fix issue in Undo/Redo command: for very large boards ( > 20000 items) this command could take a long time. Now fast.
parent b707493f
...@@ -84,39 +84,73 @@ BOARD_ITEM* DuplicateStruct( BOARD_ITEM* aItem ); ...@@ -84,39 +84,73 @@ BOARD_ITEM* DuplicateStruct( BOARD_ITEM* aItem );
* - if a call to SaveCopyInUndoList was forgotten in Pcbnew * - if a call to SaveCopyInUndoList was forgotten in Pcbnew
* - in zones outlines, when a change in one zone merges this zone with an other * - in zones outlines, when a change in one zone merges this zone with an other
* This function avoids a Pcbnew crash * This function avoids a Pcbnew crash
* Before using this function to test existence of items,
* it must be called with aItem = NULL to prepare the list
* @param aPcb = board to test * @param aPcb = board to test
* @param aItem = item to find * @param aItem = item to find
* = NULL to build the list of existing items
*/ */
static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem ) static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem )
{ {
static std::vector<BOARD_ITEM*> itemsList;
if( aItem == NULL ) // Build list
{
// Count items to store in itemsList:
int icnt = 0;
BOARD_ITEM* item; BOARD_ITEM* item;
// search in tracks: // Count tracks:
for( item = aPcb->m_Track; item != NULL; item = item->Next() )
icnt++;
// Count modules:
for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
icnt++;
// Count drawings
for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
icnt++;
// Count zones outlines
icnt += aPcb->GetAreaCount();
// Count zones segm (now obsolete):
for( item = aPcb->m_Zone; item != NULL; item = item->Next() )
icnt++;
// Build candidate list:
itemsList.clear();
itemsList.reserve(icnt);
// Store items in list:
// Append tracks:
for( item = aPcb->m_Track; item != NULL; item = item->Next() ) for( item = aPcb->m_Track; item != NULL; item = item->Next() )
if( item == aItem ) itemsList.push_back( item );
return true;
// search in modules: // Append modules:
for( item = aPcb->m_Modules; item != NULL; item = item->Next() ) for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
if( item == aItem ) itemsList.push_back( item );
return true;
// Search in drawings // Append drawings
for( item = aPcb->m_Drawings; item != NULL; item = item->Next() ) for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
if( item == aItem ) itemsList.push_back( item );
return true;
// Search in zones outlines // Append zones outlines
for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ ) for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ )
if( aPcb->GetArea( ii ) == aItem ) itemsList.push_back( aPcb->GetArea( ii ) );
return true;
// search in zones segm: // Append zones segm:
for( item = aPcb->m_Zone; item != NULL; item = item->Next() ) for( item = aPcb->m_Zone; item != NULL; item = item->Next() )
if( item == aItem ) itemsList.push_back( item );
return true;
// Sort list
std::sort( itemsList.begin(), itemsList.end() );
return false; return false;
}
// search in list:
return std::binary_search( itemsList.begin(), itemsList.end(), aItem );
} }
...@@ -504,11 +538,19 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed ...@@ -504,11 +538,19 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed
// Undo in the reverse order of list creation: (this can allow stacked changes // 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 // like the same item can be changes and deleted in the same complex command
TestForExistingItem( GetBoard(), NULL ); // Build list of existing items, for integrity test
for( int ii = aList->GetCount()-1; ii >= 0 ; ii-- ) for( int ii = aList->GetCount()-1; ii >= 0 ; ii-- )
{ {
item = (BOARD_ITEM*) aList->GetPickedItem( ii ); item = (BOARD_ITEM*) aList->GetPickedItem( ii );
wxASSERT( item ); wxASSERT( item );
#if 1
/* Test for existence of item on board.
* It could be deleted, and no more on board:
* - if a call to SaveCopyInUndoList was forgotten in Pcbnew
* - in zones outlines, when a change in one zone merges this zone with an other
* This test avoids a Pcbnew crash
*/
if( aList->GetPickedItemStatus( ii ) != UR_DELETED ) if( aList->GetPickedItemStatus( ii ) != UR_DELETED )
{ {
if( !TestForExistingItem( GetBoard(), item ) ) if( !TestForExistingItem( GetBoard(), item ) )
...@@ -516,12 +558,12 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed ...@@ -516,12 +558,12 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed
// Remove this non existant item // Remove this non existant item
aList->RemovePicker( ii ); aList->RemovePicker( ii );
ii++; // the current item was removed, ii points now the next item ii++; // the current item was removed, ii points now the next item
// whe must decrement it because it will be incremented // decrement it because it will be incremented later
not_found = true; not_found = true;
continue; continue;
} }
} }
#endif
item->m_Flags = 0; item->m_Flags = 0;
// see if we must rebuild ratsnets and pointers lists // see if we must rebuild ratsnets and pointers lists
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment