diff --git a/pcbnew/menubar_pcb_editor.cpp b/pcbnew/menubar_pcb_editor.cpp index cf9c038929..eceb584017 100644 --- a/pcbnew/menubar_pcb_editor.cpp +++ b/pcbnew/menubar_pcb_editor.cpp @@ -486,6 +486,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() toolsMenu->AddSeparator(); toolsMenu->AddItem( PCB_ACTIONS::removeUnusedPads, SELECTION_CONDITIONS::ShowAlways ); + toolsMenu->AddItem( PCB_ACTIONS::repairBoard, SELECTION_CONDITIONS::ShowAlways ); #if defined(KICAD_SCRIPTING_WXPYTHON) auto pythonConsoleShownCondition = [] ( const SELECTION& aSel ) { diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index 66a6801837..82580c40ef 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -972,6 +972,13 @@ TOOL_ACTION PCB_ACTIONS::boardReannotate( "pcbnew.ReannotateTool.ShowReannotateD _( "Geographical Reannotate..." ), _( "Reannotate PCB in geographical order" ), annotate_xpm ); +TOOL_ACTION PCB_ACTIONS::repairBoard( "pcbnew.Control.repairBoard", + AS_GLOBAL, 0, "", + _( "Repair Board" ), + _( "Run various diagnostics and attempt to repair board" ), + rescue_xpm ); + + // PLACEMENT_TOOL // TOOL_ACTION PCB_ACTIONS::alignTop( "pcbnew.AlignAndDistribute.alignTop", diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index 402c997db8..7428563102 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -408,6 +408,7 @@ public: static TOOL_ACTION showEeschema; static TOOL_ACTION boardStatistics; static TOOL_ACTION boardReannotate; + static TOOL_ACTION repairBoard; // Appearance controls static TOOL_ACTION clearHighlight; diff --git a/pcbnew/tools/pcb_editor_control.cpp b/pcbnew/tools/pcb_editor_control.cpp index 285e872e65..ff7dee2bf8 100644 --- a/pcbnew/tools/pcb_editor_control.cpp +++ b/pcbnew/tools/pcb_editor_control.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -393,6 +394,100 @@ int PCB_EDITOR_CONTROL::GenerateFabFiles( const TOOL_EVENT& aEvent ) } +int PCB_EDITOR_CONTROL::RepairBoard( const TOOL_EVENT& aEvent ) +{ + int errors = 0; + wxString details; + + /******************************* + * Repair duplicate IDs + */ + + std::set ids; + int duplicates = 0; + + auto processItem = [&]( EDA_ITEM* aItem ) + { + if( ids.count( aItem->m_Uuid ) ) + { + duplicates++; + const_cast( aItem->m_Uuid ) = KIID(); + } + + ids.insert( aItem->m_Uuid ); + }; + + // Module IDs are the most important, so give them the first crack at "owning" a particular + // KIID. + + for( MODULE* module : board()->Modules() ) + processItem( module ); + + // After that the principal use is for DRC marker pointers, which are most likely to pads + // or tracks. + + for( MODULE* module : board()->Modules() ) + { + for( D_PAD* pad : module->Pads() ) + processItem( pad ); + } + + for( TRACK* track : board()->Tracks() ) + processItem( track ); + + // From here out I don't think order matters much. + + for( MODULE* module : board()->Modules() ) + { + processItem( &module->Reference() ); + processItem( &module->Value() ); + + for( BOARD_ITEM* item : module->GraphicalItems() ) + processItem( item ); + + for( ZONE_CONTAINER* zone : module->Zones() ) + processItem( zone ); + } + + for( BOARD_ITEM* drawing : board()->Drawings() ) + processItem( drawing ); + + for( ZONE_CONTAINER* zone : board()->GetZoneList() ) + processItem( zone ); + + for( MARKER_PCB* marker : board()->Markers() ) + processItem( marker ); + + if( duplicates ) + { + errors += duplicates; + details += wxString::Format( _( "%d duplicate IDs replaced.\n" ), duplicates ); + } + + /******************************* + * Your test here + */ + + /******************************* + * Inform the user + */ + + if( errors ) + { + m_frame->OnModify(); + + wxString msg = wxString::Format( _( "%d potential problems repaired." ), errors ); + DisplayInfoMessage( m_frame, msg, details ); + } + else + { + DisplayInfoMessage( m_frame, _( "No board problems found." ) ); + } + + return 0; +} + + int PCB_EDITOR_CONTROL::UpdatePCBFromSchematic( const TOOL_EVENT& aEvent ) { NETLIST netlist; @@ -1249,6 +1344,7 @@ void PCB_EDITOR_CONTROL::setTransitions() Go( &PCB_EDITOR_CONTROL::ToggleMicrowaveToolbar, PCB_ACTIONS::showMicrowaveToolbar.MakeEvent() ); Go( &PCB_EDITOR_CONTROL::TogglePythonConsole, PCB_ACTIONS::showPythonConsole.MakeEvent() ); Go( &PCB_EDITOR_CONTROL::FlipPcbView, PCB_ACTIONS::flipBoard.MakeEvent() ); + Go( &PCB_EDITOR_CONTROL::RepairBoard, PCB_ACTIONS::repairBoard.MakeEvent() ); } diff --git a/pcbnew/tools/pcb_editor_control.h b/pcbnew/tools/pcb_editor_control.h index b0548bb12f..0324d92571 100644 --- a/pcbnew/tools/pcb_editor_control.h +++ b/pcbnew/tools/pcb_editor_control.h @@ -66,6 +66,7 @@ public: int GenerateDrillFiles( const TOOL_EVENT& aEvent ); int GeneratePosFile( const TOOL_EVENT& aEvent ); int GenerateFabFiles( const TOOL_EVENT& aEvent ); + int RepairBoard( const TOOL_EVENT& aEvent ); int UpdatePCBFromSchematic( const TOOL_EVENT& aEvent ); int UpdateSchematicFromPCB( const TOOL_EVENT& aEvent );