KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_drc.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2009-2016 Dick Hollenbeck, [email protected]
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <confirm.h>
27#include <dialog_drc.h>
29#include <kiface_base.h>
30#include <macros.h>
31#include <pad.h>
32#include <drc/drc_item.h>
33#include <drc/drc_report.h>
37#include <pcb_edit_frame.h>
38#include <pcbnew_settings.h>
39#include <tool/tool_manager.h>
40#include <tools/pcb_actions.h>
42#include <pcb_marker.h>
43#include <pgm_base.h>
44#include <wx/app.h>
45#include <wx/filedlg.h>
46#include <wx/msgdlg.h>
47#include <wx/wupdlock.h>
49#include <widgets/ui_common.h>
54#include <tools/drc_tool.h>
57#include <kiplatform/ui.h>
58#include <advanced_config.h>
59
60// wxWidgets spends *far* too long calcuating column widths (most of it, believe it or
61// not, in repeatedly creating/destroying a wxDC to do the measurement in).
62// Use default column widths instead.
63static int DEFAULT_SINGLE_COL_WIDTH = 660;
64
65static BOARD* g_lastDRCBoard = nullptr;
66static bool g_lastDRCRun = false;
67static bool g_lastFootprintTestsRun = false;
68
69static std::vector<std::pair<wxString, int>> g_lastIgnored;
70
71
72DIALOG_DRC::DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
73 DIALOG_DRC_BASE( aParent ),
75 m_running( false ),
76 m_drcRun( false ),
77 m_footprintTestsRun( false ),
78 m_markersTreeModel( nullptr ),
79 m_unconnectedTreeModel( nullptr ),
80 m_fpWarningsTreeModel( nullptr ),
82 m_lastUpdateUi( std::chrono::steady_clock::now() )
83{
84 SetName( DIALOG_DRC_WINDOW_NAME ); // Set a window name to be able to find it
86
87 m_frame = aEditorFrame;
89
91
94
95 m_markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_currentBoard,
98
99 m_ratsnestProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_currentBoard,
101
102 m_fpWarningsProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_currentBoard,
104
106 m_markerDataView->AssociateModel( m_markersTreeModel );
108
112
116
117 m_ignoredList->InsertColumn( 0, wxEmptyString, wxLIST_FORMAT_LEFT, DEFAULT_SINGLE_COL_WIDTH );
118
120 {
123
124 for( const auto& [ str, code ] : g_lastIgnored )
125 {
126 wxListItem listItem;
127 listItem.SetId( m_ignoredList->GetItemCount() );
128 listItem.SetText( str );
129 listItem.SetData( code );
130
131 m_ignoredList->InsertItem( listItem );
132 }
133 }
134
135 m_Notebook->SetSelection( 0 );
136
137 if( Kiface().IsSingle() )
138 m_cbTestFootprints->Hide();
139
140 SetupStandardButtons( { { wxID_OK, _( "Run DRC" ) },
141 { wxID_CANCEL, _( "Close" ) } } );
142
143 m_markersTitleTemplate = m_Notebook->GetPageText( 0 );
144 m_unconnectedTitleTemplate = m_Notebook->GetPageText( 1 );
145 m_footprintsTitleTemplate = m_Notebook->GetPageText( 2 );
146 m_ignoredTitleTemplate = m_Notebook->GetPageText( 3 );
147
148 m_cbRefillZones->SetValue( cfg->m_DrcDialog.refill_zones );
150
151 if( !Kiface().IsSingle() )
153
154 Layout(); // adding the units above expanded Clearance text, now resize.
155
156 SetFocus();
157
159
161}
162
163
165{
166 m_frame->FocusOnItem( nullptr );
167
171
172 g_lastIgnored.clear();
173
174 for( int ii = 0; ii < m_ignoredList->GetItemCount(); ++ii )
175 {
176 g_lastIgnored.push_back( { m_ignoredList->GetItemText( ii ),
177 m_ignoredList->GetItemData( ii ) } );
178 }
179
180 PCBNEW_SETTINGS* cfg = nullptr;
181
182 try
183 {
184 cfg = m_frame->GetPcbNewSettings();
185 }
186 catch( const std::runtime_error& e )
187 {
188 wxFAIL_MSG( e.what() );
189 }
190
191 if( cfg )
192 {
193 cfg->m_DrcDialog.refill_zones = m_cbRefillZones->GetValue();
195
196 if( !Kiface().IsSingle() )
198
200 }
201
202 m_markersTreeModel->DecRef();
203 m_unconnectedTreeModel->DecRef();
204 m_fpWarningsTreeModel->DecRef();
205}
206
207
208void DIALOG_DRC::OnActivateDlg( wxActivateEvent& aEvent )
209{
211 {
212 // If m_currentBoard is not the current board, (for instance because a new board
213 // was loaded), close the dialog, because many pointers are now invalid in lists
214 SetReturnCode( wxID_CANCEL );
215 Close();
216
218 drcTool->DestroyDRCDialog();
219 }
220}
221
222
223// PROGRESS_REPORTER calls
224
226{
227 double cur = std::clamp( (double) m_progress.load() / m_maxProgress, 0.0, 1.0 );
228
229 int newValue = KiROUND( cur * 1000.0 );
230 m_gauge->SetValue( newValue );
231
232 // There is significant overhead on at least Windows when updateUi is called constantly thousands of times
233 // in the drc process and safeyieldfor is called each time.
234 // Gate the yield to a limited rate which still allows the UI to function without slowing down the main thread
235 // which is also running DRC
236 std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
237 if( std::chrono::duration_cast<std::chrono::milliseconds>( now - m_lastUpdateUi ).count()
238 > 100 )
239 {
240 Pgm().App().SafeYieldFor( this, wxEVT_CATEGORY_NATIVE_EVENTS );
241 m_lastUpdateUi = now;
242 }
243
244 return !m_cancelled;
245}
246
247
248void DIALOG_DRC::AdvancePhase( const wxString& aMessage )
249{
251 SetCurrentProgress( 0.0 );
252
253 m_messages->Report( aMessage );
254}
255
256
257// Don't globally define this; different facilities use different definitions of "ALL"
259
260
262{
267}
268
269
270void DIALOG_DRC::OnErrorLinkClicked( wxHtmlLinkEvent& event )
271{
272 m_frame->ShowBoardSetupDialog( _( "Custom Rules" ) );
273}
274
275
276void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
277{
278 TOOL_MANAGER* toolMgr = m_frame->GetToolManager();
279 DRC_TOOL* drcTool = toolMgr->GetTool<DRC_TOOL>();
280 ZONE_FILLER_TOOL* zoneFillerTool = toolMgr->GetTool<ZONE_FILLER_TOOL>();
281 bool refillZones = m_cbRefillZones->GetValue();
282 bool reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue();
283 bool testFootprints = m_cbTestFootprints->GetValue();
284
285 if( zoneFillerTool->IsBusy() )
286 {
287 wxBell();
288 return;
289 }
290
291 // This is not the time to have stale or buggy rules. Ensure they're up-to-date
292 // and that they at least parse.
293 try
294 {
295 drcTool->GetDRCEngine()->InitEngine( m_frame->GetDesignRulesPath() );
296 }
297 catch( PARSE_ERROR& )
298 {
299 m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
300 m_DeleteCurrentMarkerButton->Enable( false );
301 m_DeleteAllMarkersButton->Enable( false );
302 m_saveReport->Enable( false );
303
304 m_messages->Clear();
305 m_messages->Report( _( "DRC incomplete: could not compile custom design rules." )
306 + wxS( "&nbsp;&nbsp;" )
307 + wxS( "<a href='$CUSTOM_RULES'>" ) + _( "Show design rules." ) + wxT( "</a>" ) );
308 m_messages->Flush();
309
310 Raise();
311
312 // set float level again, it can be lost due to window events during test run
314 return;
315 }
316
317 m_footprintTestsRun = false;
318 m_cancelled = false;
319
321 deleteAllMarkers( true );
322
323 std::vector<std::reference_wrapper<RC_ITEM>> violations = DRC_ITEM::GetItemsWithSeverities();
324 m_ignoredList->DeleteAllItems();
325
326 for( std::reference_wrapper<RC_ITEM>& item : violations )
327 {
328 if( bds().GetSeverity( item.get().GetErrorCode() ) == RPT_SEVERITY_IGNORE )
329 {
330 wxListItem listItem;
331 listItem.SetId( m_ignoredList->GetItemCount() );
332 listItem.SetText( wxT( " • " ) + item.get().GetErrorText() );
333 listItem.SetData( item.get().GetErrorCode() );
334
335 m_ignoredList->InsertItem( listItem );
336 }
337 }
338
339 m_ignoredList->SetColumnWidth( 0, m_ignoredList->GetParent()->GetClientSize().x - 20 );
340
341 Raise();
342
343 m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
344 m_messages->Clear();
345 wxYield(); // Allow time slice to refresh Messages
346
347 m_running = true;
348 m_sdbSizerCancel->SetLabel( _( "Cancel" ) );
349 m_sdbSizerOK->Enable( false );
350 m_DeleteCurrentMarkerButton->Enable( false );
351 m_DeleteAllMarkersButton->Enable( false );
352 m_saveReport->Enable( false );
353
354 {
355 wxBusyCursor dummy;
356 drcTool->RunTests( this, refillZones, reportAllTrackErrors, testFootprints );
357 }
358
359 if( m_cancelled )
360 m_messages->Report( _( "-------- DRC cancelled by user.<br><br>" ) );
361 else
362 m_messages->Report( _( "Done.<br><br>" ) );
363
364 Raise();
365 wxYield(); // Allow time slice to refresh Messages
366
367 m_running = false;
368 m_sdbSizerCancel->SetLabel( _( "Close" ) );
369 m_sdbSizerOK->Enable( true );
370 m_DeleteCurrentMarkerButton->Enable( true );
371 m_DeleteAllMarkersButton->Enable( true );
372 m_saveReport->Enable( true );
373
374 if( !m_cancelled )
375 {
376 m_sdbSizerCancel->SetDefault();
377 // wxWidgets has a tendency to keep both buttons highlighted without the following:
378 m_sdbSizerOK->Enable( false );
379
380 wxMilliSleep( 500 );
381 m_runningResultsBook->ChangeSelection( 1 );
383
384 // now re-enable m_sdbSizerOK button
385 m_sdbSizerOK->Enable( true );
386 }
387
388 // set float level again, it can be lost due to window events during test run
391}
392
393
395{
399
401}
402
403
404void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
405{
406 BOARD* board = m_frame->GetBoard();
407 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
408
409 auto getActiveLayers =
410 []( BOARD_ITEM* aItem ) -> LSET
411 {
412 if( aItem->Type() == PCB_PAD_T )
413 {
414 PAD* pad = static_cast<PAD*>( aItem );
415 LSET layers;
416
417 for( int layer : aItem->GetLayerSet().Seq() )
418 {
419 if( pad->FlashLayer( layer ) )
420 layers.set( layer );
421 }
422
423 return layers;
424 }
425 else
426 {
427 return aItem->GetLayerSet();
428 }
429 };
430
431 auto isOverlapping =
432 []( BOARD_ITEM* aSelectedMarkerItem, BOARD_ITEM* aUnSelectedMarkerItem ) -> bool
433 {
434 VECTOR2D selectedItemPos = aSelectedMarkerItem->GetPosition() / PCB_IU_PER_MM;
435 VECTOR2D unSelectedItemPos = aUnSelectedMarkerItem->GetPosition() / PCB_IU_PER_MM;
436
437 double dist = selectedItemPos.Distance( unSelectedItemPos );
438
439 double minimumMarkerSeparationDistance =
441
442 return dist <= minimumMarkerSeparationDistance;
443 };
444
445 if( !node )
446 {
447 // list is being freed; don't do anything with null ptrs
448
449 aEvent.Skip();
450 return;
451 }
452
453 std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
454
455 if( rc_item->GetErrorCode() == DRCE_UNRESOLVED_VARIABLE
456 && rc_item->GetParent()->GetMarkerType() == MARKER_BASE::MARKER_DRAWING_SHEET )
457 {
458 m_frame->FocusOnLocation( node->m_RcItem->GetParent()->GetPos() );
459
460 aEvent.Skip();
461 return;
462 }
463
464 const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() );
465 BOARD_ITEM* item = board->GetItem( itemID );
466
467 if( !item || item == DELETED_BOARD_ITEM::GetInstance() )
468 {
469 // nothing to highlight / focus on
470
471 aEvent.Skip();
472 return;
473 }
474
475 PCB_LAYER_ID principalLayer;
476 LSET violationLayers;
477 BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
478 BOARD_ITEM* b = board->GetItem( rc_item->GetAuxItemID() );
479 BOARD_ITEM* c = board->GetItem( rc_item->GetAuxItem2ID() );
480 BOARD_ITEM* d = board->GetItem( rc_item->GetAuxItem3ID() );
481
482 if( rc_item->GetErrorCode() == DRCE_MALFORMED_COURTYARD )
483 {
484 if( a && ( a->GetFlags() & MALFORMED_B_COURTYARD ) > 0
485 && ( a->GetFlags() & MALFORMED_F_COURTYARD ) == 0 )
486 {
487 principalLayer = B_CrtYd;
488 }
489 else
490 {
491 principalLayer = F_CrtYd;
492 }
493 }
494 else if (rc_item->GetErrorCode() == DRCE_INVALID_OUTLINE )
495 {
496 principalLayer = Edge_Cuts;
497 }
498 else
499 {
500 principalLayer = UNDEFINED_LAYER;
501
502 if( a || b || c || d )
503 violationLayers = LSET::AllLayersMask();
504
505 // Try to initialize principalLayer to a valid layer. Note that some markers have
506 // a layer set to UNDEFINED_LAYER, so we may need to keep looking.
507
508 for( BOARD_ITEM* it: { a, b, c, d } )
509 {
510 if( !it )
511 continue;
512
513 LSET layersList = getActiveLayers( it );
514 violationLayers &= layersList;
515
516 if( principalLayer <= UNDEFINED_LAYER && layersList.count() )
517 principalLayer = layersList.Seq().front();
518 }
519 }
520
521 if( violationLayers.count() )
522 principalLayer = violationLayers.Seq().front();
523 else if( !(principalLayer <= UNDEFINED_LAYER ) )
524 violationLayers.set( principalLayer );
525
526 WINDOW_THAWER thawer( m_frame );
527
528 if( principalLayer > UNDEFINED_LAYER && ( violationLayers & board->GetVisibleLayers() ).none() )
529 m_frame->GetAppearancePanel()->SetLayerVisible( principalLayer, true );
530
531 if( principalLayer > UNDEFINED_LAYER && board->GetVisibleLayers().test( principalLayer ) )
532 m_frame->SetActiveLayer( principalLayer );
533
534 if( rc_item->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
535 {
538
539 if( item->Type() == PCB_ZONE_T )
540 {
541 m_frame->FocusOnItem( item, principalLayer );
542
543 m_frame->GetBoard()->GetConnectivity()->RunOnUnconnectedEdges(
544 [&]( CN_EDGE& edge )
545 {
546 // Connectivity was valid when DRC was run, but this is a modeless dialog
547 // so it might not be now.
548 if( !edge.GetSourceNode() || edge.GetSourceNode()->Dirty() )
549 return true;
550
551 if( !edge.GetTargetNode() || edge.GetTargetNode()->Dirty() )
552 return true;
553
554 if( edge.GetSourceNode()->Parent() == a
555 && edge.GetTargetNode()->Parent() == b )
556 {
557 VECTOR2I focusPos;
558
559 if( item == a && item == b )
560 {
561 focusPos = ( node->m_Type == RC_TREE_NODE::MAIN_ITEM )
562 ? edge.GetSourcePos()
563 : edge.GetTargetPos();
564 }
565 else
566 {
567 focusPos = ( item == edge.GetSourceNode()->Parent() )
568 ? edge.GetSourcePos()
569 : edge.GetTargetPos();
570 }
571
572 m_frame->FocusOnLocation( focusPos );
574
575 return false;
576 }
577
578 return true;
579 } );
580 }
581 else
582 {
583 m_frame->FocusOnItem( item, principalLayer );
584 }
585 }
586 else if( rc_item->GetErrorCode() == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG )
587 {
588 BOARD_CONNECTED_ITEM* track = dynamic_cast<PCB_TRACK*>( item );
589 std::vector<BOARD_ITEM*> items;
590
591 if( track )
592 {
593 int net = track->GetNetCode();
594
595 wxASSERT( net > 0 ); // Without a net how can it be a diff-pair?
596
597 for( const KIID& id : rc_item->GetIDs() )
598 {
599 auto* candidate = dynamic_cast<BOARD_CONNECTED_ITEM*>( board->GetItem( id ) );
600
601 if( candidate && candidate->GetNetCode() == net )
602 items.push_back( candidate );
603 }
604 }
605 else
606 {
607 items.push_back( item );
608 }
609
610 m_frame->FocusOnItems( items, principalLayer );
611 }
612 else
613 {
614 if( item->Type() == PCB_MARKER_T )
615 {
616 std::vector<BOARD_ITEM*> items;
617
618 for( BOARD_ITEM* boardMarkerItem : board->Markers() )
619 {
620 if( item->m_Uuid != boardMarkerItem->m_Uuid && isOverlapping( item, boardMarkerItem ) )
621 {
622 items.push_back( boardMarkerItem );
623 }
624 }
625
626 items.push_back( item );
627 m_frame->FocusOnItems( items, principalLayer );
628 }
629 else
630 {
631 m_frame->FocusOnItem( item, principalLayer );
632 }
633 }
634
635 aEvent.Skip();
636}
637
638
639void DIALOG_DRC::OnDRCItemDClick( wxDataViewEvent& aEvent )
640{
641 if( aEvent.GetItem().IsOk() )
642 {
643 // turn control over to m_frame, hide this DIALOG_DRC window,
644 // no destruction so we can preserve listbox cursor
645 if( !IsModal() )
646 Show( false );
647 }
648
649 // Do not skip aEvent here: this is not useful, and Pcbnew crashes
650 // if skipped (at least on Windows)
651}
652
653
654void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
655{
656 TOOL_MANAGER* toolMgr = m_frame->GetToolManager();
657 BOARD_INSPECTION_TOOL* inspectionTool = toolMgr->GetTool<BOARD_INSPECTION_TOOL>();
658 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
659
660 if( !node )
661 return;
662
663 std::shared_ptr<RC_ITEM> rcItem = node->m_RcItem;
664 DRC_ITEM* drcItem = static_cast<DRC_ITEM*>( rcItem.get() );
665 std::shared_ptr<CONNECTIVITY_DATA> conn = m_currentBoard->GetConnectivity();
666 wxString listName;
667 wxMenu menu;
668
669 switch( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] )
670 {
671 case RPT_SEVERITY_ERROR: listName = _( "errors" ); break;
672 case RPT_SEVERITY_WARNING: listName = _( "warnings" ); break;
673 default: listName = _( "appropriate" ); break;
674 }
675
676 enum MENU_IDS
677 {
678 ID_EDIT_EXCLUSION_COMMENT = 4467,
679 ID_REMOVE_EXCLUSION,
680 ID_REMOVE_EXCLUSION_ALL,
681 ID_ADD_EXCLUSION,
682 ID_ADD_EXCLUSION_WITH_COMMENT,
683 ID_ADD_EXCLUSION_ALL,
684 ID_INSPECT_VIOLATION,
685 ID_SET_SEVERITY_TO_ERROR,
686 ID_SET_SEVERITY_TO_WARNING,
687 ID_SET_SEVERITY_TO_IGNORE,
688 ID_EDIT_SEVERITIES
689 };
690
691 if( rcItem->GetParent()->IsExcluded() )
692 {
693 menu.Append( ID_REMOVE_EXCLUSION,
694 _( "Remove exclusion for this violation" ),
695 wxString::Format( _( "It will be placed back in the %s list" ), listName ) );
696
697 menu.Append( ID_EDIT_EXCLUSION_COMMENT,
698 _( "Edit exclusion comment..." ) );
699
700 if( drcItem->GetViolatingRule() && !drcItem->GetViolatingRule()->m_Implicit )
701 {
702 menu.Append( ID_REMOVE_EXCLUSION_ALL,
703 wxString::Format( _( "Remove all exclusions for violations of rule '%s'" ),
704 drcItem->GetViolatingRule()->m_Name ),
705 wxString::Format( _( "They will be placed back in the %s list" ), listName ) );
706 }
707 }
708 else
709 {
710 menu.Append( ID_ADD_EXCLUSION,
711 _( "Exclude this violation" ),
712 wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
713
714 menu.Append( ID_ADD_EXCLUSION_WITH_COMMENT,
715 _( "Exclude with comment..." ),
716 wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
717
718 if( drcItem->GetViolatingRule() && !drcItem->GetViolatingRule()->m_Implicit )
719 {
720 menu.Append( ID_ADD_EXCLUSION_ALL,
721 wxString::Format( _( "Exclude all violations of rule '%s'..." ),
722 drcItem->GetViolatingRule()->m_Name ),
723 wxString::Format( _( "They will be excluded from the %s list" ), listName ) );
724 }
725 }
726
727 wxString inspectDRCErrorMenuText = inspectionTool->InspectDRCErrorMenuText( rcItem );
728
729 if( !inspectDRCErrorMenuText.IsEmpty() )
730 menu.Append( ID_INSPECT_VIOLATION, inspectDRCErrorMenuText );
731
732 menu.AppendSeparator();
733
734 if( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] == RPT_SEVERITY_WARNING )
735 {
736 menu.Append( ID_SET_SEVERITY_TO_ERROR,
737 wxString::Format( _( "Change severity to Error for all '%s' violations" ),
738 rcItem->GetErrorText() ),
739 _( "Violation severities can also be edited in the Board Setup... dialog" ) );
740 }
741 else
742 {
743 menu.Append( ID_SET_SEVERITY_TO_WARNING,
744 wxString::Format( _( "Change severity to Warning for all '%s' violations" ),
745 rcItem->GetErrorText() ),
746 _( "Violation severities can also be edited in the Board Setup... dialog" ) );
747 }
748
749 menu.Append( ID_SET_SEVERITY_TO_IGNORE,
750 wxString::Format( _( "Ignore all '%s' violations" ), rcItem->GetErrorText() ),
751 _( "Violations will not be checked or reported" ) );
752
753 menu.AppendSeparator();
754
755 menu.Append( ID_EDIT_SEVERITIES,
756 _( "Edit violation severities..." ),
757 _( "Open the Board Setup... dialog" ) );
758
759 bool modified = false;
760 int command = GetPopupMenuSelectionFromUser( menu );
761
762 switch( command )
763 {
764 case ID_EDIT_EXCLUSION_COMMENT:
765 if( PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() ) )
766 {
767 WX_TEXT_ENTRY_DIALOG dlg( this, wxEmptyString, _( "Exclusion Comment" ),
768 marker->GetComment(), true );
769
770 if( dlg.ShowModal() == wxID_CANCEL )
771 break;
772
773 marker->SetExcluded( true, dlg.GetValue() );
774
775 wxString serialized = marker->SerializeToString();
776 bds().m_DrcExclusions.insert( serialized );
777 bds().m_DrcExclusionComments[serialized] = dlg.GetValue();
778
779 // Update view
780 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
781 modified = true;
782 }
783
784 break;
785
786 case ID_REMOVE_EXCLUSION:
787 if( PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( rcItem->GetParent() ) )
788 {
789 marker->SetExcluded( false );
790
791 wxString serialized = marker->SerializeToString();
792 bds().m_DrcExclusions.erase( serialized );
793 bds().m_DrcExclusionComments.erase( serialized );
794
795 if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
796 {
799 }
800 else
801 {
802 m_frame->GetCanvas()->GetView()->Update( marker );
803 }
804
805 // Update view
806 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
807 modified = true;
808 }
809
810 break;
811
812 case ID_ADD_EXCLUSION:
813 case ID_ADD_EXCLUSION_WITH_COMMENT:
814 if( PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( rcItem->GetParent() ) )
815 {
816 wxString comment;
817
818 if( command == ID_ADD_EXCLUSION_WITH_COMMENT )
819 {
820 WX_TEXT_ENTRY_DIALOG dlg( this, wxEmptyString, _( "Exclusion Comment" ),
821 wxEmptyString, true );
822
823 if( dlg.ShowModal() == wxID_CANCEL )
824 break;
825
826 comment = dlg.GetValue();
827 }
828
829 marker->SetExcluded( true, comment );
830
831 wxString serialized = marker->SerializeToString();
832 bds().m_DrcExclusions.insert( serialized );
833 bds().m_DrcExclusionComments[serialized] = comment;
834
835 if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
836 {
839 }
840 else
841 {
842 m_frame->GetCanvas()->GetView()->Update( marker );
843 }
844
845 // Update view
847 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
848 else
849 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false );
850
851 modified = true;
852 }
853
854 break;
855
856 case ID_REMOVE_EXCLUSION_ALL:
857 for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
858 {
859 DRC_ITEM* candidateDrcItem = static_cast<DRC_ITEM*>( marker->GetRCItem().get() );
860
861 if( candidateDrcItem->GetViolatingRule() == drcItem->GetViolatingRule() )
862 {
863 marker->SetExcluded( false );
864
865 wxString serialized = marker->SerializeToString();
866 bds().m_DrcExclusions.erase( serialized );
867 bds().m_DrcExclusionComments.erase( serialized );
868 }
869 }
870
871 // Rebuild model and view
872 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, m_severities );
873 modified = true;
874 break;
875
876 case ID_ADD_EXCLUSION_ALL:
877 for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
878 {
879 DRC_ITEM* candidateDrcItem = static_cast<DRC_ITEM*>( marker->GetRCItem().get() );
880
881 if( candidateDrcItem->GetViolatingRule() == drcItem->GetViolatingRule() )
882 {
883 marker->SetExcluded( true );
884
885 wxString serialized = marker->SerializeToString();
886 bds().m_DrcExclusions.insert( serialized );
887 }
888 }
889
890 // Rebuild model and view
891 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, m_severities );
892 modified = true;
893 break;
894
895 case ID_INSPECT_VIOLATION:
896 inspectionTool->InspectDRCError( node->m_RcItem );
897 break;
898
899 case ID_SET_SEVERITY_TO_ERROR:
900 bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_ERROR;
901
902 for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
903 {
904 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
905 m_frame->GetCanvas()->GetView()->Update( marker );
906 }
907
908 // Rebuild model and view
909 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, m_severities );
910 modified = true;
911 break;
912
913 case ID_SET_SEVERITY_TO_WARNING:
914 bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_WARNING;
915
916 for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
917 {
918 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
919 m_frame->GetCanvas()->GetView()->Update( marker );
920 }
921
922 // Rebuild model and view
923 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, m_severities );
924 modified = true;
925 break;
926
927 case ID_SET_SEVERITY_TO_IGNORE:
928 {
929 bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_IGNORE;
930
931 wxListItem listItem;
932 listItem.SetId( m_ignoredList->GetItemCount() );
933 listItem.SetText( wxT( " • " ) + rcItem->GetErrorText() );
934 listItem.SetData( rcItem->GetErrorCode() );
935
936 m_ignoredList->InsertItem( listItem );
937
938 BOARD* board = m_frame->GetBoard();
939
940 std::vector<BOARD_ITEM*> toRemove;
941
942 for( PCB_MARKER* marker : board->Markers() )
943 {
944 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
945 {
946 m_frame->GetCanvas()->GetView()->Remove( marker );
947 toRemove.emplace_back( marker );
948 }
949 }
950
951 for( BOARD_ITEM* marker : toRemove )
952 board->Remove( marker, REMOVE_MODE::BULK );
953
954 board->FinalizeBulkRemove( toRemove );
955
956 if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
958
959 // Rebuild model and view
960 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, m_severities );
961 modified = true;
962 break;
963 }
964
965 case ID_EDIT_SEVERITIES:
966 m_frame->ShowBoardSetupDialog( _( "Violation Severity" ) );
967 break;
968 }
969
970 if( modified )
971 {
974 m_frame->OnModify();
975 }
976}
977
978
979void DIALOG_DRC::OnIgnoredItemRClick( wxListEvent& event )
980{
981 int errorCode = (int) event.m_item.GetData();
982 wxMenu menu;
983
984 menu.Append( RPT_SEVERITY_ERROR, _( "Error" ), wxEmptyString, wxITEM_CHECK );
985 menu.Append( RPT_SEVERITY_WARNING, _( "Warning" ), wxEmptyString, wxITEM_CHECK );
986 menu.Append( RPT_SEVERITY_IGNORE, _( "Ignore" ), wxEmptyString, wxITEM_CHECK );
987
988 menu.Check( bds().GetSeverity( errorCode ), true );
989
990 int severity = GetPopupMenuSelectionFromUser( menu );
991
992 if( severity > 0 )
993 {
994 if( bds().m_DRCSeverities[ errorCode ] != severity )
995 {
996 bds().m_DRCSeverities[ errorCode ] = (SEVERITY) severity;
997
1000 m_frame->OnModify();
1001 }
1002 }
1003}
1004
1005
1006void DIALOG_DRC::OnEditViolationSeverities( wxHyperlinkEvent& aEvent )
1007{
1008 m_frame->ShowBoardSetupDialog( _( "Violation Severity" ) );
1009}
1010
1011
1012void DIALOG_DRC::OnSeverity( wxCommandEvent& aEvent )
1013{
1014 int flag = 0;
1015
1016 if( aEvent.GetEventObject() == m_showAll )
1018 else if( aEvent.GetEventObject() == m_showErrors )
1020 else if( aEvent.GetEventObject() == m_showWarnings )
1022 else if( aEvent.GetEventObject() == m_showExclusions )
1024
1025 if( aEvent.IsChecked() )
1026 m_severities |= flag;
1027 else if( aEvent.GetEventObject() == m_showAll )
1029 else
1030 m_severities &= ~flag;
1031
1033 UpdateData();
1034}
1035
1036
1037void DIALOG_DRC::OnSaveReport( wxCommandEvent& aEvent )
1038{
1039 wxFileName fn( "DRC." + FILEEXT::ReportFileExtension );
1040
1041 wxFileDialog dlg( this, _( "Save Report File" ), Prj().GetProjectPath(), fn.GetFullName(),
1043 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1044
1045 if( dlg.ShowModal() != wxID_OK )
1046 return;
1047
1048 fn = dlg.GetPath();
1049
1050 if( fn.GetExt().IsEmpty() )
1051 fn.SetExt( FILEEXT::ReportFileExtension );
1052
1053 if( !fn.IsAbsolute() )
1054 {
1055 wxString prj_path = Prj().GetProjectPath();
1056 fn.MakeAbsolute( prj_path );
1057 }
1058
1061
1062 bool success = false;
1063 if( fn.GetExt() == FILEEXT::JsonFileExtension )
1064 success = reportWriter.WriteJsonReport( fn.GetFullPath() );
1065 else
1066 success = reportWriter.WriteTextReport( fn.GetFullPath() );
1067
1068 if( success )
1069 {
1070 m_messages->Report( wxString::Format( _( "Report file '%s' created<br>" ),
1071 fn.GetFullPath() ) );
1072 }
1073 else
1074 {
1075 DisplayError( this, wxString::Format( _( "Failed to create file '%s'." ),
1076 fn.GetFullPath() ) );
1077 }
1078}
1079
1080
1081void DIALOG_DRC::OnClose( wxCloseEvent& aEvent )
1082{
1083 if( m_running )
1084 aEvent.Veto();
1085
1086 wxCommandEvent dummy;
1087
1089}
1090
1091
1092void DIALOG_DRC::OnCancelClick( wxCommandEvent& aEvent )
1093{
1094 if( m_running )
1095 {
1096 m_cancelled = true;
1097 return;
1098 }
1099
1100 m_frame->FocusOnItem( nullptr );
1101
1102 SetReturnCode( wxID_CANCEL );
1103
1104 // The dialog can be modal or not modal.
1105 // Leave the DRC caller destroy (or not) the dialog
1107 drcTool->DestroyDRCDialog();
1108}
1109
1110
1111void DIALOG_DRC::OnChangingNotebookPage( wxNotebookEvent& aEvent )
1112{
1113 m_markerDataView->UnselectAll();
1114 m_unconnectedDataView->UnselectAll();
1115 m_footprintsDataView->UnselectAll();
1116
1117 aEvent.Skip();
1118}
1119
1120
1122{
1123 WINDOW_THAWER thawer( m_frame );
1124
1126}
1127
1128
1130{
1131 if( m_Notebook->IsShown() )
1132 {
1133 switch( m_Notebook->GetSelection() )
1134 {
1135 case 0: m_markersTreeModel->PrevMarker(); break;
1136 case 1: m_unconnectedTreeModel->PrevMarker(); break;
1137 case 2: m_fpWarningsTreeModel->PrevMarker(); break;
1138 case 3: break;
1139 }
1140 }
1141}
1142
1143
1145{
1146 if( m_Notebook->IsShown() )
1147 {
1148 switch( m_Notebook->GetSelection() )
1149 {
1150 case 0: m_markersTreeModel->NextMarker(); break;
1151 case 1: m_unconnectedTreeModel->NextMarker(); break;
1152 case 2: m_fpWarningsTreeModel->NextMarker(); break;
1153 case 3: break;
1154 }
1155 }
1156}
1157
1158
1160{
1161 if( m_Notebook->IsShown() )
1162 {
1163 enum MARKER_BASE::MARKER_T markerType = aMarker->GetMarkerType();
1164
1165 if( markerType == MARKER_BASE::MARKER_DRC )
1166 m_Notebook->SetSelection( 0 );
1167 else if( markerType == MARKER_BASE::MARKER_PARITY )
1168 m_Notebook->SetSelection( 2 );
1169
1170 m_markersTreeModel->SelectMarker( aMarker );
1171
1172 CallAfter(
1173 [this, aMarker]
1174 {
1175 m_markersTreeModel->CenterMarker( aMarker );
1176 } );
1177 }
1178}
1179
1180
1182{
1183 if( !m_Notebook->IsShown() || m_Notebook->GetSelection() != 0 )
1184 return;
1185
1186 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( m_markerDataView->GetCurrentItem() );
1187 PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() );
1188
1189 if( marker && marker->GetSeverity() != RPT_SEVERITY_EXCLUSION )
1190 {
1191 marker->SetExcluded( true );
1192 bds().m_DrcExclusions.insert( marker->SerializeToString() );
1193 m_frame->GetCanvas()->GetView()->Update( marker );
1194
1195 // Update view
1198 else
1200
1202 refreshEditor();
1203 m_frame->OnModify();
1204 }
1205}
1206
1207
1208void DIALOG_DRC::deleteAllMarkers( bool aIncludeExclusions )
1209{
1210 // Clear current selection list to avoid selection of deleted items
1211 Freeze();
1213
1214 m_markersTreeModel->DeleteItems( false, aIncludeExclusions, false );
1215 m_unconnectedTreeModel->DeleteItems( false, aIncludeExclusions, false );
1216 m_fpWarningsTreeModel->DeleteItems( false, aIncludeExclusions, false );
1217
1218 m_frame->GetBoard()->DeleteMARKERs( true, aIncludeExclusions );
1219 Thaw();
1220}
1221
1222
1223void DIALOG_DRC::OnDeleteOneClick( wxCommandEvent& aEvent )
1224{
1225 if( m_Notebook->GetSelection() == 0 )
1226 {
1227 // Clear the selection. It may be the selected DRC marker.
1229
1231
1232 // redraw the pcb
1233 refreshEditor();
1234 }
1235 else if( m_Notebook->GetSelection() == 1 )
1236 {
1238 }
1239 else if( m_Notebook->GetSelection() == 2 )
1240 {
1242 }
1243
1245}
1246
1247
1248void DIALOG_DRC::OnDeleteAllClick( wxCommandEvent& aEvent )
1249{
1250 static bool s_includeExclusions = false;
1251
1252 int numExcluded = 0;
1253
1254 if( m_markersProvider )
1255 numExcluded += m_markersProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1256
1257 if( m_ratsnestProvider )
1258 numExcluded += m_ratsnestProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1259
1261 numExcluded += m_fpWarningsProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1262
1263 if( numExcluded > 0 )
1264 {
1265 wxMessageDialog dlg( this, _( "Delete exclusions too?" ), _( "Delete All Markers" ),
1266 wxYES_NO | wxCANCEL | wxCENTER | wxICON_QUESTION );
1267 dlg.SetYesNoLabels( _( "Errors and Warnings Only" ),
1268 _( "Errors, Warnings and Exclusions" ) );
1269
1270 int ret = dlg.ShowModal();
1271
1272 if( ret == wxID_CANCEL )
1273 return;
1274 else if( ret == wxID_NO )
1275 s_includeExclusions = true;
1276 }
1277
1278 deleteAllMarkers( s_includeExclusions );
1279
1280 refreshEditor();
1282}
1283
1284
1286{
1288 DRC_ENGINE* drcEngine = drcTool->GetDRCEngine().get();
1289
1290 // Collect counts:
1291
1292 int numMarkers = 0;
1293 int numUnconnected = 0;
1294 int numFootprints = 0;
1295
1296 int numErrors = 0;
1297 int numWarnings = 0;
1298 int numExcluded = 0;
1299
1300 if( m_markersProvider )
1301 {
1302 numMarkers += m_markersProvider->GetCount();
1303 numErrors += m_markersProvider->GetCount( RPT_SEVERITY_ERROR );
1304 numWarnings += m_markersProvider->GetCount( RPT_SEVERITY_WARNING );
1305 numExcluded += m_markersProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1306 }
1307
1308 if( m_ratsnestProvider )
1309 {
1310 numUnconnected += m_ratsnestProvider->GetCount();
1311 numErrors += m_ratsnestProvider->GetCount( RPT_SEVERITY_ERROR );
1312 numWarnings += m_ratsnestProvider->GetCount( RPT_SEVERITY_WARNING );
1313 numExcluded += m_ratsnestProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1314 }
1315
1317 {
1318 numFootprints += m_fpWarningsProvider->GetCount();
1319 numErrors += m_fpWarningsProvider->GetCount( RPT_SEVERITY_ERROR );
1320 numWarnings += m_fpWarningsProvider->GetCount( RPT_SEVERITY_WARNING );
1321 numExcluded += m_fpWarningsProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1322 }
1323
1324 bool showErrors = m_showErrors->GetValue();
1325 bool showWarnings = m_showWarnings->GetValue();
1326 bool errorsOverflowed = false;
1327 bool warningsOverflowed = false;
1328 bool markersOverflowed = false;
1329 bool unconnectedOverflowed = false;
1330 bool footprintsOverflowed = false;
1331
1332 for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
1333 {
1334 const SEVERITY severity = bds().GetSeverity( ii );
1335
1336 if( drcEngine->IsErrorLimitExceeded( ii ) )
1337 {
1338 if( severity == RPT_SEVERITY_ERROR )
1339 errorsOverflowed = true;
1340 else if( severity == RPT_SEVERITY_WARNING )
1341 warningsOverflowed = true;
1342
1343 if( ii == DRCE_UNCONNECTED_ITEMS )
1344 {
1345 if( showWarnings && severity == RPT_SEVERITY_WARNING )
1346 unconnectedOverflowed = true;
1347 else if( showErrors && severity == RPT_SEVERITY_ERROR )
1348 unconnectedOverflowed = true;
1349 }
1350 else if( ii == DRCE_MISSING_FOOTPRINT
1352 || ii == DRCE_EXTRA_FOOTPRINT
1353 || ii == DRCE_NET_CONFLICT
1354 || ii == DRCE_SCHEMATIC_PARITY
1355 || ii == DRCE_FOOTPRINT_FILTERS )
1356 {
1357 if( showWarnings && severity == RPT_SEVERITY_WARNING )
1358 footprintsOverflowed = true;
1359 else if( showErrors && severity == RPT_SEVERITY_ERROR )
1360 footprintsOverflowed = true;
1361 }
1362 else
1363 {
1364 if( showWarnings && severity == RPT_SEVERITY_WARNING )
1365 markersOverflowed = true;
1366 else if( showErrors && severity == RPT_SEVERITY_ERROR )
1367 markersOverflowed = true;
1368 }
1369 }
1370 }
1371
1372 wxString msg;
1373 wxString num;
1374
1375 // Update tab headers:
1376
1377 if( m_drcRun )
1378 {
1379 num.Printf( markersOverflowed ? wxT( "%d+" ) : wxT( "%d" ), numMarkers );
1380 msg.Printf( m_markersTitleTemplate, num );
1381 }
1382 else
1383 {
1385 msg.Replace( wxT( "(%s)" ), wxEmptyString );
1386 }
1387
1388 m_Notebook->SetPageText( 0, msg );
1389
1390 if( m_drcRun )
1391 {
1392 num.Printf( unconnectedOverflowed ? wxT( "%d+" ) : wxT( "%d" ), numUnconnected );
1393 msg.sprintf( m_unconnectedTitleTemplate, num );
1394 }
1395 else
1396 {
1398 msg.Replace( wxT( "(%s)" ), wxEmptyString );
1399 }
1400
1401 m_Notebook->SetPageText( 1, msg );
1402
1404 {
1405 num.Printf( footprintsOverflowed ? wxT( "%d+" ) : wxT( "%d" ), numFootprints );
1406 msg.sprintf( m_footprintsTitleTemplate, num );
1407 }
1408 else if( m_drcRun )
1409 {
1411 msg.Replace( wxT( "%s" ), _( "not run" ) );
1412 }
1413 else
1414 {
1416 msg.Replace( wxT( "(%s)" ), wxEmptyString );
1417 }
1418
1419 m_Notebook->SetPageText( 2, msg );
1420
1421 if( m_drcRun )
1422 {
1423 num.Printf( wxT( "%d" ), m_ignoredList->GetItemCount() );
1424 msg.sprintf( m_ignoredTitleTemplate, num );
1425 }
1426 else
1427 {
1429 msg.Replace( wxT( "(%s)" ), wxEmptyString );
1430 }
1431
1432 m_Notebook->SetPageText( 3, msg );
1433
1434 // Update badges:
1435
1436 if( !m_drcRun && numErrors == 0 )
1437 numErrors = -1;
1438
1439 if( !m_drcRun && numWarnings == 0 )
1440 numWarnings = -1;
1441
1442 m_errorsBadge->SetMaximumNumber( numErrors );
1443 m_errorsBadge->UpdateNumber( errorsOverflowed ? numErrors + 1 : numErrors,
1445
1446 m_warningsBadge->SetMaximumNumber( numWarnings );
1447 m_warningsBadge->UpdateNumber( warningsOverflowed ? numWarnings + 1 : numWarnings,
1449
1450 m_exclusionsBadge->SetMaximumNumber( numExcluded );
1452}
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
Definition: base_units.h:70
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetLayerVisible(int aLayer, bool isVisible)
BASE_SET & set(size_t pos)
Definition: base_set.h:116
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
std::map< wxString, wxString > m_DrcExclusionComments
std::map< int, SEVERITY > m_DRCSeverities
std::set< wxString > m_DrcExclusions
SEVERITY GetSeverity(int aDRCErrorCode)
Tool for pcb inspection.
void InspectDRCError(const std::shared_ptr< RC_ITEM > &aDRCItem)
Show the clearance resolution for two selected items.
wxString InspectDRCErrorMenuText(const std::shared_ptr< RC_ITEM > &aDRCItem)
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:295
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:831
BOARD_ITEM * GetItem(const KIID &aID) const
Definition: board.cpp:1451
void RecordDRCExclusions()
Scan existing markers and record data from any that are Excluded.
Definition: board.cpp:327
const MARKERS & Markers() const
Definition: board.h:344
void FinalizeBulkRemove(std::vector< BOARD_ITEM * > &aRemovedItems)
Must be used if Remove() is used using a BULK_x REMOVE_MODE to generate a change event for listeners.
Definition: board.cpp:1170
void UpdateRatsnestExclusions()
Update the visibility flags on the current unconnected ratsnest lines.
Definition: board.cpp:296
void DeleteMARKERs()
Delete all MARKERS from the board.
Definition: board.cpp:1400
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:1176
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:483
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
std::shared_ptr< const CN_ANCHOR > GetSourceNode() const
std::shared_ptr< const CN_ANCHOR > GetTargetNode() const
static DELETED_BOARD_ITEM * GetInstance()
Definition: board_item.h:477
Class DIALOG_DRC_BASE.
wxCheckBox * m_cbRefillZones
wxCheckBox * m_showAll
wxButton * m_DeleteAllMarkersButton
wxCheckBox * m_showExclusions
wxNotebook * m_Notebook
wxCheckBox * m_showErrors
wxDataViewCtrl * m_unconnectedDataView
wxDataViewCtrl * m_footprintsDataView
NUMBER_BADGE * m_warningsBadge
wxCheckBox * m_cbReportAllTrackErrors
NUMBER_BADGE * m_exclusionsBadge
wxSimplebook * m_runningResultsBook
wxButton * m_DeleteCurrentMarkerButton
wxButton * m_sdbSizerCancel
wxButton * m_saveReport
wxCheckBox * m_cbTestFootprints
wxCheckBox * m_showWarnings
wxButton * m_sdbSizerOK
wxListCtrl * m_ignoredList
NUMBER_BADGE * m_errorsBadge
WX_HTML_REPORT_BOX * m_messages
wxDataViewCtrl * m_markerDataView
bool updateUI() override
Definition: dialog_drc.cpp:225
void OnDRCItemSelected(wxDataViewEvent &aEvent) override
Definition: dialog_drc.cpp:404
wxString m_footprintsTitleTemplate
Definition: dialog_drc.h:120
void UpdateData()
Rebuild the contents of the violation tabs based on the current markers and severties.
Definition: dialog_drc.cpp:394
std::shared_ptr< RC_ITEMS_PROVIDER > m_ratsnestProvider
Definition: dialog_drc.h:124
wxString m_markersTitleTemplate
Definition: dialog_drc.h:118
int m_severities
Definition: dialog_drc.h:131
bool m_footprintTestsRun
Definition: dialog_drc.h:116
DIALOG_DRC(PCB_EDIT_FRAME *aEditorFrame, wxWindow *aParent)
Constructors.
Definition: dialog_drc.cpp:72
void OnEditViolationSeverities(wxHyperlinkEvent &aEvent) override
void OnDeleteOneClick(wxCommandEvent &aEvent) override
RC_TREE_MODEL * m_fpWarningsTreeModel
Definition: dialog_drc.h:129
bool m_running
Definition: dialog_drc.h:114
void OnDeleteAllClick(wxCommandEvent &aEvent) override
void OnErrorLinkClicked(wxHtmlLinkEvent &event) override
Definition: dialog_drc.cpp:270
BOARD_DESIGN_SETTINGS & bds()
Definition: dialog_drc.h:110
void SelectMarker(const PCB_MARKER *aMarker)
std::chrono::steady_clock::time_point m_lastUpdateUi
Used to slow down the rate of yields in updateUi()
Definition: dialog_drc.h:134
void OnClose(wxCloseEvent &event) override
void syncCheckboxes()
Definition: dialog_drc.cpp:261
BOARD * m_currentBoard
Definition: dialog_drc.h:112
void OnDRCItemRClick(wxDataViewEvent &aEvent) override
Definition: dialog_drc.cpp:654
void PrevMarker()
void OnRunDRCClick(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:276
wxString m_ignoredTitleTemplate
Definition: dialog_drc.h:121
void OnDRCItemDClick(wxDataViewEvent &aEvent) override
Definition: dialog_drc.cpp:639
void deleteAllMarkers(bool aIncludeExclusions)
void updateDisplayedCounts()
RC_TREE_MODEL * m_unconnectedTreeModel
Definition: dialog_drc.h:128
void refreshEditor()
wxString m_unconnectedTitleTemplate
Definition: dialog_drc.h:119
std::shared_ptr< RC_ITEMS_PROVIDER > m_fpWarningsProvider
Definition: dialog_drc.h:125
std::shared_ptr< RC_ITEMS_PROVIDER > m_markersProvider
Definition: dialog_drc.h:123
void OnSeverity(wxCommandEvent &aEvent) override
PCB_EDIT_FRAME * m_frame
Definition: dialog_drc.h:113
bool m_drcRun
Definition: dialog_drc.h:115
void OnIgnoredItemRClick(wxListEvent &event) override
Definition: dialog_drc.cpp:979
void OnCancelClick(wxCommandEvent &aEvent) override
void NextMarker()
void OnActivateDlg(wxActivateEvent &aEvent) override
Definition: dialog_drc.cpp:208
void OnChangingNotebookPage(wxNotebookEvent &aEvent) override
void OnSaveReport(wxCommandEvent &aEvent) override
void ExcludeMarker()
RC_TREE_MODEL * m_markersTreeModel
Definition: dialog_drc.h:127
bool Show(bool show) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:138
int ShowModal() override
Design Rule Checker object that performs all the DRC tests.
Definition: drc_engine.h:86
DRC_RULE * GetViolatingRule() const
Definition: drc_item.h:164
static std::vector< std::reference_wrapper< RC_ITEM > > GetItemsWithSeverities(bool aIncludeDeprecated=false)
Definition: drc_item.h:133
bool WriteJsonReport(const wxString &aFullFileName)
Definition: drc_report.cpp:114
bool WriteTextReport(const wxString &aFullFileName)
Definition: drc_report.cpp:47
bool m_Implicit
Definition: drc_rule.h:115
wxString m_Name
Definition: drc_rule.h:117
void DestroyDRCDialog()
Close and free the DRC dialog.
Definition: drc_tool.cpp:122
std::shared_ptr< DRC_ENGINE > GetDRCEngine()
Definition: drc_tool.h:78
void RunTests(PROGRESS_REPORTER *aProgressReporter, bool aRefillZones, bool aReportAllTrackErrors, bool aTestFootprints)
Run the DRC tests.
Definition: drc_tool.cpp:132
void RefreshCanvas() override
void FocusOnLocation(const VECTOR2I &aPos)
Useful to focus on a particular location, in find functions.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:244
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:130
bool IsSingle() const
Is this KIFACE running under single_top?
Definition: kiface_base.h:107
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: pcb_view.cpp:91
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition: pcb_view.cpp:74
Definition: kiid.h:49
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static LSET AllLayersMask()
Definition: lset.cpp:587
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:295
@ MARKER_DRAWING_SHEET
Definition: marker_base.h:56
void SetExcluded(bool aExcluded, const wxString &aComment=wxEmptyString)
Definition: marker_base.h:99
enum MARKER_T GetMarkerType() const
Definition: marker_base.h:96
void SetMaximumNumber(int aMax)
Set the maximum number to be shown on the badge.
void UpdateNumber(int aNumber, SEVERITY aSeverity)
Update the number displayed on the badge.
Definition: pad.h:54
DISPLAY_OPTIONS m_Display
DIALOG_DRC m_DrcDialog
static TOOL_ACTION showRatsnest
Definition: pcb_actions.h:335
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
APPEARANCE_CONTROLS * GetAppearancePanel()
PCBNEW_SETTINGS * GetPcbNewSettings() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
void FocusOnItem(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
void RedrawRatsnest()
Return the bounding box of the view that should be used if model is not valid.
The main frame for Pcbnew.
void ShowBoardSetupDialog(const wxString &aInitialPage=wxEmptyString)
void SetActiveLayer(PCB_LAYER_ID aLayer) override
Change the currently active layer to aLayer and also update the APPEARANCE_CONTROLS.
void OnModify() override
Must be called after a board change to set the modified flag.
SEVERITY GetSeverity() const override
Definition: pcb_marker.cpp:281
wxString SerializeToString() const
Definition: pcb_marker.cpp:97
virtual wxApp & App()
Return a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:182
This implements all the tricky bits for thread safety, but the GUI is left to derived classes.
virtual void AdvancePhase() override
Use the next available virtual zone of the dialog progress bar.
virtual void SetCurrentProgress(double aProgress) override
Set the progress value to aProgress (0..1).
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:146
void PrevMarker()
Definition: rc_item.cpp:689
void SelectMarker(const MARKER_BASE *aMarker)
Definition: rc_item.cpp:738
static RC_TREE_NODE * ToNode(wxDataViewItem aItem)
Definition: rc_item.h:238
void ValueChanged(RC_TREE_NODE *aNode)
Definition: rc_item.cpp:517
void Update(std::shared_ptr< RC_ITEMS_PROVIDER > aProvider, int aSeverities)
Definition: rc_item.cpp:364
void DeleteItems(bool aCurrentOnly, bool aIncludeExclusions, bool aDeep)
Delete the current item or all items.
Definition: rc_item.cpp:572
void DeleteCurrentItem(bool aDeep)
Definition: rc_item.cpp:566
void CenterMarker(const MARKER_BASE *aMarker)
Definition: rc_item.cpp:751
static KIID ToUUID(wxDataViewItem aItem)
Definition: rc_item.cpp:220
void NextMarker()
Definition: rc_item.cpp:710
std::shared_ptr< RC_ITEM > m_RcItem
Definition: rc_item.h:223
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
Master controller class:
Definition: tool_manager.h:62
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition: vector2d.h:561
void Clear()
Delete the stored messages.
void SetImmediateMode()
In immediate mode, messages are flushed as they are added.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
void Flush()
Build the HTML messages page.
A KICAD version of wxTextEntryDialog which supports the various improvements/work-arounds from DIALOG...
wxString GetValue() const
Handle actions specific to filling copper zones.
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
This file is part of the common library.
static bool g_lastDRCRun
Definition: dialog_drc.cpp:66
static int RPT_SEVERITY_ALL
Definition: dialog_drc.cpp:258
static int DEFAULT_SINGLE_COL_WIDTH
Definition: dialog_drc.cpp:63
static BOARD * g_lastDRCBoard
Definition: dialog_drc.cpp:65
static bool g_lastFootprintTestsRun
Definition: dialog_drc.cpp:67
static std::vector< std::pair< wxString, int > > g_lastIgnored
Definition: dialog_drc.cpp:69
#define DIALOG_DRC_WINDOW_NAME
Definition: dialog_drc.h:42
@ DRCE_FOOTPRINT_FILTERS
Definition: drc_item.h:79
@ DRCE_UNCONNECTED_ITEMS
Definition: drc_item.h:39
@ DRCE_INVALID_OUTLINE
Definition: drc_item.h:72
@ DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
Definition: drc_item.h:107
@ DRCE_MALFORMED_COURTYARD
Definition: drc_item.h:67
@ DRCE_FIRST
Definition: drc_item.h:38
@ DRCE_UNRESOLVED_VARIABLE
Definition: drc_item.h:87
@ DRCE_DUPLICATE_FOOTPRINT
Definition: drc_item.h:75
@ DRCE_EXTRA_FOOTPRINT
Definition: drc_item.h:76
@ DRCE_LAST
Definition: drc_item.h:112
@ DRCE_NET_CONFLICT
Definition: drc_item.h:77
@ DRCE_MISSING_FOOTPRINT
Definition: drc_item.h:74
@ DRCE_SCHEMATIC_PARITY
Definition: drc_item.h:78
#define _(s)
#define MALFORMED_F_COURTYARD
#define MALFORMED_B_COURTYARD
static int DEFAULT_SINGLE_COL_WIDTH
double m_MinimumMarkerSeparationDistance
When finding overlapped marker a minium distance (in mm) between two DRC markers required to mark it ...
static const std::string ReportFileExtension
static const std::string JsonFileExtension
static wxString JsonFileWildcard()
static wxString ReportFileWildcard()
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:116
@ Edge_Cuts
Definition: layer_ids.h:112
@ B_CrtYd
Definition: layer_ids.h:115
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
This file contains miscellaneous commonly used macros and functions.
void SetFloatLevel(wxWindow *aWindow)
Intended to set the floating window level in macOS on a window.
Definition: wxgtk/ui.cpp:395
void ForceFocus(wxWindow *aWindow)
Pass the current focus to the window.
Definition: wxgtk/ui.cpp:124
STL namespace.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:1073
see class PGM_BASE
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_EXCLUSION
@ RPT_SEVERITY_IGNORE
std::vector< FAB_LAYER_COLOR > dummy
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:120
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:99
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
Functions to provide common constants and other functions to assist in making a consistent UI.
Definition of file extensions used in Kicad.
static int RPT_SEVERITY_ALL