Pcbnew: Fix issue in Undo/Redo command: for very large boards ( > 20000 items) this command could take a long time. Now fast.

This commit is contained in:
jean-pierre charras 2011-11-27 13:29:01 +01:00
parent b707493f35
commit 5e3ca2e769
1 changed files with 67 additions and 25 deletions

View File

@ -84,39 +84,73 @@ BOARD_ITEM* DuplicateStruct( BOARD_ITEM* aItem );
* - 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 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 aItem = item to find
* = NULL to build the list of existing items
*/
static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem )
{
BOARD_ITEM* item;
static std::vector<BOARD_ITEM*> itemsList;
// search in tracks:
for( item = aPcb->m_Track; item != NULL; item = item->Next() )
if( item == aItem )
return true;
if( aItem == NULL ) // Build list
{
// Count items to store in itemsList:
int icnt = 0;
BOARD_ITEM* item;
// search in modules:
for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
if( item == aItem )
return true;
// Count tracks:
for( item = aPcb->m_Track; item != NULL; item = item->Next() )
icnt++;
// Search in drawings
for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
if( item == aItem )
return true;
// Count modules:
for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
icnt++;
// Search in zones outlines
for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ )
if( aPcb->GetArea( ii ) == aItem )
return true;
// Count drawings
for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
icnt++;
// search in zones segm:
for( item = aPcb->m_Zone; item != NULL; item = item->Next() )
if( item == aItem )
return true;
// Count zones outlines
icnt += aPcb->GetAreaCount();
return false;
// 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() )
itemsList.push_back( item );
// Append modules:
for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
itemsList.push_back( item );
// Append drawings
for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
itemsList.push_back( item );
// Append zones outlines
for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ )
itemsList.push_back( aPcb->GetArea( ii ) );
// Append zones segm:
for( item = aPcb->m_Zone; item != NULL; item = item->Next() )
itemsList.push_back( item );
// Sort list
std::sort( itemsList.begin(), itemsList.end() );
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
// 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
TestForExistingItem( GetBoard(), NULL ); // Build list of existing items, for integrity test
for( int ii = aList->GetCount()-1; ii >= 0 ; ii-- )
{
item = (BOARD_ITEM*) aList->GetPickedItem( ii );
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( !TestForExistingItem( GetBoard(), item ) )
@ -516,12 +558,12 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed
// Remove this non existant item
aList->RemovePicker( ii );
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;
continue;
}
}
#endif
item->m_Flags = 0;
// see if we must rebuild ratsnets and pointers lists