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