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

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
Loading
Loading
Loading
Loading
+67 −25
Original line number Diff line number Diff line
@@ -84,41 +84,75 @@ 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 )
{
    static std::vector<BOARD_ITEM*> itemsList;

    if( aItem == NULL ) // Build list
    {
        // Count items to store in itemsList:
        int icnt = 0;
        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() )
        if( item == aItem )
            return true;
            itemsList.push_back( item );

    // search in modules:
        // Append modules:
        for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
        if( item == aItem )
            return true;
            itemsList.push_back( item );

    // Search in drawings
        // Append drawings
        for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
        if( item == aItem )
            return true;
            itemsList.push_back( item );

    // Search in zones outlines
        // Append zones outlines
        for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ )
        if( aPcb->GetArea( ii ) == aItem )
            return true;
            itemsList.push_back( aPcb->GetArea( ii ) );

    // search in zones segm:
        // Append zones segm:
        for( item = aPcb->m_Zone; item != NULL; item = item->Next() )
        if( item == aItem )
            return true;
            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 );
}


/**
 * Function SwapData
@@ -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