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 <core/throttle.h>
28#include <dialog_drc.h>
30#include <kiface_base.h>
31#include <macros.h>
32#include <pad.h>
33#include <drc/drc_item.h>
34#include <drc/drc_report.h>
38#include <pcb_edit_frame.h>
39#include <tool/tool_manager.h>
40#include <tools/pcb_actions.h>
42#include <pcb_marker.h>
43#include <pcb_track.h>
44#include <pgm_base.h>
45#include <wx/app.h>
46#include <wx/filedlg.h>
47#include <wx/msgdlg.h>
48#include <wx/wupdlock.h>
50#include <widgets/ui_common.h>
54#include <view/view_controls.h>
57#include <tools/drc_tool.h>
60#include <kiplatform/ui.h>
61
62// wxWidgets spends *far* too long calcuating column widths (most of it, believe it or
63// not, in repeatedly creating/destroying a wxDC to do the measurement in).
64// Use default column widths instead.
65static int DEFAULT_SINGLE_COL_WIDTH = 660;
66
67static BOARD* g_lastDRCBoard = nullptr;
68static bool g_lastDRCRun = false;
69static bool g_lastFootprintTestsRun = false;
70
71static std::vector<std::pair<wxString, int>> g_lastIgnored;
72
73
74DIALOG_DRC::DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
75 DIALOG_DRC_BASE( aParent ),
77 m_running( false ),
78 m_drcRun( false ),
79 m_footprintTestsRun( false ),
81 m_crossprobe( true ),
83 m_markersTreeModel( nullptr ),
84 m_unconnectedTreeModel( nullptr ),
85 m_fpWarningsTreeModel( nullptr ),
86 m_updateThrottle( std::chrono::milliseconds( 100 ) ),
87 m_yieldThrottle( std::chrono::milliseconds( 2000 ) )
88{
89 SetName( DIALOG_DRC_WINDOW_NAME ); // Set a window name to be able to find it
91
92 m_frame = aEditorFrame;
93 m_currentBoard = m_frame->GetBoard();
94
95 m_bMenu->SetBitmap( KiBitmapBundle( BITMAPS::config ) );
96
97 if( PCBNEW_SETTINGS* cfg = m_frame->GetPcbNewSettings() )
98 {
99 m_report_all_track_errors = cfg->m_DRCDialog.report_all_track_errors;
100 m_crossprobe = cfg->m_DRCDialog.crossprobe;
101 m_scroll_on_crossprobe = cfg->m_DRCDialog.scroll_on_crossprobe;
102 }
103
104 m_messages->SetImmediateMode();
105
106 m_markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_currentBoard,
109
110 m_ratsnestProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_currentBoard,
112
113 m_fpWarningsProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_currentBoard,
115
117 m_markerDataView->AssociateModel( m_markersTreeModel );
118
121
124
125 // Prevent RTL locales from mirroring the text in the data views
126 m_markerDataView->SetLayoutDirection( wxLayout_LeftToRight );
127 m_unconnectedDataView->SetLayoutDirection( wxLayout_LeftToRight );
128 m_footprintsDataView->SetLayoutDirection( wxLayout_LeftToRight );
129 m_ignoredList->SetLayoutDirection( wxLayout_LeftToRight );
130
131 m_ignoredList->InsertColumn( 0, wxEmptyString, wxLIST_FORMAT_LEFT, DEFAULT_SINGLE_COL_WIDTH );
132
134 {
137
138 for( const auto& [ str, code ] : g_lastIgnored )
139 {
140 wxListItem listItem;
141 listItem.SetId( m_ignoredList->GetItemCount() );
142 listItem.SetText( str );
143 listItem.SetData( code );
144
145 m_ignoredList->InsertItem( listItem );
146 }
147 }
148
149 m_Notebook->SetSelection( 0 );
150
151 if( Kiface().IsSingle() )
152 m_cbTestFootprints->Hide();
153
154 SetupStandardButtons( { { wxID_OK, _( "Run DRC" ) },
155 { wxID_CANCEL, _( "Close" ) } } );
156
157 m_markersTitleTemplate = m_Notebook->GetPageText( 0 );
158 m_unconnectedTitleTemplate = m_Notebook->GetPageText( 1 );
159 m_footprintsTitleTemplate = m_Notebook->GetPageText( 2 );
160 m_ignoredTitleTemplate = m_Notebook->GetPageText( 3 );
161
162 // DPI fix
163 bSizerViolationsBox->SetMinSize( FromDIP( bSizerViolationsBox->GetMinSize() ) );
164
165 Layout(); // adding the units above expanded Clearance text, now resize.
166
167 SetFocus();
168
170}
171
172
174{
175 if( PCBNEW_SETTINGS* cfg = m_frame->GetPcbNewSettings() )
176 {
177 cfg->m_DRCDialog.report_all_track_errors = m_report_all_track_errors;
178 cfg->m_DRCDialog.crossprobe = m_crossprobe;
179 cfg->m_DRCDialog.scroll_on_crossprobe = m_scroll_on_crossprobe;
180 }
181
182 m_frame->ClearFocus();
183
187
188 g_lastIgnored.clear();
189
190 for( int ii = 0; ii < m_ignoredList->GetItemCount(); ++ii )
191 g_lastIgnored.push_back( { m_ignoredList->GetItemText( ii ), m_ignoredList->GetItemData( ii ) } );
192
193 m_markersTreeModel->DecRef();
194 m_unconnectedTreeModel->DecRef();
195 m_fpWarningsTreeModel->DecRef();
196}
197
198
200{
201 UpdateData();
202 return true;
203}
204
205
206void DIALOG_DRC::OnActivateDlg( wxActivateEvent& aEvent )
207{
208 if( m_currentBoard != m_frame->GetBoard() )
209 {
210 // If m_currentBoard is not the current board, (for instance because a new board was loaded),
211 // close the dialog, because many pointers are now invalid in lists
212 SetReturnCode( wxID_CANCEL );
213 Close();
214
215 DRC_TOOL* drcTool = m_frame->GetToolManager()->GetTool<DRC_TOOL>();
216 drcTool->DestroyDRCDialog();
217 }
218}
219
220
221// PROGRESS_REPORTER calls
222
224{
225 if( m_maxProgress != 0 )
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
233 // Repaint the dialog at ~10Hz using Update() which processes only pending expose/
234 // draw events without entering the full platform event loop.
235 if( m_updateThrottle.Ready() )
236 Update();
237
238 // Yield to the event loop infrequently so the cancel button remains functional.
239 // On some Linux systems with glycin-enabled gdk-pixbuf (2.44+), entering the GTK event
240 // loop triggers heavyweight sandbox process spawning that can add hundreds of milliseconds
241 // per call, so we keep this interval long.
242 if( m_yieldThrottle.Ready() )
243 Pgm().App().SafeYieldFor( this, wxEVT_CATEGORY_NATIVE_EVENTS );
244
245 return !m_cancelled;
246}
247
248
249void DIALOG_DRC::AdvancePhase( const wxString& aMessage )
250{
252 SetCurrentProgress( 0.0 );
253
254 m_messages->Report( aMessage );
255}
256
257
259{
260 int severities = 0;
261
262 if( m_showErrors->GetValue() )
263 severities |= RPT_SEVERITY_ERROR;
264
265 if( m_showWarnings->GetValue() )
266 severities |= RPT_SEVERITY_WARNING;
267
268 if( m_showExclusions->GetValue() )
269 severities |= RPT_SEVERITY_EXCLUSION;
270
271 return severities;
272}
273
274
275void DIALOG_DRC::OnMenu( wxCommandEvent& event )
276{
277 // Build a pop menu:
278 wxMenu menu;
279
280 menu.Append( 4205, _( "Report All Errors for Each Track" ),
281 _( "If unchecked, only the first error will be reported for each track" ),
282 wxITEM_CHECK );
283 menu.Check( 4205, m_report_all_track_errors );
284
285 menu.AppendSeparator();
286
287 menu.Append( 4206, _( "Cross-probe Selected Items" ),
288 _( "Highlight corresponding items on canvas when selected in the DRC list" ),
289 wxITEM_CHECK );
290 menu.Check( 4206, m_crossprobe );
291
292 menu.Append( 4207, _( "Center on Cross-probe" ),
293 _( "When cross-probing, scroll the canvas so that the item is visible" ),
294 wxITEM_CHECK );
295 menu.Check( 4207, m_scroll_on_crossprobe );
296
297 // menu_id is the selected submenu id from the popup menu or wxID_NONE
298 int menu_id = m_bMenu->GetPopupMenuSelectionFromUser( menu );
299
300 if( menu_id == 0 || menu_id == 4205 )
301 {
303 }
304 else if( menu_id == 2 || menu_id == 4206 )
305 {
307 }
308 else if( menu_id == 3 || menu_id == 4207 )
309 {
311 }
312}
313
314
315void DIALOG_DRC::OnErrorLinkClicked( wxHtmlLinkEvent& event )
316{
317 m_frame->ShowBoardSetupDialog( _( "Custom Rules" ), this );
318}
319
320
321void DIALOG_DRC::OnCharHook( wxKeyEvent& aEvt )
322{
323 if( int hotkey = aEvt.GetKeyCode() )
324 {
325 if( aEvt.ControlDown() )
326 hotkey |= MD_CTRL;
327 if( aEvt.ShiftDown() )
328 hotkey |= MD_SHIFT;
329 if( aEvt.AltDown() )
330 hotkey |= MD_ALT;
331
332 if( hotkey == ACTIONS::excludeMarker.GetHotKey() )
333 {
335 return;
336 }
337 }
338
340}
341
342
343void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
344{
345 TOOL_MANAGER* toolMgr = m_frame->GetToolManager();
346 DRC_TOOL* drcTool = toolMgr->GetTool<DRC_TOOL>();
347 ZONE_FILLER_TOOL* zoneFillerTool = toolMgr->GetTool<ZONE_FILLER_TOOL>();
348 bool refillZones = m_cbRefillZones->GetValue();
349 bool testFootprints = m_cbTestFootprints->GetValue();
350
351 if( zoneFillerTool->IsBusy() )
352 {
353 wxBell();
354 return;
355 }
356
357 m_footprintTestsRun = false;
358 m_cancelled = false;
359
360 m_frame->GetBoard()->RecordDRCExclusions();
361 deleteAllMarkers( true );
362
363 // This is not the time to have stale or buggy rules. Ensure they're up-to-date
364 // and that they at least parse.
365 try
366 {
367 drcTool->GetDRCEngine()->InitEngine( m_frame->GetDesignRulesPath() );
368 }
369 catch( PARSE_ERROR& )
370 {
371 m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
372 m_DeleteCurrentMarkerButton->Enable( false );
373 m_DeleteAllMarkersButton->Enable( false );
374 m_saveReport->Enable( false );
375
376 m_messages->Clear();
377 m_messages->Report( _( "DRC incomplete: could not compile custom design rules." )
378 + wxS( "&nbsp;&nbsp;" )
379 + wxS( "<a href='$CUSTOM_RULES'>" ) + _( "Show design rules." ) + wxT( "</a>" ) );
380 m_messages->Flush();
381
382 Raise();
383
384 // set float level again, it can be lost due to window events during test run
386 return;
387 }
388
389 std::vector<std::reference_wrapper<RC_ITEM>> violations = DRC_ITEM::GetItemsWithSeverities();
390 m_ignoredList->DeleteAllItems();
391
392 for( std::reference_wrapper<RC_ITEM>& item : violations )
393 {
394 if( bds().GetSeverity( item.get().GetErrorCode() ) == RPT_SEVERITY_IGNORE )
395 {
396 wxListItem listItem;
397 listItem.SetId( m_ignoredList->GetItemCount() );
398 listItem.SetText( wxT( " • " ) + item.get().GetErrorText( true ) );
399 listItem.SetData( item.get().GetErrorCode() );
400
401 m_ignoredList->InsertItem( listItem );
402 }
403 }
404
405 m_ignoredList->SetColumnWidth( 0, m_ignoredList->GetParent()->GetClientSize().x - 20 );
406
407 Raise();
408
409 m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
410 m_messages->Clear();
411 Update(); // Repaint only, don't enter the full event loop
412
413 m_running = true;
414 m_sdbSizerCancel->SetLabel( _( "Cancel" ) );
415 m_sdbSizerOK->Enable( false );
416 m_DeleteCurrentMarkerButton->Enable( false );
417 m_DeleteAllMarkersButton->Enable( false );
418 m_saveReport->Enable( false );
419
420 {
421 wxBusyCursor dummy;
422 drcTool->RunTests( this, refillZones, m_report_all_track_errors, testFootprints );
423 }
424
425 if( m_cancelled )
426 m_messages->Report( _( "-------- DRC canceled by user.<br><br>" ) );
427 else
428 m_messages->Report( _( "Done.<br><br>" ) );
429
430 Raise();
431 Update(); // Repaint only, don't enter the full event loop
432
433 m_running = false;
434 m_sdbSizerCancel->SetLabel( _( "Close" ) );
435 m_sdbSizerOK->Enable( true );
436 m_DeleteCurrentMarkerButton->Enable( true );
437 m_DeleteAllMarkersButton->Enable( true );
438 m_saveReport->Enable( true );
439
440 if( !m_cancelled )
441 {
442 m_sdbSizerCancel->SetDefault();
443 // wxWidgets has a tendency to keep both buttons highlighted without the following:
444 m_sdbSizerOK->Enable( false );
445
446 wxMilliSleep( 500 );
447 m_runningResultsBook->ChangeSelection( 1 );
449
450 // now re-enable m_sdbSizerOK button
451 m_sdbSizerOK->Enable( true );
452 }
453
454 // set float level again, it can be lost due to window events during test run
457}
458
459
461{
462 int severities = getSeverities();
463
464 m_markersTreeModel->Update( m_markersProvider, severities );
465 m_unconnectedTreeModel->Update( m_ratsnestProvider, severities );
466 m_fpWarningsTreeModel->Update( m_fpWarningsProvider, severities );
467
469}
470
471
472void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
473{
474 if( !m_crossprobe )
475 {
476 aEvent.Skip();
477 return;
478 }
479
480 BOARD* board = m_frame->GetBoard();
481 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
482
483 auto getActiveLayers =
484 []( BOARD_ITEM* aItem ) -> LSET
485 {
486 if( aItem->Type() == PCB_PAD_T )
487 {
488 PAD* pad = static_cast<PAD*>( aItem );
489 LSET layers;
490
491 for( int layer : aItem->GetLayerSet() )
492 {
493 if( pad->FlashLayer( layer ) )
494 layers.set( layer );
495 }
496
497 return layers;
498 }
499 else
500 {
501 return aItem->GetLayerSet();
502 }
503 };
504
505 if( !node )
506 {
507 // list is being freed; don't do anything with null ptrs
508
509 aEvent.Skip();
510 return;
511 }
512
513 std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
514
515 if( rc_item->GetErrorCode() == DRCE_UNRESOLVED_VARIABLE
516 && rc_item->GetParent()->GetMarkerType() == MARKER_BASE::MARKER_DRAWING_SHEET )
517 {
518 m_frame->FocusOnLocation( node->m_RcItem->GetParent()->GetPos(), m_scroll_on_crossprobe );
519
520 aEvent.Skip();
521 return;
522 }
523
524 const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() );
525 BOARD_ITEM* item = board->ResolveItem( itemID, true );
526
527 if( !item )
528 {
529 // nothing to highlight / focus on
530 aEvent.Skip();
531 return;
532 }
533
534 PCB_LAYER_ID principalLayer;
535 LSET violationLayers;
536 BOARD_ITEM* a = board->ResolveItem( rc_item->GetMainItemID(), true );
537 BOARD_ITEM* b = board->ResolveItem( rc_item->GetAuxItemID(), true );
538 BOARD_ITEM* c = board->ResolveItem( rc_item->GetAuxItem2ID(), true );
539 BOARD_ITEM* d = board->ResolveItem( rc_item->GetAuxItem3ID(), true );
540
541 if( rc_item->GetErrorCode() == DRCE_MALFORMED_COURTYARD )
542 {
543 if( a && ( a->GetFlags() & MALFORMED_B_COURTYARD ) > 0
544 && ( a->GetFlags() & MALFORMED_F_COURTYARD ) == 0 )
545 {
546 principalLayer = B_CrtYd;
547 }
548 else
549 {
550 principalLayer = F_CrtYd;
551 }
552 }
553 else if( rc_item->GetErrorCode() == DRCE_INVALID_OUTLINE )
554 {
555 principalLayer = Edge_Cuts;
556 }
557 else
558 {
559 principalLayer = UNDEFINED_LAYER;
560
561 // The marker's layer is set by the test provider
562 if( auto* marker = dynamic_cast<PCB_MARKER*>( rc_item->GetParent() ) )
563 {
564 PCB_LAYER_ID markerLayer = marker->GetLayer();
565
566 if( markerLayer > UNDEFINED_LAYER )
567 principalLayer = markerLayer;
568 }
569
570 // Fall back to intersecting the contributing items layer sets.
571 if( principalLayer <= UNDEFINED_LAYER )
572 {
573 if( a || b || c || d )
574 violationLayers = LSET::AllLayersMask();
575
576 for( BOARD_ITEM* it: { a, b, c, d } )
577 {
578 if( !it )
579 continue;
580
581 LSET layersList = getActiveLayers( it );
582 violationLayers &= layersList;
583
584 if( principalLayer <= UNDEFINED_LAYER && layersList.count() )
585 principalLayer = layersList.Seq().front();
586
587 }
588 }
589 }
590
591 if( violationLayers.count() )
592 principalLayer = violationLayers.Seq().front();
593 else if( principalLayer >= 0 )
594 violationLayers.set( principalLayer );
595
596 WINDOW_THAWER thawer( m_frame );
597
598 if( principalLayer > UNDEFINED_LAYER && ( violationLayers & board->GetVisibleLayers() ).none() )
599 m_frame->GetAppearancePanel()->SetLayerVisible( principalLayer, true );
600
601 if( principalLayer > UNDEFINED_LAYER && board->GetVisibleLayers().test( principalLayer ) )
602 m_frame->SetActiveLayer( principalLayer );
603
604 if( rc_item->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
605 {
606 if( !m_frame->GetPcbNewSettings()->m_Display.m_ShowGlobalRatsnest )
607 m_frame->GetToolManager()->RunAction( PCB_ACTIONS::showRatsnest );
608
609 if( item->Type() == PCB_ZONE_T )
610 {
611 m_frame->FocusOnItem( item, principalLayer, m_scroll_on_crossprobe );
612
613 m_frame->GetBoard()->GetConnectivity()->RunOnUnconnectedEdges(
614 [&]( CN_EDGE& edge )
615 {
616 // Connectivity was valid when DRC was run, but this is a modeless dialog
617 // so it might not be now.
618 if( !edge.GetSourceNode() || edge.GetSourceNode()->Dirty() )
619 return true;
620
621 if( !edge.GetTargetNode() || edge.GetTargetNode()->Dirty() )
622 return true;
623
624 if( edge.GetSourceNode()->Parent() == a
625 && edge.GetTargetNode()->Parent() == b )
626 {
627 VECTOR2I focusPos;
628
629 if( item == a && item == b )
630 {
631 focusPos = ( node->m_Type == RC_TREE_NODE::MAIN_ITEM ) ? edge.GetSourcePos()
632 : edge.GetTargetPos();
633 }
634 else
635 {
636 focusPos = ( item == edge.GetSourceNode()->Parent() ) ? edge.GetSourcePos()
637 : edge.GetTargetPos();
638 }
639
640 m_frame->FocusOnLocation( focusPos, m_scroll_on_crossprobe );
641 m_frame->RefreshCanvas();
642
643 return false;
644 }
645
646 return true;
647 } );
648 }
649 else
650 {
651 m_frame->FocusOnItem( item, principalLayer, m_scroll_on_crossprobe );
652 }
653 }
654 else if( rc_item->GetErrorCode() == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG )
655 {
656 BOARD_CONNECTED_ITEM* track = dynamic_cast<PCB_TRACK*>( item );
657 std::vector<BOARD_ITEM*> items;
658
659 if( track )
660 {
661 int net = track->GetNetCode();
662
663 wxASSERT( net > 0 ); // Without a net how can it be a diff-pair?
664
665 for( const KIID& id : rc_item->GetIDs() )
666 {
667 auto* candidate = dynamic_cast<BOARD_CONNECTED_ITEM*>( board->ResolveItem( id, true ) );
668
669 if( candidate && candidate->GetNetCode() == net )
670 items.push_back( candidate );
671 }
672 }
673 else
674 {
675 items.push_back( item );
676 }
677
678 m_frame->FocusOnItems( items, principalLayer, m_scroll_on_crossprobe );
679 }
680 else
681 {
682 m_frame->FocusOnItem( item, principalLayer, m_scroll_on_crossprobe );
683 }
684
685 aEvent.Skip();
686}
687
688
689void DIALOG_DRC::OnDRCItemDClick( wxDataViewEvent& aEvent )
690{
691 if( aEvent.GetItem().IsOk() )
692 {
693 // turn control over to m_frame, hide this DIALOG_DRC window,
694 // no destruction so we can preserve listbox cursor
695 if( !IsModal() )
696 Show( false );
697 }
698
699 // Do not skip aEvent here: this is not useful, and Pcbnew crashes if skipped (at least on MSW)
700}
701
702
703void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
704{
705 TOOL_MANAGER* toolMgr = m_frame->GetToolManager();
706 BOARD_INSPECTION_TOOL* inspectionTool = toolMgr->GetTool<BOARD_INSPECTION_TOOL>();
707 DRC_TOOL* drcTool = toolMgr->GetTool<DRC_TOOL>();
708 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
709
710 if( !node )
711 return;
712
713 std::shared_ptr<RC_ITEM> rcItem = node->m_RcItem;
714 DRC_ITEM* drcItem = static_cast<DRC_ITEM*>( rcItem.get() );
715 std::shared_ptr<CONNECTIVITY_DATA> conn = m_currentBoard->GetConnectivity();
716 wxString listName;
717 wxMenu menu;
718
719 switch( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] )
720 {
721 case RPT_SEVERITY_ERROR: listName = _( "errors" ); break;
722 case RPT_SEVERITY_WARNING: listName = _( "warnings" ); break;
723 default: listName = _( "appropriate" ); break;
724 }
725
726 enum MENU_IDS
727 {
728 ID_EDIT_EXCLUSION_COMMENT = 4467,
729 ID_REMOVE_EXCLUSION,
730 ID_REMOVE_EXCLUSION_ALL,
731 ID_ADD_EXCLUSION,
732 ID_ADD_EXCLUSION_WITH_COMMENT,
733 ID_ADD_EXCLUSION_ALL,
734 ID_INSPECT_VIOLATION,
735 ID_FIX_VIOLATION,
736 ID_SET_SEVERITY_TO_ERROR,
737 ID_SET_SEVERITY_TO_WARNING,
738 ID_SET_SEVERITY_TO_IGNORE,
739 ID_EDIT_SEVERITIES
740 };
741
742 if( rcItem->GetParent()->IsExcluded() )
743 {
744 menu.Append( ID_REMOVE_EXCLUSION,
745 _( "Remove exclusion for this violation" ),
746 wxString::Format( _( "It will be placed back in the %s list" ), listName ) );
747
748 menu.Append( ID_EDIT_EXCLUSION_COMMENT,
749 _( "Edit exclusion comment..." ) );
750
751 if( drcItem->GetViolatingRule() && !drcItem->GetViolatingRule()->IsImplicit() )
752 {
753 menu.Append( ID_REMOVE_EXCLUSION_ALL,
754 wxString::Format( _( "Remove all exclusions for violations of rule '%s'" ),
755 drcItem->GetViolatingRule()->m_Name ),
756 wxString::Format( _( "They will be placed back in the %s list" ), listName ) );
757 }
758 }
759 else
760 {
761 menu.Append( ID_ADD_EXCLUSION,
762 _( "Exclude this violation" ),
763 wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
764
765 menu.Append( ID_ADD_EXCLUSION_WITH_COMMENT,
766 _( "Exclude with comment..." ),
767 wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
768
769 if( drcItem->GetViolatingRule() && !drcItem->GetViolatingRule()->IsImplicit() )
770 {
771 menu.Append( ID_ADD_EXCLUSION_ALL,
772 wxString::Format( _( "Exclude all violations of rule '%s'..." ),
773 drcItem->GetViolatingRule()->m_Name ),
774 wxString::Format( _( "They will be excluded from the %s list" ), listName ) );
775 }
776 }
777
778 menu.AppendSeparator();
779
780 wxString inspectDRCErrorMenuText = inspectionTool->InspectDRCErrorMenuText( rcItem );
781 wxString fixDRCErrorMenuText = drcTool->FixDRCErrorMenuText( rcItem );
782
783 if( !inspectDRCErrorMenuText.IsEmpty() || !fixDRCErrorMenuText.IsEmpty() )
784 {
785 if( !inspectDRCErrorMenuText.IsEmpty() )
786 menu.Append( ID_INSPECT_VIOLATION, inspectDRCErrorMenuText );
787
788 if( !fixDRCErrorMenuText.IsEmpty() )
789 menu.Append( ID_FIX_VIOLATION, fixDRCErrorMenuText );
790
791 menu.AppendSeparator();
792 }
793
794 if( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] == RPT_SEVERITY_WARNING )
795 {
796 menu.Append( ID_SET_SEVERITY_TO_ERROR,
797 wxString::Format( _( "Change severity to Error for all '%s' violations" ),
798 rcItem->GetErrorText( true ) ),
799 _( "Violation severities can also be edited in Board Setup" ) );
800 }
801 else
802 {
803 menu.Append( ID_SET_SEVERITY_TO_WARNING,
804 wxString::Format( _( "Change severity to Warning for all '%s' violations" ),
805 rcItem->GetErrorText( true ) ),
806 _( "Violation severities can also be edited in Board Setup" ) );
807 }
808
809 menu.Append( ID_SET_SEVERITY_TO_IGNORE,
810 wxString::Format( _( "Ignore all '%s' violations" ), rcItem->GetErrorText( true ) ),
811 _( "Violations will not be checked or reported" ) );
812
813 menu.AppendSeparator();
814
815 menu.Append( ID_EDIT_SEVERITIES,
816 _( "Edit violation severities..." ),
817 _( "Open the Board Setup dialog" ) );
818
819 bool modified = false;
820 int command = GetPopupMenuSelectionFromUser( menu );
821
822 switch( command )
823 {
824 case ID_EDIT_EXCLUSION_COMMENT:
825 if( PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() ) )
826 {
827 WX_TEXT_ENTRY_DIALOG dlg( this, wxEmptyString, _( "Exclusion Comment" ), marker->GetComment(), true );
828
829 if( dlg.ShowModal() == wxID_CANCEL )
830 break;
831
832 marker->SetExcluded( true, dlg.GetValue() );
833
834 wxString serialized = marker->SerializeToString();
835 bds().m_DrcExclusions.insert( serialized );
836 bds().m_DrcExclusionComments[serialized] = dlg.GetValue();
837
838 // Update view
839 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
840 modified = true;
841 }
842
843 break;
844
845 case ID_REMOVE_EXCLUSION:
846 if( PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( rcItem->GetParent() ) )
847 {
848 marker->SetExcluded( false );
849
850 wxString serialized = marker->SerializeToString();
851 bds().m_DrcExclusions.erase( serialized );
852 bds().m_DrcExclusionComments.erase( serialized );
853
854 if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
855 {
856 m_frame->GetBoard()->UpdateRatsnestExclusions();
857 m_frame->GetCanvas()->RedrawRatsnest();
858 }
859 else
860 {
861 m_frame->GetCanvas()->GetView()->Update( marker );
862 }
863
864 // Update view
865 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
866 modified = true;
867 }
868
869 break;
870
871 case ID_ADD_EXCLUSION:
872 case ID_ADD_EXCLUSION_WITH_COMMENT:
873 if( PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( rcItem->GetParent() ) )
874 {
875 wxString comment;
876
877 if( command == ID_ADD_EXCLUSION_WITH_COMMENT )
878 {
879 WX_TEXT_ENTRY_DIALOG dlg( this, wxEmptyString, _( "Exclusion Comment" ), wxEmptyString, true );
880
881 if( dlg.ShowModal() == wxID_CANCEL )
882 break;
883
884 comment = dlg.GetValue();
885 }
886
887 marker->SetExcluded( true, comment );
888
889 wxString serialized = marker->SerializeToString();
890 bds().m_DrcExclusions.insert( serialized );
891 bds().m_DrcExclusionComments[serialized] = comment;
892
893 if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
894 {
895 m_frame->GetBoard()->UpdateRatsnestExclusions();
896 m_frame->GetCanvas()->RedrawRatsnest();
897 }
898 else
899 {
900 m_frame->GetCanvas()->GetView()->Update( marker );
901 }
902
903 // Update view
904 if( m_showExclusions->GetValue() )
905 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
906 else
907 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false );
908
909 modified = true;
910 }
911
912 break;
913
914 case ID_REMOVE_EXCLUSION_ALL:
915 for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
916 {
917 DRC_ITEM* candidateDrcItem = static_cast<DRC_ITEM*>( marker->GetRCItem().get() );
918
919 if( candidateDrcItem->GetViolatingRule() == drcItem->GetViolatingRule() )
920 {
921 marker->SetExcluded( false );
922
923 wxString serialized = marker->SerializeToString();
924 bds().m_DrcExclusions.erase( serialized );
925 bds().m_DrcExclusionComments.erase( serialized );
926 }
927 }
928
929 // Rebuild model and view
930 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, getSeverities() );
931 modified = true;
932 break;
933
934 case ID_ADD_EXCLUSION_ALL:
935 for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
936 {
937 DRC_ITEM* candidateDrcItem = static_cast<DRC_ITEM*>( marker->GetRCItem().get() );
938
939 if( candidateDrcItem->GetViolatingRule() == drcItem->GetViolatingRule() )
940 {
941 marker->SetExcluded( true );
942
943 wxString serialized = marker->SerializeToString();
944 bds().m_DrcExclusions.insert( serialized );
945 }
946 }
947
948 // Rebuild model and view
949 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, getSeverities() );
950 modified = true;
951 break;
952
953 case ID_INSPECT_VIOLATION:
954 inspectionTool->InspectDRCError( node->m_RcItem );
955 break;
956
957 case ID_FIX_VIOLATION:
958 drcTool->FixDRCError( node->m_RcItem );
959 break;
960
961 case ID_SET_SEVERITY_TO_ERROR:
962 bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_ERROR;
963
964 for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
965 {
966 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
967 m_frame->GetCanvas()->GetView()->Update( marker );
968 }
969
970 // Rebuild model and view
971 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, getSeverities() );
972 modified = true;
973 break;
974
975 case ID_SET_SEVERITY_TO_WARNING:
976 bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_WARNING;
977
978 for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
979 {
980 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
981 m_frame->GetCanvas()->GetView()->Update( marker );
982 }
983
984 // Rebuild model and view
985 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, getSeverities() );
986 modified = true;
987 break;
988
989 case ID_SET_SEVERITY_TO_IGNORE:
990 {
991 bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_IGNORE;
992
993 wxListItem listItem;
994 listItem.SetId( m_ignoredList->GetItemCount() );
995 listItem.SetText( wxT( " • " ) + rcItem->GetErrorText( true ) );
996 listItem.SetData( rcItem->GetErrorCode() );
997
998 m_ignoredList->InsertItem( listItem );
999
1000 BOARD* board = m_frame->GetBoard();
1001
1002 std::vector<BOARD_ITEM*> toRemove;
1003
1004 for( PCB_MARKER* marker : board->Markers() )
1005 {
1006 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
1007 {
1008 m_frame->GetCanvas()->GetView()->Remove( marker );
1009 toRemove.emplace_back( marker );
1010 }
1011 }
1012
1013 for( BOARD_ITEM* marker : toRemove )
1014 board->Remove( marker, REMOVE_MODE::BULK );
1015
1016 board->FinalizeBulkRemove( toRemove );
1017
1018 if( rcItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
1019 m_frame->GetCanvas()->RedrawRatsnest();
1020
1021 // Rebuild model and view
1022 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markersProvider, getSeverities() );
1023 modified = true;
1024 break;
1025 }
1026
1027 case ID_EDIT_SEVERITIES:
1028 m_frame->ShowBoardSetupDialog( _( "Violation Severity" ), this );
1029 break;
1030 }
1031
1032 if( modified )
1033 {
1035 refreshEditor();
1036 m_frame->OnModify();
1037 }
1038}
1039
1040
1041void DIALOG_DRC::OnIgnoredItemRClick( wxListEvent& event )
1042{
1043 int errorCode = (int) event.m_item.GetData();
1044 wxMenu menu;
1045
1046 menu.Append( RPT_SEVERITY_ERROR, _( "Error" ), wxEmptyString, wxITEM_RADIO );
1047 menu.Append( RPT_SEVERITY_WARNING, _( "Warning" ), wxEmptyString, wxITEM_RADIO );
1048 menu.Append( RPT_SEVERITY_IGNORE, _( "Ignore" ), wxEmptyString, wxITEM_RADIO );
1049
1050 menu.Check( bds().GetSeverity( errorCode ), true );
1051
1052 int severity = GetPopupMenuSelectionFromUser( menu );
1053
1054 if( severity > 0 )
1055 {
1056 if( bds().m_DRCSeverities[ errorCode ] != severity )
1057 {
1058 bds().m_DRCSeverities[ errorCode ] = (SEVERITY) severity;
1059
1061 refreshEditor();
1062 m_frame->OnModify();
1063 }
1064 }
1065}
1066
1067
1068void DIALOG_DRC::OnEditViolationSeverities( wxHyperlinkEvent& aEvent )
1069{
1070 m_frame->ShowBoardSetupDialog( _( "Violation Severity" ), this );
1071}
1072
1073
1074void DIALOG_DRC::OnSeverity( wxCommandEvent& aEvent )
1075{
1076 if( aEvent.GetEventObject() == m_showAll )
1077 {
1078 m_showErrors->SetValue( true );
1079 m_showWarnings->SetValue( aEvent.IsChecked() );
1080 m_showExclusions->SetValue( aEvent.IsChecked() );
1081 }
1082
1083 UpdateData();
1084}
1085
1086
1087void DIALOG_DRC::OnSaveReport( wxCommandEvent& aEvent )
1088{
1089 wxFileName fn( "DRC." + FILEEXT::ReportFileExtension );
1090
1091 wxFileDialog dlg( this, _( "Save Report File" ), Prj().GetProjectPath(), fn.GetFullName(),
1093 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1094
1096
1097 if( dlg.ShowModal() != wxID_OK )
1098 return;
1099
1100 fn = dlg.GetPath();
1101
1102 if( fn.GetExt().IsEmpty() )
1103 fn.SetExt( FILEEXT::ReportFileExtension );
1104
1105 if( !fn.IsAbsolute() )
1106 {
1107 wxString prj_path = Prj().GetProjectPath();
1108 fn.MakeAbsolute( prj_path );
1109 }
1110
1111 DRC_REPORT reportWriter( m_frame->GetBoard(), GetUserUnits(), m_markersProvider,
1113
1114 bool success = false;
1115 if( fn.GetExt() == FILEEXT::JsonFileExtension )
1116 success = reportWriter.WriteJsonReport( fn.GetFullPath() );
1117 else
1118 success = reportWriter.WriteTextReport( fn.GetFullPath() );
1119
1120 if( success )
1121 m_messages->Report( wxString::Format( _( "Report file '%s' created<br>" ), fn.GetFullPath() ) );
1122 else
1123 DisplayError( this, wxString::Format( _( "Failed to create file '%s'." ), fn.GetFullPath() ) );
1124}
1125
1126
1127void DIALOG_DRC::OnClose( wxCloseEvent& aEvent )
1128{
1129 wxCommandEvent dummy;
1131}
1132
1133
1134void DIALOG_DRC::OnCancelClick( wxCommandEvent& aEvent )
1135{
1136 if( m_running )
1137 {
1138 m_cancelled = true;
1139 return;
1140 }
1141
1142 m_frame->ClearFocus();
1143
1144 SetReturnCode( wxID_CANCEL );
1145
1146 // The dialog can be modal or not modal.
1147 // Leave the DRC caller destroy (or not) the dialog
1148 DRC_TOOL* drcTool = m_frame->GetToolManager()->GetTool<DRC_TOOL>();
1149 drcTool->DestroyDRCDialog();
1150}
1151
1152
1153void DIALOG_DRC::OnChangingNotebookPage( wxNotebookEvent& aEvent )
1154{
1155 m_markerDataView->UnselectAll();
1156 m_unconnectedDataView->UnselectAll();
1157 m_footprintsDataView->UnselectAll();
1158
1159 aEvent.Skip();
1160}
1161
1162
1164{
1165 WINDOW_THAWER thawer( m_frame );
1166
1167 m_frame->GetCanvas()->Refresh();
1168}
1169
1170
1172{
1173 if( m_Notebook->IsShown() )
1174 {
1175 switch( m_Notebook->GetSelection() )
1176 {
1177 case 0: m_markersTreeModel->PrevMarker(); break;
1178 case 1: m_unconnectedTreeModel->PrevMarker(); break;
1179 case 2: m_fpWarningsTreeModel->PrevMarker(); break;
1180 case 3: break;
1181 }
1182 }
1183}
1184
1185
1187{
1188 if( m_Notebook->IsShown() )
1189 {
1190 switch( m_Notebook->GetSelection() )
1191 {
1192 case 0: m_markersTreeModel->NextMarker(); break;
1193 case 1: m_unconnectedTreeModel->NextMarker(); break;
1194 case 2: m_fpWarningsTreeModel->NextMarker(); break;
1195 case 3: break;
1196 }
1197 }
1198}
1199
1200
1202{
1203 if( m_Notebook->IsShown() )
1204 {
1205 enum MARKER_BASE::MARKER_T markerType = aMarker->GetMarkerType();
1206
1207 if( markerType == MARKER_BASE::MARKER_DRC )
1208 m_Notebook->SetSelection( 0 );
1209 else if( markerType == MARKER_BASE::MARKER_PARITY )
1210 m_Notebook->SetSelection( 2 );
1211
1212 m_markersTreeModel->SelectMarker( aMarker );
1213
1214 CallAfter(
1215 [this, aMarker]
1216 {
1217 m_markersTreeModel->CenterMarker( aMarker );
1218 } );
1219 }
1220}
1221
1222
1224{
1225 if( !m_Notebook->IsShown() || m_Notebook->GetSelection() != 0 )
1226 return;
1227
1228 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( m_markerDataView->GetCurrentItem() );
1229
1230 if( node && node->m_RcItem )
1231 {
1232 PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() );
1233
1234 if( marker && marker->GetSeverity() != RPT_SEVERITY_EXCLUSION )
1235 {
1236 marker->SetExcluded( true );
1237 bds().m_DrcExclusions.insert( marker->SerializeToString() );
1238 m_frame->GetCanvas()->GetView()->Update( marker );
1239
1240 // Update view
1241 if( m_showExclusions->GetValue() )
1242 m_markersTreeModel->ValueChanged( node );
1243 else
1244 m_markersTreeModel->DeleteCurrentItem( false );
1245
1247 refreshEditor();
1248 m_frame->OnModify();
1249 }
1250 }
1251}
1252
1253
1254void DIALOG_DRC::deleteAllMarkers( bool aIncludeExclusions )
1255{
1256 // Clear current selection list to avoid selection of deleted items
1257 Freeze();
1258 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
1259
1260 m_markersTreeModel->DeleteItems( false, aIncludeExclusions, false );
1261 m_unconnectedTreeModel->DeleteItems( false, aIncludeExclusions, false );
1262 m_fpWarningsTreeModel->DeleteItems( false, aIncludeExclusions, false );
1263
1264 m_frame->GetBoard()->DeleteMARKERs( true, aIncludeExclusions );
1265 Thaw();
1266}
1267
1268
1269void DIALOG_DRC::OnDeleteOneClick( wxCommandEvent& aEvent )
1270{
1271 if( m_Notebook->GetSelection() == 0 )
1272 {
1273 // Clear the selection. It may be the selected DRC marker.
1274 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
1275
1276 m_markersTreeModel->DeleteCurrentItem( true );
1277
1278 // redraw the pcb
1279 refreshEditor();
1280 }
1281 else if( m_Notebook->GetSelection() == 1 )
1282 {
1283 m_unconnectedTreeModel->DeleteCurrentItem( true );
1284 }
1285 else if( m_Notebook->GetSelection() == 2 )
1286 {
1287 m_fpWarningsTreeModel->DeleteCurrentItem( true );
1288 }
1289
1291}
1292
1293
1294void DIALOG_DRC::OnDeleteAllClick( wxCommandEvent& aEvent )
1295{
1296 static bool s_includeExclusions = false;
1297
1298 int numExcluded = 0;
1299
1300 if( m_markersProvider )
1301 numExcluded += m_markersProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1302
1303 if( m_ratsnestProvider )
1304 numExcluded += m_ratsnestProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1305
1307 numExcluded += m_fpWarningsProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1308
1309 if( numExcluded > 0 )
1310 {
1311 wxMessageDialog dlg( this, _( "Delete exclusions too?" ), _( "Delete All Markers" ),
1312 wxYES_NO | wxCANCEL | wxCENTER | wxICON_QUESTION );
1313 dlg.SetYesNoLabels( _( "Errors and Warnings Only" ),
1314 _( "Errors, Warnings and Exclusions" ) );
1315
1316 int ret = dlg.ShowModal();
1317
1318 if( ret == wxID_CANCEL )
1319 return;
1320 else if( ret == wxID_NO )
1321 s_includeExclusions = true;
1322 }
1323
1324 deleteAllMarkers( s_includeExclusions );
1325 m_drcRun = false;
1326
1327 refreshEditor();
1329}
1330
1331
1333{
1334 DRC_TOOL* drcTool = m_frame->GetToolManager()->GetTool<DRC_TOOL>();
1335 DRC_ENGINE* drcEngine = drcTool->GetDRCEngine().get();
1336
1337 // Collect counts:
1338
1339 int numMarkers = 0;
1340 int numUnconnected = 0;
1341 int numFootprints = 0;
1342
1343 int numErrors = 0;
1344 int numWarnings = 0;
1345 int numExcluded = 0;
1346
1347 if( m_markersProvider )
1348 {
1349 numMarkers += m_markersProvider->GetCount();
1350 numErrors += m_markersProvider->GetCount( RPT_SEVERITY_ERROR );
1351 numWarnings += m_markersProvider->GetCount( RPT_SEVERITY_WARNING );
1352 numExcluded += m_markersProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1353 }
1354
1355 if( m_ratsnestProvider )
1356 {
1357 numUnconnected += m_ratsnestProvider->GetCount();
1358 numErrors += m_ratsnestProvider->GetCount( RPT_SEVERITY_ERROR );
1359 numWarnings += m_ratsnestProvider->GetCount( RPT_SEVERITY_WARNING );
1360 numExcluded += m_ratsnestProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1361 }
1362
1364 {
1365 numFootprints += m_fpWarningsProvider->GetCount();
1366 numErrors += m_fpWarningsProvider->GetCount( RPT_SEVERITY_ERROR );
1367 numWarnings += m_fpWarningsProvider->GetCount( RPT_SEVERITY_WARNING );
1368 numExcluded += m_fpWarningsProvider->GetCount( RPT_SEVERITY_EXCLUSION );
1369 }
1370
1371 bool errorsOverflowed = false;
1372 bool warningsOverflowed = false;
1373 bool markersOverflowed = false;
1374 bool unconnectedOverflowed = false;
1375 bool footprintsOverflowed = false;
1376
1377 for( int ii = DRCE_FIRST; ii <= DRCE_LAST; ++ii )
1378 {
1379 const SEVERITY severity = bds().GetSeverity( ii );
1380
1381 if( drcEngine->IsErrorLimitExceeded( ii ) )
1382 {
1383 if( severity == RPT_SEVERITY_ERROR )
1384 errorsOverflowed = true;
1385 else if( severity == RPT_SEVERITY_WARNING )
1386 warningsOverflowed = true;
1387
1388 if( ii == DRCE_UNCONNECTED_ITEMS )
1389 {
1390 if( m_showWarnings->GetValue() && severity == RPT_SEVERITY_WARNING )
1391 unconnectedOverflowed = true;
1392 else if( m_showErrors->GetValue() && severity == RPT_SEVERITY_ERROR )
1393 unconnectedOverflowed = true;
1394 }
1395 else if( ii == DRCE_MISSING_FOOTPRINT
1397 || ii == DRCE_EXTRA_FOOTPRINT
1398 || ii == DRCE_NET_CONFLICT
1399 || ii == DRCE_SCHEMATIC_PARITY
1400 || ii == DRCE_FOOTPRINT_FILTERS
1402 {
1403 if( m_showWarnings->GetValue() && severity == RPT_SEVERITY_WARNING )
1404 footprintsOverflowed = true;
1405 else if( m_showErrors->GetValue() && severity == RPT_SEVERITY_ERROR )
1406 footprintsOverflowed = true;
1407 }
1408 else
1409 {
1410 if( m_showWarnings->GetValue() && severity == RPT_SEVERITY_WARNING )
1411 markersOverflowed = true;
1412 else if( m_showErrors->GetValue() && severity == RPT_SEVERITY_ERROR )
1413 markersOverflowed = true;
1414 }
1415 }
1416 }
1417
1418 wxString msg;
1419 wxString num;
1420
1421 // Update tab headers:
1422
1423 if( m_drcRun )
1424 {
1425 num.Printf( markersOverflowed ? wxT( "%d+" ) : wxT( "%d" ), numMarkers );
1426 msg.Printf( m_markersTitleTemplate, num );
1427 }
1428 else
1429 {
1431 msg.Replace( wxT( "(%s)" ), wxEmptyString );
1432 }
1433
1434 m_Notebook->SetPageText( 0, msg );
1435
1436 if( m_drcRun )
1437 {
1438 num.Printf( unconnectedOverflowed ? wxT( "%d+" ) : wxT( "%d" ), numUnconnected );
1439 msg.sprintf( m_unconnectedTitleTemplate, num );
1440 }
1441 else
1442 {
1444 msg.Replace( wxT( "(%s)" ), wxEmptyString );
1445 }
1446
1447 m_Notebook->SetPageText( 1, msg );
1448
1450 {
1451 num.Printf( footprintsOverflowed ? wxT( "%d+" ) : wxT( "%d" ), numFootprints );
1452 msg.sprintf( m_footprintsTitleTemplate, num );
1453 }
1454 else if( m_drcRun )
1455 {
1457 msg.Replace( wxT( "%s" ), _( "not run" ) );
1458 }
1459 else
1460 {
1462 msg.Replace( wxT( "(%s)" ), wxEmptyString );
1463 }
1464
1465 m_Notebook->SetPageText( 2, msg );
1466
1467 if( m_drcRun )
1468 {
1469 num.Printf( wxT( "%d" ), m_ignoredList->GetItemCount() );
1470 msg.sprintf( m_ignoredTitleTemplate, num );
1471 }
1472 else
1473 {
1475 msg.Replace( wxT( "(%s)" ), wxEmptyString );
1476 }
1477
1478 m_Notebook->SetPageText( 3, msg );
1479
1480 // Update badges:
1481
1482 if( !m_drcRun && numErrors == 0 )
1483 numErrors = -1;
1484
1485 if( !m_drcRun && numWarnings == 0 )
1486 numWarnings = -1;
1487
1488 m_errorsBadge->SetMaximumNumber( numErrors );
1489 m_errorsBadge->UpdateNumber( errorsOverflowed ? numErrors + 1 : numErrors, RPT_SEVERITY_ERROR );
1490
1491 m_warningsBadge->SetMaximumNumber( numWarnings );
1492 m_warningsBadge->UpdateNumber( warningsOverflowed ? numWarnings + 1 : numWarnings, RPT_SEVERITY_WARNING );
1493
1494 m_exclusionsBadge->SetMaximumNumber( numExcluded );
1495 m_exclusionsBadge->UpdateNumber( numExcluded, RPT_SEVERITY_EXCLUSION );
1496}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
static TOOL_ACTION excludeMarker
Definition actions.h:129
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
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:84
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
const LSET & GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition board.cpp:1000
const MARKERS & Markers() const
Definition board.h:376
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:1371
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition board.cpp:1394
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition board.cpp:1789
bool Dirty() const
BOARD_CONNECTED_ITEM * Parent() const
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
const VECTOR2I GetTargetPos() const
const VECTOR2I GetSourcePos() const
wxCheckBox * m_cbRefillZones
wxBoxSizer * bSizerViolationsBox
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
NUMBER_BADGE * m_exclusionsBadge
wxSimplebook * m_runningResultsBook
wxButton * m_DeleteCurrentMarkerButton
STD_BITMAP_BUTTON * m_bMenu
wxButton * m_sdbSizerCancel
wxButton * m_saveReport
wxCheckBox * m_cbTestFootprints
DIALOG_DRC_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Design Rules Checker"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
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
void OnDRCItemSelected(wxDataViewEvent &aEvent) override
wxString m_footprintsTitleTemplate
Definition dialog_drc.h:128
void UpdateData()
Rebuild the contents of the violation tabs based on the current markers and severties.
std::shared_ptr< RC_ITEMS_PROVIDER > m_ratsnestProvider
Definition dialog_drc.h:132
wxString m_markersTitleTemplate
Definition dialog_drc.h:126
bool m_footprintTestsRun
Definition dialog_drc.h:120
DIALOG_DRC(PCB_EDIT_FRAME *aEditorFrame, wxWindow *aParent)
Constructors.
void OnEditViolationSeverities(wxHyperlinkEvent &aEvent) override
void OnDeleteOneClick(wxCommandEvent &aEvent) override
RC_TREE_MODEL * m_fpWarningsTreeModel
Definition dialog_drc.h:137
bool m_running
Definition dialog_drc.h:118
void OnDeleteAllClick(wxCommandEvent &aEvent) override
bool m_crossprobe
Definition dialog_drc.h:123
void OnMenu(wxCommandEvent &aEvent) override
bool TransferDataToWindow() override
void OnErrorLinkClicked(wxHtmlLinkEvent &event) override
BOARD_DESIGN_SETTINGS & bds()
Definition dialog_drc.h:113
bool m_report_all_track_errors
Definition dialog_drc.h:122
void SelectMarker(const PCB_MARKER *aMarker)
void OnClose(wxCloseEvent &event) override
void OnCharHook(wxKeyEvent &aEvt) override
int getSeverities()
BOARD * m_currentBoard
Definition dialog_drc.h:116
void OnDRCItemRClick(wxDataViewEvent &aEvent) override
void PrevMarker()
void OnRunDRCClick(wxCommandEvent &aEvent) override
wxString m_ignoredTitleTemplate
Definition dialog_drc.h:129
THROTTLE m_yieldThrottle
Definition dialog_drc.h:140
void OnDRCItemDClick(wxDataViewEvent &aEvent) override
THROTTLE m_updateThrottle
Definition dialog_drc.h:139
void deleteAllMarkers(bool aIncludeExclusions)
void updateDisplayedCounts()
RC_TREE_MODEL * m_unconnectedTreeModel
Definition dialog_drc.h:136
bool m_scroll_on_crossprobe
Definition dialog_drc.h:124
void refreshEditor()
wxString m_unconnectedTitleTemplate
Definition dialog_drc.h:127
std::shared_ptr< RC_ITEMS_PROVIDER > m_fpWarningsProvider
Definition dialog_drc.h:133
std::shared_ptr< RC_ITEMS_PROVIDER > m_markersProvider
Definition dialog_drc.h:131
void OnSeverity(wxCommandEvent &aEvent) override
PCB_EDIT_FRAME * m_frame
Definition dialog_drc.h:117
bool m_drcRun
Definition dialog_drc.h:119
void OnIgnoredItemRClick(wxListEvent &event) override
void OnCancelClick(wxCommandEvent &aEvent) override
void NextMarker()
void OnActivateDlg(wxActivateEvent &aEvent) override
void OnChangingNotebookPage(wxNotebookEvent &aEvent) override
void OnSaveReport(wxCommandEvent &aEvent) override
void ExcludeMarker()
RC_TREE_MODEL * m_markersTreeModel
Definition dialog_drc.h:135
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...
virtual void OnCharHook(wxKeyEvent &aEvt)
EDA_UNITS GetUserUnits() const
int ShowModal() override
Design Rule Checker object that performs all the DRC tests.
Definition drc_engine.h:133
void InitEngine(const wxFileName &aRulePath)
Initialize the DRC engine.
static std::vector< std::reference_wrapper< RC_ITEM > > GetItemsWithSeverities()
Definition drc_item.h:143
DRC_RULE * GetViolatingRule() const
Definition drc_item.h:162
bool WriteJsonReport(const wxString &aFullFileName)
bool WriteTextReport(const wxString &aFullFileName)
bool IsImplicit() const
Definition drc_rule.h:144
wxString m_Name
Definition drc_rule.h:154
void DestroyDRCDialog()
Close and free the DRC dialog.
Definition drc_tool.cpp:127
std::shared_ptr< DRC_ENGINE > GetDRCEngine()
Definition drc_tool.h:87
void RunTests(PROGRESS_REPORTER *aProgressReporter, bool aRefillZones, bool aReportAllTrackErrors, bool aTestFootprints)
Run the DRC tests.
Definition drc_tool.cpp:137
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:152
Definition kiid.h:48
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
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:313
static const LSET & AllLayersMask()
Definition lset.cpp:641
const VECTOR2I & GetPos() const
Definition marker_base.h:83
@ MARKER_DRAWING_SHEET
Definition marker_base.h:56
void SetExcluded(bool aExcluded, const wxString &aComment=wxEmptyString)
Definition marker_base.h:94
enum MARKER_T GetMarkerType() const
Definition marker_base.h:91
Definition pad.h:55
static TOOL_ACTION showRatsnest
The main frame for Pcbnew.
SEVERITY GetSeverity() const override
wxString SerializeToString() const
virtual wxApp & App()
Return a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition pgm_base.cpp:211
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:187
MARKER_BASE * GetParent() const
Definition rc_item.h:136
static RC_TREE_NODE * ToNode(wxDataViewItem aItem)
Definition rc_item.h:259
void ValueChanged(RC_TREE_NODE *aNode)
Definition rc_item.cpp:586
void Update(std::shared_ptr< RC_ITEMS_PROVIDER > aProvider, int aSeverities)
Definition rc_item.cpp:413
void DeleteCurrentItem(bool aDeep)
Definition rc_item.cpp:637
static KIID ToUUID(wxDataViewItem aItem)
Definition rc_item.cpp:226
std::shared_ptr< RC_ITEM > m_RcItem
Definition rc_item.h:238
NODE_TYPE m_Type
Definition rc_item.h:237
Master controller class:
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)
Display an error or warning message box with aMessage.
Definition confirm.cpp:196
This file is part of the common library.
static bool g_lastDRCRun
static BOARD * g_lastDRCBoard
static bool g_lastFootprintTestsRun
static std::vector< std::pair< wxString, int > > g_lastIgnored
#define DIALOG_DRC_WINDOW_NAME
Definition dialog_drc.h:41
@ DRCE_FOOTPRINT_FILTERS
Definition drc_item.h:80
@ DRCE_UNCONNECTED_ITEMS
Definition drc_item.h:40
@ DRCE_INVALID_OUTLINE
Definition drc_item.h:73
@ DRCE_SCHEMATIC_FIELDS_PARITY
Definition drc_item.h:120
@ DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG
Definition drc_item.h:108
@ DRCE_MALFORMED_COURTYARD
Definition drc_item.h:68
@ DRCE_FIRST
Definition drc_item.h:39
@ DRCE_UNRESOLVED_VARIABLE
Definition drc_item.h:88
@ DRCE_DUPLICATE_FOOTPRINT
Definition drc_item.h:76
@ DRCE_EXTRA_FOOTPRINT
Definition drc_item.h:77
@ DRCE_LAST
Definition drc_item.h:122
@ DRCE_NET_CONFLICT
Definition drc_item.h:78
@ DRCE_MISSING_FOOTPRINT
Definition drc_item.h:75
@ DRCE_SCHEMATIC_PARITY
Definition drc_item.h:79
#define _(s)
#define MALFORMED_F_COURTYARD
#define MALFORMED_B_COURTYARD
static int DEFAULT_SINGLE_COL_WIDTH
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:424
void ForceFocus(wxWindow *aWindow)
Pass the current focus to the window.
Definition wxgtk/ui.cpp:125
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:435
STL namespace.
PGM_BASE & Pgm()
The global program "get" accessor.
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,...
@ MD_ALT
Definition tool_event.h:145
@ MD_CTRL
Definition tool_event.h:144
@ MD_SHIFT
Definition tool_event.h:143
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:105
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:84
Functions to provide common constants and other functions to assist in making a consistent UI.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
Definition of file extensions used in Kicad.