예제 #1
0
파일: edit_tool.cpp 프로젝트: OpenEE/micad
int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();

    // Shall the selection be cleared at the end?
    bool unselect = selection.Empty();

    if( !hoverSelection( selection ) )
        return 0;

    wxPoint translation;
    double rotation = 0;

    PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();

    DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation );
    int ret = dialog.ShowModal();

    if( ret == wxID_OK )
    {
        if( !isUndoInhibited() )
        {
            editFrame->OnModify();
            // Record an action of move and rotate
            editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED );
        }

        VECTOR2I rp = selection.GetCenter();
        wxPoint rotPoint( rp.x, rp.y );

        for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
        {
            BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );

            item->Move( translation );
            item->Rotate( rotPoint, rotation );

            if( !m_dragging )
                item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }

        updateRatsnest( m_dragging );

        if( m_dragging )
            selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        else
            getModel<BOARD>()->GetRatsnest()->Recalculate();

        if( unselect )
            m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );

        m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true );
    }

    return 0;
}
예제 #2
0
int EDIT_TOOL::Flip( TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();
    PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();

    // Shall the selection be cleared at the end?
    bool unselect = selection.Empty();

    if( !makeSelection( selection ) || m_selectionTool->CheckLock() )
    {
        setTransitions();

        return 0;
    }

    wxPoint flipPoint = getModificationPoint( selection );

    if( !m_dragging )   // If it is being dragged, then it is already saved with UR_CHANGED flag
    {
        editFrame->OnModify();
        editFrame->SaveCopyInUndoList( selection.items, UR_FLIPPED, flipPoint );
    }

    for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
    {
        BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );

        item->Flip( flipPoint );

        if( !m_dragging )
            item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
    }

    updateRatsnest( m_dragging );

    // Update dragging offset (distance between cursor and the first dragged item)
    m_offset = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( 0 ) )->GetPosition() -
                                         flipPoint;

    if( m_dragging )
        selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
    else
        getModel<BOARD>()->GetRatsnest()->Recalculate();

    if( unselect )
        m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );

    m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true );
    setTransitions();

    return 0;
}
예제 #3
0
int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();

    // Shall the selection be cleared at the end?
    bool unselect = selection.Empty();

    if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED )
        return 0;

    wxPoint translation;
    double rotation = 0;

    PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();

    DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation );
    int ret = dialog.ShowModal();

    if( ret == wxID_OK )
    {
        VECTOR2I rp = selection.GetCenter();
        wxPoint rotPoint( rp.x, rp.y );

        for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
        {
            BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );

            m_commit->Modify( item );
            item->Move( translation );
            item->Rotate( rotPoint, rotation );

            if( !m_dragging )
                item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }

        m_commit->Push( _( "Move exact" ) );

        if( unselect )
            m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );

        m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true );
    }

    return 0;
}
예제 #4
0
int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();
    PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();

    if( !hoverSelection( selection, false ) )
        return 0;

    // Properties are displayed when there is only one item selected
    if( selection.Size() == 1 )
    {
        // Display properties dialog
        BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 );

        std::vector<PICKED_ITEMS_LIST*>& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList;

        // Some of properties dialogs alter pointers, so we should deselect them
        m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
        STATUS_FLAGS flags = item->GetFlags();
        item->ClearFlags();

        // It is necessary to determine if anything has changed
        PICKED_ITEMS_LIST* lastChange = undoList.empty() ? NULL : undoList.back();

        // Display properties dialog
        editFrame->OnEditItemRequest( NULL, item );

        PICKED_ITEMS_LIST* currentChange = undoList.empty() ? NULL : undoList.back();

        if( lastChange != currentChange )        // Something has changed
        {
            processChanges( currentChange );

            updateRatsnest( true );
            getModel<BOARD>()->GetRatsnest()->Recalculate();
            item->ViewUpdate();

            m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true );
        }

        item->SetFlags( flags );
    }

    return 0;
}
예제 #5
0
파일: edit_tool.cpp 프로젝트: morio/kicad
void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList )
{
    KIGFX::VIEW* view = getView();
    RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();

    for( unsigned int i = 0; i < aList->GetCount(); ++i )
    {
        UNDO_REDO_T operation = aList->GetPickedItemStatus( i );
        BOARD_ITEM* updItem = static_cast<BOARD_ITEM*>( aList->GetPickedItem( i ) );

        switch( operation )
        {
        case UR_CHANGED:
            ratsnest->Update( updItem );
            // fall through

        case UR_MODEDIT:
            updItem->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            break;

        case UR_DELETED:
            if( updItem->Type() == PCB_MODULE_T )
                static_cast<MODULE*>( updItem )->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove,
                                                                             view, _1 ) );

            view->Remove( updItem );
            //ratsnest->Remove( updItem );  // this is done in BOARD::Remove
            break;

        case UR_NEW:
            if( updItem->Type() == PCB_MODULE_T )
                static_cast<MODULE*>( updItem )->RunOnChildren( boost::bind( &KIGFX::VIEW::Add,
                                                                             view, _1 ) );

            view->Add( updItem );
            //ratsnest->Add( updItem );     // this is done in BOARD::Add
            break;

        default:
            assert( false );    // Not handled
            break;
        }
    }
}
예제 #6
0
void MODULE::ViewUpdate( int aUpdateFlags )
{
    if( !m_view )
        return;

    // Update the module itself
    VIEW_ITEM::ViewUpdate( aUpdateFlags );

    // Update pads
    for( D_PAD* pad = m_Pads.GetFirst(); pad; pad = pad->Next() )
        pad->ViewUpdate( aUpdateFlags );

    // Update module's drawing (mostly silkscreen)
    for( BOARD_ITEM* drawing = m_Drawings.GetFirst(); drawing; drawing = drawing->Next() )
        drawing->ViewUpdate( aUpdateFlags );

    // Update module's texts
    m_Reference->ViewUpdate( aUpdateFlags );
    m_Value->ViewUpdate( aUpdateFlags );
}
void SELECTION_TOOL::clearSelection()
{
    if( m_selection.Empty() )
        return;

    KIGFX::VIEW_GROUP::const_iter it, it_end;

    // Restore the initial properties
    for( it = m_selection.group->Begin(), it_end = m_selection.group->End(); it != it_end; ++it )
    {
        BOARD_ITEM* item = static_cast<BOARD_ITEM*>( *it );

        item->ViewHide( false );
        item->ClearSelected();
        item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ) ;
    }
    m_selection.clear();

    m_frame->SetCurItem( NULL );
    m_locked = true;

    // Inform other potentially interested tools
    m_toolMgr->ProcessEvent( ClearedEvent );
}
int PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent )
{
    SELECTION selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
    BOARD* board = getModel<BOARD>();
    RN_DATA* ratsnest = board->GetRatsnest();
    KIGFX::VIEW* view = getView();

    if( selection.Size() < 2 )
        return 0;

    PICKED_ITEMS_LIST changes;
    int netcode = -1;

    // Loop through all combinations
    for( int ia1 = 0; ia1 < selection.Size() - 1; ++ia1 )
    {
        ZONE_CONTAINER* curr_area = dynamic_cast<ZONE_CONTAINER*>( selection.Item<EDA_ITEM>( ia1 ) );

        if( !curr_area )
            continue;

        netcode = curr_area->GetNetCode();

        EDA_RECT b1 = curr_area->Outline()->GetBoundingBox();
        bool mod_ia1 = false;

        for( int ia2 = selection.Size() - 1; ia2 > ia1; --ia2 )
        {
            ZONE_CONTAINER* area2 = dynamic_cast<ZONE_CONTAINER*>( selection.Item<EDA_ITEM>( ia2 ) );

            if( !area2 )
                continue;

            if( area2->GetNetCode() != netcode )
                continue;

            if( curr_area->GetPriority() != area2->GetPriority() )
                continue;

            if( curr_area->GetIsKeepout() != area2->GetIsKeepout() )
                continue;

            if( curr_area->GetLayer() != area2->GetLayer() )
                continue;

            EDA_RECT b2 = area2->Outline()->GetBoundingBox();

            if( b1.Intersects( b2 ) )
            {
                EDA_ITEM* backup = curr_area->Clone();
                bool ret = board->TestAreaIntersection( curr_area, area2 );

                if( ret && board->CombineAreas( &changes, curr_area, area2 ) )
                {
                    mod_ia1 = true;
                    selection.items.RemovePicker( ia2 );

                    ITEM_PICKER picker( curr_area, UR_CHANGED );
                    picker.SetLink( backup );
                    changes.PushItem( picker );
                }
                else
                {
                    delete backup;
                }
            }
        }

        if( mod_ia1 )
            --ia1;     // if modified, we need to check it again
    }

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
    m_frame->SaveCopyInUndoList( changes, UR_UNSPECIFIED );

    for( unsigned i = 0; i < changes.GetCount(); ++i )
    {
        ITEM_PICKER picker = changes.GetItemWrapper( i );
        BOARD_ITEM* item = static_cast<BOARD_ITEM*>( picker.GetItem() );

        if( picker.GetStatus() == UR_DELETED )
        {
            view->Remove( item );
            ratsnest->Remove( item );
        }
        else if( picker.GetStatus() == UR_CHANGED )
        {
            item->ViewUpdate( KIGFX::VIEW_ITEM::ALL );
            m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, item );
        }
    }

    return 0;
}
예제 #9
0
파일: edit_tool.cpp 프로젝트: OpenEE/micad
int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();
    PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();

    // Shall the selection be cleared at the end?
    bool unselect = selection.Empty();

    if( !hoverSelection( selection, false ) )
        return 0;

    // Tracks & vias are treated in a special way:
    if( ( SELECTION_CONDITIONS::OnlyTypes( m_tracksViasType ) )( selection ) )
    {
        DIALOG_TRACK_VIA_PROPERTIES dlg( editFrame, selection );

        if( dlg.ShowModal() )
        {
            RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();

            editFrame->OnModify();
            editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED );
            dlg.Apply();

            selection.ForAll<KIGFX::VIEW_ITEM>( boost::bind( &KIGFX::VIEW_ITEM::ViewUpdate, _1,
                                                KIGFX::VIEW_ITEM::ALL ) );
            selection.ForAll<BOARD_ITEM>( boost::bind( &RN_DATA::Update, ratsnest, _1 ) );
            ratsnest->Recalculate();
        }
    }
    else if( selection.Size() == 1 ) // Properties are displayed when there is only one item selected
    {
        // Display properties dialog
        BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 );

        // Store the head of the undo list to compare if anything has changed
        std::vector<PICKED_ITEMS_LIST*>& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList;

        // Some of properties dialogs alter pointers, so we should deselect them
        m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
        STATUS_FLAGS flags = item->GetFlags();
        item->ClearFlags();

        // It is necessary to determine if anything has changed, so store the current undo save point
        PICKED_ITEMS_LIST* undoSavePoint = undoList.empty() ? NULL : undoList.back();

        // Display properties dialog provided by the legacy canvas frame
        editFrame->OnEditItemRequest( NULL, item );

        if( !undoList.empty() && undoList.back() != undoSavePoint )      // Undo buffer has changed
        {
            // Process changes stored after undoSavePoint
            processUndoBuffer( undoSavePoint );

            // Update the modified item
            item->ViewUpdate();
            RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest();
            ratsnest->Recalculate();

            // TODO OBSERVER! I miss you so much..
            m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true );
        }

        item->SetFlags( flags );
    }

    if( unselect )
        m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );

    return 0;
}
예제 #10
0
int EDIT_TOOL::Properties( TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();
    PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();

    if( !makeSelection( selection ) )
    {
        setTransitions();

        return 0;
    }

    // Properties are displayed when there is only one item selected
    if( selection.Size() == 1 )
    {
        // Display properties dialog
        BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 );

        // Check if user wants to edit pad or module properties
        if( item->Type() == PCB_MODULE_T )
        {
            VECTOR2D cursor = getViewControls()->GetCursorPosition();

            for( D_PAD* pad = static_cast<MODULE*>( item )->Pads(); pad; pad = pad->Next() )
            {
                if( pad->ViewBBox().Contains( cursor ) )
                {
                    // Turns out that user wants to edit a pad properties
                    item = pad;
                    break;
                }
            }
        }

        std::vector<PICKED_ITEMS_LIST*>& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList;

        // Some of properties dialogs alter pointers, so we should deselect them
        m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
        STATUS_FLAGS flags = item->GetFlags();
        item->ClearFlags();

        // It is necessary to determine if anything has changed
        PICKED_ITEMS_LIST* lastChange = undoList.empty() ? NULL : undoList.back();

        // Display properties dialog
        editFrame->OnEditItemRequest( NULL, item );

        PICKED_ITEMS_LIST* currentChange = undoList.empty() ? NULL : undoList.back();

        if( lastChange != currentChange )        // Something has changed
        {
            processChanges( currentChange );

            updateRatsnest( true );
            getModel<BOARD>()->GetRatsnest()->Recalculate();
            item->ViewUpdate();

            m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true );
        }

        item->SetFlags( flags );
    }

    setTransitions();

    return 0;
}
void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand,
                                             bool aRebuildRatsnet )
{
    BOARD_ITEM* item;
    bool        not_found = false;
    bool        reBuild_ratsnest = false;
    KIGFX::VIEW* view = GetGalCanvas()->GetView();
    RN_DATA* ratsnest = GetBoard()->GetRatsnest();

    // 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

    bool build_item_list = true;    // if true the list of existing items must be rebuilt

    for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- )
    {
        item = (BOARD_ITEM*) aList->GetPickedItem( ii );
        wxASSERT( item );

        /* 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
         * Obviously, this test is not made for deleted items
         */
        UNDO_REDO_T status = aList->GetPickedItemStatus( ii );

        if( status != UR_DELETED )
        {
            if( build_item_list )
                // Build list of existing items, for integrity test
                TestForExistingItem( GetBoard(), NULL );

            build_item_list = false;

            if( !TestForExistingItem( GetBoard(), item ) )
            {
                // Remove this non existent item
                aList->RemovePicker( ii );
                ii++;       // the current item was removed, ii points now the next item
                            // decrement it because it will be incremented later
                not_found = true;
                continue;
            }
        }

        item->ClearFlags();

        // see if we must rebuild ratsnets and pointers lists
        switch( item->Type() )
        {
        case PCB_MODULE_T:
        case PCB_ZONE_AREA_T:
        case PCB_TRACE_T:
        case PCB_VIA_T:
            reBuild_ratsnest = true;
            break;

        default:
            break;
        }

        switch( aList->GetPickedItemStatus( ii ) )
        {
        case UR_CHANGED:    /* Exchange old and new data for each item */
        {
            BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii );

            // Remove all pads/drawings/texts, as they become invalid
            // for the VIEW after SwapData() called for modules
            if( item->Type() == PCB_MODULE_T )
            {
                MODULE* oldModule = static_cast<MODULE*>( item );
                oldModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) );
            }
            ratsnest->Remove( item );

            item->SwapData( image );

            // Update all pads/drawings/texts, as they become invalid
            // for the VIEW after SwapData() called for modules
            if( item->Type() == PCB_MODULE_T )
            {
                MODULE* newModule = static_cast<MODULE*>( item );
                newModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) );
            }
            ratsnest->Add( item );

            item->ClearFlags( SELECTED );
            item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
        }
        break;

        case UR_NEW:        /* new items are deleted */
            aList->SetPickedItemStatus( UR_DELETED, ii );
            GetBoard()->Remove( item );

            if( item->Type() == PCB_MODULE_T )
            {
                MODULE* module = static_cast<MODULE*>( item );
                module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) );
            }
            view->Remove( item );

            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            break;

        case UR_DELETED:    /* deleted items are put in List, as new items */
            aList->SetPickedItemStatus( UR_NEW, ii );
            GetBoard()->Add( item );

            if( item->Type() == PCB_MODULE_T )
            {
                MODULE* module = static_cast<MODULE*>( item );
                module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1) );
            }
            view->Add( item );

            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            build_item_list = true;
            break;

        case UR_MOVED:
            item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint );
            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            ratsnest->Update( item );
            break;

        case UR_ROTATED:
            item->Rotate( aList->m_TransformPoint,
                          aRedoCommand ? m_rotationAngle : -m_rotationAngle );
            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            ratsnest->Update( item );
            break;

        case UR_ROTATED_CLOCKWISE:
            item->Rotate( aList->m_TransformPoint,
                          aRedoCommand ? -m_rotationAngle : m_rotationAngle );
            item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
            ratsnest->Update( item );
            break;

        case UR_FLIPPED:
            item->Flip( aList->m_TransformPoint );
            item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
            ratsnest->Update( item );
            break;

        default:
        {
            wxString msg;
            msg.Printf( wxT( "PutDataInPreviousState() error (unknown code %X)" ),
                        aList->GetPickedItemStatus( ii ) );
            wxMessageBox( msg );
        }
        break;
        }
    }

    if( not_found )
        wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) );

    // Rebuild pointers and ratsnest that can be changed.
    if( reBuild_ratsnest && aRebuildRatsnet )
    {
        if( IsGalCanvasActive() )
            ratsnest->Recalculate();
        else
            Compile_Ratsnest( NULL, true );
    }
}
예제 #12
0
void BOARD_COMMIT::Push( const wxString& aMessage )
{
    // Objects potentially interested in changes:
    PICKED_ITEMS_LIST undoList;
    KIGFX::VIEW* view = m_toolMgr->GetView();
    BOARD* board = (BOARD*) m_toolMgr->GetModel();
    PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame();
    RN_DATA* ratsnest = board->GetRatsnest();
    std::set<EDA_ITEM*> savedModules;

    if( Empty() )
        return;

    for( COMMIT_LINE& ent : m_changes )
    {
        int changeType = ent.m_type & CHT_TYPE;
        int changeFlags = ent.m_type & CHT_FLAGS;
        BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );

        // Module items need to be saved in the undo buffer before modification
        if( m_editModules )
        {
            // Be sure that we are storing a module
            if( ent.m_item->Type() != PCB_MODULE_T )
                ent.m_item = ent.m_item->GetParent();

            // We have not saved the module yet, so let's create an entry
            if( savedModules.count( ent.m_item ) == 0 )
            {
                if( !ent.m_copy )
                {
                    assert( changeType != CHT_MODIFY );     // too late to make a copy..
                    ent.m_copy = ent.m_item->Clone();
                }

                assert( ent.m_item->Type() == PCB_MODULE_T );
                assert( ent.m_copy->Type() == PCB_MODULE_T );

                ITEM_PICKER itemWrapper( ent.m_item, UR_CHANGED );
                itemWrapper.SetLink( ent.m_copy );
                undoList.PushItem( itemWrapper );
                frame->SaveCopyInUndoList( undoList, UR_CHANGED );

                savedModules.insert( ent.m_item );
                static_cast<MODULE*>( ent.m_item )->SetLastEditTime();
            }
        }

        switch( changeType )
        {
            case CHT_ADD:
            {
                if( !m_editModules )
                {
                    undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) );

                    if( !( changeFlags & CHT_DONE ) )
                        board->Add( boardItem );

                    //ratsnest->Add( boardItem );       // TODO currently done by BOARD::Add()

                    if( boardItem->Type() == PCB_MODULE_T )
                    {
                        MODULE* mod = static_cast<MODULE*>( boardItem );
                        mod->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) );
                    }
                }
                else
                {
                    // modules inside modules are not supported yet
                    assert( boardItem->Type() != PCB_MODULE_T );

                    if( !( changeFlags & CHT_DONE ) )
                        board->m_Modules->Add( boardItem );
                }

                view->Add( boardItem );
                break;
            }

            case CHT_REMOVE:
            {
                if( !m_editModules )
                {
                    undoList.PushItem( ITEM_PICKER( boardItem, UR_DELETED ) );
                }

                switch( boardItem->Type() )
                {
                // Module items
                case PCB_PAD_T:
                case PCB_MODULE_EDGE_T:
                case PCB_MODULE_TEXT_T:
                {
                    // Do not allow footprint text removal when not editing a module
                    if( !m_editModules )
                        break;

                    bool remove = true;

                    if( boardItem->Type() == PCB_MODULE_TEXT_T )
                    {
                        TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( boardItem );

                        switch( text->GetType() )
                        {
                            case TEXTE_MODULE::TEXT_is_REFERENCE:
                                //DisplayError( frame, _( "Cannot delete component reference." ) );
                                remove = false;
                                break;

                            case TEXTE_MODULE::TEXT_is_VALUE:
                                //DisplayError( frame, _( "Cannot delete component value." ) );
                                remove = false;
                                break;

                            case TEXTE_MODULE::TEXT_is_DIVERS:    // suppress warnings
                                break;

                            default:
                                assert( false );
                                break;
                        }
                    }

                    if( remove )
                    {
                        view->Remove( boardItem );

                        if( !( changeFlags & CHT_DONE ) )
                        {
                            MODULE* module = static_cast<MODULE*>( boardItem->GetParent() );
                            assert( module && module->Type() == PCB_MODULE_T );
                            module->Delete( boardItem );
                        }

                        board->m_Status_Pcb = 0; // it is done in the legacy view (ratsnest perhaps?)
                    }

                    break;
                }

                // Board items
                case PCB_LINE_T:                // a segment not on copper layers
                case PCB_TEXT_T:                // a text on a layer
                case PCB_TRACE_T:               // a track segment (segment on a copper layer)
                case PCB_VIA_T:                 // a via (like track segment on a copper layer)
                case PCB_DIMENSION_T:           // a dimension (graphic item)
                case PCB_TARGET_T:              // a target (graphic item)
                case PCB_MARKER_T:              // a marker used to show something
                case PCB_ZONE_T:                // SEG_ZONE items are now deprecated
                case PCB_ZONE_AREA_T:
                    view->Remove( boardItem );

                    if( !( changeFlags & CHT_DONE ) )
                        board->Remove( boardItem );

                    //ratsnest->Remove( boardItem );    // currently done by BOARD::Remove()
                    break;

                case PCB_MODULE_T:
                {
                    // There are no modules inside a module yet
                    assert( !m_editModules );

                    MODULE* module = static_cast<MODULE*>( boardItem );
                    module->ClearFlags();
                    module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) );

                    view->Remove( module );

                    if( !( changeFlags & CHT_DONE ) )
                        board->Remove( module );

                    // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore
                    board->m_Status_Pcb = 0;
                }
                break;

                default:                        // other types do not need to (or should not) be handled
                    assert( false );
                    break;
                }
                break;
            }

            case CHT_MODIFY:
            {
                if( !m_editModules )
                {
                    ITEM_PICKER itemWrapper( boardItem, UR_CHANGED );
                    assert( ent.m_copy );
                    itemWrapper.SetLink( ent.m_copy );
                    undoList.PushItem( itemWrapper );
                }

                boardItem->ViewUpdate( KIGFX::VIEW_ITEM::ALL );
                ratsnest->Update( boardItem );
                break;
            }

            default:
                assert( false );
                break;
        }
    }

    if( !m_editModules )
        frame->SaveCopyInUndoList( undoList, UR_UNSPECIFIED );

    frame->OnModify();
    ratsnest->Recalculate();

    clear();
}