/* Copy marked items, at new position = old position + offset
 */
void CopyMarkedItems( MODULE* module, wxPoint offset )
{
    if( module == NULL )
        return;

    for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
    {
        if( !pad->IsSelected() )
            continue;

        pad->ClearFlags( SELECTED );
        D_PAD* NewPad = new D_PAD( *pad );
        NewPad->SetParent( module );
        NewPad->SetFlags( SELECTED );
        module->Pads().PushFront( NewPad );
    }

    BOARD_ITEM* newItem;

    for( BOARD_ITEM* item = module->GraphicalItems();  item;  item = item->Next() )
    {
        if( !item->IsSelected() )
            continue;

        item->ClearFlags( SELECTED );

        newItem = (BOARD_ITEM*)item->Clone();
        newItem->SetParent( module );
        newItem->SetFlags( SELECTED );
        module->GraphicalItems().PushFront( newItem );
    }

    MoveMarkedItems( module, offset );
}
/* Copy marked items, at new position = old position + offset
 */
void CopyMarkedItems( MODULE* module, wxPoint offset, bool aIncrement )
{
    if( module == NULL )
        return;

    // Reference and value cannot be copied, they are unique.
    // Ensure they are not selected
    module->Reference().ClearFlags();
    module->Value().ClearFlags();

    for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
    {
        if( !pad->IsSelected() )
            continue;

        pad->ClearFlags( SELECTED );
        D_PAD* NewPad = new D_PAD( *pad );
        NewPad->SetParent( module );
        NewPad->SetFlags( SELECTED );
        module->Pads().PushFront( NewPad );

        if( aIncrement )
            NewPad->IncrementPadName( true, true );
    }

    BOARD_ITEM* newItem;

    for( BOARD_ITEM* item = module->GraphicalItems();  item;  item = item->Next() )
    {
        if( !item->IsSelected() )
            continue;

        item->ClearFlags( SELECTED );

        newItem = (BOARD_ITEM*)item->Clone();
        newItem->SetParent( module );
        newItem->SetFlags( SELECTED );
        module->GraphicalItems().PushFront( newItem );
    }

    MoveMarkedItems( module, offset );
}
Example #3
0
void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool aSetDirtyBit )
{
    // 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();
    auto              connectivity = board->GetConnectivity();
    std::set<EDA_ITEM*>      savedModules;
    std::vector<BOARD_ITEM*> itemsToDeselect;

    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 )
                {
                    wxASSERT( changeType != CHT_MODIFY );     // too late to make a copy..
                    ent.m_copy = ent.m_item->Clone();
                }

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

                if( aCreateUndoEntry )
                {
                    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 )
                {
                    if( aCreateUndoEntry )
                    {
                        undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) );
                    }

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

                }
                else
                {
                    // modules inside modules are not supported yet
                    wxASSERT( boardItem->Type() != PCB_MODULE_T );

                    boardItem->SetParent( board->m_Modules.GetFirst() );

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

                view->Add( boardItem );
                break;
            }

            case CHT_REMOVE:
            {
                if( !m_editModules && aCreateUndoEntry )
                    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:
                    // This level can only handle module items when editing modules
                    if( !m_editModules )
                        break;

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

                        // don't allow deletion of Reference or Value
                        if( text->GetType() != TEXTE_MODULE::TEXT_is_DIVERS )
                            break;
                    }

                    view->Remove( boardItem );

                    if( !( changeFlags & CHT_DONE ) )
                    {
                        MODULE* module = static_cast<MODULE*>( boardItem->GetParent() );
                        wxASSERT( 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_AREA_T:
                    itemsToDeselect.push_back( boardItem );

                    view->Remove( boardItem );

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

                    break;

                case PCB_MODULE_T:
                {
                    itemsToDeselect.push_back( boardItem );

                    // There are no modules inside a module yet
                    wxASSERT( !m_editModules );

                    MODULE* module = static_cast<MODULE*>( boardItem );
                    view->Remove( module );
                    module->ClearFlags();

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

                    // 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
                    wxASSERT( false );
                    break;
                }

                break;
            }

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

                if( ent.m_copy )
                    connectivity->MarkItemNetAsDirty( static_cast<BOARD_ITEM*>( ent.m_copy ) );

                connectivity->Update( boardItem );
                view->Update( boardItem );

                // if no undo entry is needed, the copy would create a memory leak
                if( !aCreateUndoEntry )
                    delete ent.m_copy;

                break;
            }

            default:
                wxASSERT( false );
                break;
        }
    }

    // Removing an item should trigger the unselect action
    // but only after all items are removed otherwise we can get
    // flickering depending on the system
    if( itemsToDeselect.size() > 0 )
        m_toolMgr->RunAction( PCB_ACTIONS::unselectItems, true, &itemsToDeselect );

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

    if( TOOL_MANAGER* toolMgr = frame->GetToolManager() )
        toolMgr->PostEvent( { TC_MESSAGE, TA_MODEL_CHANGE, AS_GLOBAL } );

    if ( !m_editModules )
    {
        auto panel = static_cast<PCB_DRAW_PANEL_GAL*>( frame->GetGalCanvas() );
        connectivity->RecalculateRatsnest();
        connectivity->ClearDynamicRatsnest();
        panel->RedrawRatsnest();
    }

    if( aSetDirtyBit )
        frame->OnModify();

    frame->UpdateMsgPanel();

    clear();
}
MODULE::MODULE( const MODULE& aModule ) :
    BOARD_ITEM( aModule )
{
    m_Pos = aModule.m_Pos;
    m_fpid = aModule.m_fpid;
    m_Layer  = aModule.m_Layer;
    m_Attributs = aModule.m_Attributs;
    m_ModuleStatus = aModule.m_ModuleStatus;
    m_Orient = aModule.m_Orient;
    m_BoundaryBox = aModule.m_BoundaryBox;
    m_CntRot90 = aModule.m_CntRot90;
    m_CntRot180 = aModule.m_CntRot180;
    m_LastEditTime = aModule.m_LastEditTime;
    m_Link = aModule.m_Link;
    m_Path = aModule.m_Path;              //is this correct behavior?

    m_LocalClearance = aModule.m_LocalClearance;
    m_LocalSolderMaskMargin = aModule.m_LocalSolderMaskMargin;
    m_LocalSolderPasteMargin = aModule.m_LocalSolderPasteMargin;
    m_LocalSolderPasteMarginRatio = aModule.m_LocalSolderPasteMarginRatio;
    m_ZoneConnection = aModule.m_ZoneConnection;
    m_ThermalWidth = aModule.m_ThermalWidth;
    m_ThermalGap = aModule.m_ThermalGap;

    // Copy reference and value.
    m_Reference = new TEXTE_MODULE( *aModule.m_Reference );
    m_Reference->SetParent( this );

    m_Value = new TEXTE_MODULE( *aModule.m_Value );
    m_Value->SetParent( this );

    // Copy auxiliary data: Pads
    for( D_PAD* pad = aModule.m_Pads;  pad;  pad = pad->Next() )
    {
        D_PAD* newpad = new D_PAD( *pad );
        assert( newpad->GetNet() == pad->GetNet() );
        newpad->SetParent( this );
        m_Pads.PushBack( newpad );
    }

    // Copy auxiliary data: Drawings
    for( BOARD_ITEM* item = aModule.m_Drawings;  item;  item = item->Next() )
    {
        BOARD_ITEM* newItem;

        switch( item->Type() )
        {
        case PCB_MODULE_TEXT_T:
        case PCB_MODULE_EDGE_T:
            newItem = static_cast<BOARD_ITEM*>( item->Clone() );
            newItem->SetParent( this );
            m_Drawings.PushBack( newItem );
            break;

        default:
            wxLogMessage( wxT( "MODULE::Copy() Internal Err:  unknown type" ) );
            break;
        }
    }

    // Copy auxiliary data: 3D_Drawings info
    for( S3D_MASTER* item = aModule.m_3D_Drawings;  item;  item = item->Next() )
    {
        if( item->GetShape3DName().IsEmpty() )           // do not copy empty shapes.
            continue;

        S3D_MASTER* t3d = new S3D_MASTER( this );
        t3d->Copy( item );
        m_3D_Drawings.PushBack( t3d );
    }

    // Ensure there is at least one item in m_3D_Drawings.
    if( m_3D_Drawings.GetCount() == 0 )
        m_3D_Drawings.PushBack( new S3D_MASTER( this ) ); // push a void item

    m_Doc     = aModule.m_Doc;
    m_KeyWord = aModule.m_KeyWord;

    m_arflag = 0;

    // Ensure auxiliary data is up to date
    CalculateBoundingBox();

    m_initial_comments = aModule.m_initial_comments ?
                            new wxArrayString( *aModule.m_initial_comments ) : 0;
}