KiCad PCB EDA Suite
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 (C) 2004-2021 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>
28 #include <board_design_settings.h>
29 #include <kiface_base.h>
30 #include <macros.h>
31 #include <pad.h>
32 #include <pcb_edit_frame.h>
33 #include <pcbnew_settings.h>
34 #include <tool/tool_manager.h>
35 #include <tools/pcb_actions.h>
37 #include <pcb_marker.h>
38 #include <wx/filedlg.h>
39 #include <wx/wupdlock.h>
41 #include <widgets/ui_common.h>
45 #include <tools/drc_tool.h>
46 #include <tools/zone_filler_tool.h>
48 #include <kiplatform/ui.h>
49 
50 DIALOG_DRC::DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
51  DIALOG_DRC_BASE( aParent ),
53  m_running( false ),
54  m_cancelled( false ),
55  m_drcRun( false ),
56  m_footprintTestsRun( false ),
57  m_markersProvider( nullptr ),
58  m_markersTreeModel( nullptr ),
59  m_unconnectedItemsProvider( nullptr ),
60  m_unconnectedTreeModel( nullptr ),
61  m_footprintWarningsProvider( nullptr ),
62  m_footprintWarningsTreeModel( nullptr ),
63  m_centerMarkerOnIdle( nullptr ),
65 {
66  SetName( DIALOG_DRC_WINDOW_NAME ); // Set a window name to be able to find it
67 
68  m_frame = aEditorFrame;
70 
72 
74  m_markerDataView->AssociateModel( m_markersTreeModel );
75 
78 
81 
82  if( Kiface().IsSingle() )
83  m_cbTestFootprints->Hide();
84 
85  // We use a sdbSizer here to get the order right, which is platform-dependent
86  m_sdbSizerOK->SetLabel( _( "Run DRC" ) );
87  m_sdbSizerCancel->SetLabel( _( "Close" ) );
88  m_sizerButtons->Layout();
89 
90  m_sdbSizerOK->SetDefault();
91 
92  initValues();
94 
96 }
97 
98 
100 {
101  m_frame->FocusOnItem( nullptr );
102 
104  settings->m_DrcDialog.refill_zones = m_cbRefillZones->GetValue();
106 
107  if( !Kiface().IsSingle() )
108  settings->m_DrcDialog.test_footprints = m_cbTestFootprints->GetValue();
109 
110  settings->m_DrcDialog.severities = m_severities;
111 
112  m_markersTreeModel->DecRef();
113 }
114 
115 
116 void DIALOG_DRC::OnActivateDlg( wxActivateEvent& aEvent )
117 {
118  if( m_currentBoard != m_frame->GetBoard() )
119  {
120  // If m_currentBoard is not the current board, (for instance because a new board
121  // was loaded), close the dialog, because many pointers are now invalid in lists
122  SetReturnCode( wxID_CANCEL );
123  Close();
124 
125  DRC_TOOL* drcTool = m_frame->GetToolManager()->GetTool<DRC_TOOL>();
126  drcTool->DestroyDRCDialog();
127  }
128 }
129 
130 
132 {
133  m_markersTitleTemplate = m_Notebook->GetPageText( 0 );
134  m_unconnectedTitleTemplate = m_Notebook->GetPageText( 1 );
135  m_footprintsTitleTemplate = m_Notebook->GetPageText( 2 );
136 
137  auto cfg = m_frame->GetPcbNewSettings();
138 
139  m_cbRefillZones->SetValue( cfg->m_DrcDialog.refill_zones );
140  m_cbReportAllTrackErrors->SetValue( cfg->m_DrcDialog.test_all_track_errors );
141 
142 
143  if( !Kiface().IsSingle() )
144  m_cbTestFootprints->SetValue( cfg->m_DrcDialog.test_footprints );
145 
146  m_severities = cfg->m_DrcDialog.severities;
150 
151  Layout(); // adding the units above expanded Clearance text, now resize.
152 
153  SetFocus();
154 }
155 
156 
158 {
159  double cur = (double) m_progress.load() / m_maxProgress;
160  cur = std::max( 0.0, std::min( cur, 1.0 ) );
161 
162  m_gauge->SetValue( KiROUND( cur * 1000.0 ) );
163  wxSafeYield( this );
164 
165  return !m_cancelled;
166 }
167 
168 
169 void DIALOG_DRC::AdvancePhase( const wxString& aMessage )
170 {
172  SetCurrentProgress( 0.0 );
173 
174  m_messages->Report( aMessage );
175 }
176 
177 
178 // Don't globally define this; different facilities use different definitions of "ALL"
180 
181 
183 {
184  m_showAll->SetValue( m_severities == RPT_SEVERITY_ALL );
188 }
189 
190 
191 void DIALOG_DRC::OnErrorLinkClicked( wxHtmlLinkEvent& event )
192 {
193  m_frame->ShowBoardSetupDialog( _( "Custom Rules" ) );
194 }
195 
196 
197 void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
198 {
199  TOOL_MANAGER* toolMgr = m_frame->GetToolManager();
200  DRC_TOOL* drcTool = toolMgr->GetTool<DRC_TOOL>();
201  ZONE_FILLER_TOOL* zoneFillerTool = toolMgr->GetTool<ZONE_FILLER_TOOL>();
202  bool refillZones = m_cbRefillZones->GetValue();
203  bool reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue();
204  bool testFootprints = m_cbTestFootprints->GetValue();
205 
206  if( zoneFillerTool->IsBusy() )
207  {
208  wxBell();
209  return;
210  }
211 
212  // This is not the time to have stale or buggy rules. Ensure they're up-to-date
213  // and that they at least parse.
214  try
215  {
216  drcTool->GetDRCEngine()->InitEngine( m_frame->GetDesignRulesPath() );
217  }
218  catch( PARSE_ERROR& )
219  {
220  m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
221  m_DeleteCurrentMarkerButton->Enable( false );
222  m_DeleteAllMarkersButton->Enable( false );
223  m_saveReport->Enable( false );
224 
225  m_messages->Clear();
226  m_messages->Report( _( "DRC incomplete: could not compile custom design rules. " )
227  + wxT( "<a href='boardsetup'>" )
228  + _( "Show design rules." )
229  + wxT( "</a>" ) );
230  m_messages->Flush();
231 
232  Raise();
233  return;
234  }
235 
236  m_drcRun = false;
237  m_footprintTestsRun = false;
238  m_cancelled = false;
239 
241  deleteAllMarkers( true );
242  m_unconnectedTreeModel->DeleteItems( false, true, true );
243  m_footprintWarningsTreeModel->DeleteItems( false, true, true );
244 
245  Raise();
246 
247  m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
248  m_messages->Clear();
249  wxYield(); // Allow time slice to refresh Messages
250 
251  m_running = true;
252  m_sdbSizerCancel->SetLabel( _( "Cancel" ) );
253  m_sdbSizerOK->Enable( false );
254  m_DeleteCurrentMarkerButton->Enable( false );
255  m_DeleteAllMarkersButton->Enable( false );
256  m_saveReport->Enable( false );
257 
258  drcTool->RunTests( this, refillZones, reportAllTrackErrors, testFootprints );
259 
260  if( m_cancelled )
261  m_messages->Report( _( "-------- DRC cancelled by user.<br><br>" ) );
262  else
263  m_messages->Report( _( "Done.<br><br>" ) );
264 
265  Raise();
266  wxYield(); // Allow time slice to refresh Messages
267 
268  m_running = false;
269  m_sdbSizerCancel->SetLabel( _( "Close" ) );
270  m_sdbSizerOK->Enable( true );
271  m_DeleteCurrentMarkerButton->Enable( true );
272  m_DeleteAllMarkersButton->Enable( true );
273  m_saveReport->Enable( true );
274 
275  if( !m_cancelled )
276  {
277  wxMilliSleep( 500 );
278  m_runningResultsBook->ChangeSelection( 1 );
280  }
281 
282  refreshEditor();
283 }
284 
285 
287 {
288  m_markersProvider = aProvider;
291 }
292 
293 
295 {
296  m_unconnectedItemsProvider = aProvider;
299 }
300 
301 
303 {
304  m_footprintWarningsProvider = aProvider;
307 }
308 
309 
310 void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
311 {
312  BOARD* board = m_frame->GetBoard();
313  RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
314  const KIID& itemID = node ? RC_TREE_MODEL::ToUUID( aEvent.GetItem() ) : niluuid;
315  BOARD_ITEM* item = board->GetItem( itemID );
316 
317  auto getActiveLayers =
318  []( BOARD_ITEM* aItem ) -> LSET
319  {
320  if( aItem->Type() == PCB_PAD_T )
321  {
322  PAD* pad = static_cast<PAD*>( aItem );
323  LSET layers;
324 
325  for( int layer : aItem->GetLayerSet().Seq() )
326  {
327  if( pad->FlashLayer( layer ) )
328  layers.set( layer );
329  }
330 
331  return layers;
332  }
333  else
334  {
335  return aItem->GetLayerSet();
336  }
337  };
338 
339  if( node && item )
340  {
341  PCB_LAYER_ID principalLayer = item->GetLayer();
342  LSET violationLayers;
343  std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
344 
345  if( rc_item->GetErrorCode() == DRCE_MALFORMED_COURTYARD )
346  {
347  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
348 
349  if( a && ( a->GetFlags() & MALFORMED_B_COURTYARD ) > 0
350  && ( a->GetFlags() & MALFORMED_F_COURTYARD ) == 0 )
351  {
352  principalLayer = B_CrtYd;
353  }
354  else
355  {
356  principalLayer = F_CrtYd;
357  }
358  }
359  else if (rc_item->GetErrorCode() == DRCE_INVALID_OUTLINE )
360  {
361  principalLayer = Edge_Cuts;
362  }
363  else
364  {
365  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
366  BOARD_ITEM* b = board->GetItem( rc_item->GetAuxItemID() );
367  BOARD_ITEM* c = board->GetItem( rc_item->GetAuxItem2ID() );
368  BOARD_ITEM* d = board->GetItem( rc_item->GetAuxItem3ID() );
369 
370  if( a || b || c || d )
371  violationLayers = LSET::AllLayersMask();
372 
373  if( a )
374  violationLayers &= getActiveLayers( a );
375 
376  if( b )
377  violationLayers &= getActiveLayers( b );
378 
379  if( c )
380  violationLayers &= getActiveLayers( c );
381 
382  if( d )
383  violationLayers &= getActiveLayers( d );
384  }
385 
386  if( violationLayers.count() )
387  principalLayer = violationLayers.Seq().front();
388  else
389  violationLayers.set( principalLayer );
390 
391  WINDOW_THAWER thawer( m_frame );
392 
393  if( ( violationLayers & board->GetVisibleLayers() ) == 0 )
394  m_frame->GetAppearancePanel()->SetLayerVisible( principalLayer, true );
395 
396  if( board->GetVisibleLayers().test( principalLayer ) )
397  m_frame->SetActiveLayer( principalLayer );
398 
400  {
401  // we already came from a cross-probe of the marker in the document; don't go
402  // around in circles
403  }
404  else
405  {
406  m_frame->FocusOnItem( item, principalLayer );
407  }
408  }
409 
410  aEvent.Skip();
411 }
412 
413 
414 void DIALOG_DRC::OnDRCItemDClick( wxDataViewEvent& aEvent )
415 {
416  if( aEvent.GetItem().IsOk() )
417  {
418  // turn control over to m_frame, hide this DIALOG_DRC window,
419  // no destruction so we can preserve listbox cursor
420  if( !IsModal() )
421  Show( false );
422  }
423 
424  // Do not skip aVent here: this is not useful, and Pcbnew crashes
425  // if skipped (at least on Windows)
426 }
427 
428 
429 void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
430 {
431  RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
432 
433  if( !node )
434  return;
435 
436  std::shared_ptr<RC_ITEM> rcItem = node->m_RcItem;
437  wxString listName;
438  wxMenu menu;
439  wxString msg;
440 
441  switch( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] )
442  {
443  case RPT_SEVERITY_ERROR: listName = _( "errors" ); break;
444  case RPT_SEVERITY_WARNING: listName = _( "warnings" ); break;
445  default: listName = _( "appropriate" ); break;
446  }
447 
448  if( rcItem->GetParent()->IsExcluded() )
449  {
450  menu.Append( 1, _( "Remove exclusion for this violation" ),
451  wxString::Format( _( "It will be placed back in the %s list" ), listName ) );
452  }
453  else
454  {
455  menu.Append( 2, _( "Exclude this violation" ),
456  wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
457  }
458 
459  if( rcItem->GetErrorCode() == DRCE_CLEARANCE
460  || rcItem->GetErrorCode() == DRCE_EDGE_CLEARANCE )
461  {
462  menu.Append( 3, _( "Run clearance resolution tool..." ) );
463  }
464 
465  menu.AppendSeparator();
466 
467  if( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] == RPT_SEVERITY_WARNING )
468  {
469  msg.Printf( _( "Change severity to Error for all '%s' violations" ),
470  rcItem->GetErrorText(),
471  _( "Violation severities can also be edited in the Board Setup... dialog" ) );
472  menu.Append( 4, msg );
473  }
474  else
475  {
476  msg.Printf( _( "Change severity to Warning for all '%s' violations" ),
477  rcItem->GetErrorText(),
478  _( "Violation severities can also be edited in the Board Setup... dialog" ) );
479  menu.Append( 5, msg );
480  }
481 
482  msg.Printf( _( "Ignore all '%s' violations" ),
483  rcItem->GetErrorText(),
484  _( "Violations will not be checked or reported" ) );
485  menu.Append( 6, msg );
486 
487  menu.AppendSeparator();
488 
489  menu.Append( 7, _( "Edit violation severities..." ), _( "Open the Board Setup... dialog" ) );
490 
491  bool modified = false;
492 
493  switch( GetPopupMenuSelectionFromUser( menu ) )
494  {
495  case 1:
496  {
497  PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() );
498 
499  if( marker )
500  {
501  marker->SetExcluded( false );
502  m_frame->GetCanvas()->GetView()->Update( marker );
503 
504  // Update view
505  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
506  modified = true;
507  }
508 
509  break;
510  }
511 
512  case 2:
513  {
514  PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() );
515 
516  if( marker )
517  {
518  marker->SetExcluded( true );
519  m_frame->GetCanvas()->GetView()->Update( marker );
520 
521  // Update view
523  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
524  else
525  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false );
526 
527  modified = true;
528  }
529 
530  break;
531  }
532 
533  case 3:
534  {
535  TOOL_MANAGER* toolMgr = m_frame->GetToolManager();
536  BOARD_INSPECTION_TOOL* inspectionTool = toolMgr->GetTool<BOARD_INSPECTION_TOOL>();
537 
538  inspectionTool->InspectDRCError( node->m_RcItem );
539  break;
540  }
541 
542  case 4:
543  bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_ERROR;
544 
545  for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
546  {
547  if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
548  m_frame->GetCanvas()->GetView()->Update( marker );
549  }
550 
551  // Rebuild model and view
552  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markersProvider );
553  modified = true;
554  break;
555 
556  case 5:
557  bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_WARNING;
558 
559  for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
560  {
561  if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
562  m_frame->GetCanvas()->GetView()->Update( marker );
563  }
564 
565  // Rebuild model and view
566  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markersProvider );
567  modified = true;
568  break;
569 
570  case 6:
571  {
572  bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_IGNORE;
573 
574  std::vector<PCB_MARKER*>& markers = m_frame->GetBoard()->Markers();
575 
576  for( unsigned i = 0; i < markers.size(); )
577  {
578  if( markers[i]->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
579  {
580  m_frame->GetCanvas()->GetView()->Remove( markers.at( i ) );
581  markers.erase( markers.begin() + i );
582  }
583  else
584  ++i;
585  }
586 
587  // Rebuild model and view
588  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markersProvider );
589  modified = true;
590  break;
591  }
592 
593  case 7:
594  m_frame->ShowBoardSetupDialog( _( "Violation Severity" ) );
595  break;
596  }
597 
598  if( modified )
599  {
601  refreshEditor();
602  m_frame->OnModify();
603  }
604 }
605 
606 
607 void DIALOG_DRC::OnSeverity( wxCommandEvent& aEvent )
608 {
609  int flag = 0;
610 
611  if( aEvent.GetEventObject() == m_showAll )
613  else if( aEvent.GetEventObject() == m_showErrors )
615  else if( aEvent.GetEventObject() == m_showWarnings )
617  else if( aEvent.GetEventObject() == m_showExclusions )
619 
620  if( aEvent.IsChecked() )
621  m_severities |= flag;
622  else if( aEvent.GetEventObject() == m_showAll )
624  else
625  m_severities &= ~flag;
626 
627  syncCheckboxes();
628 
629  // Set the provider's severity levels through the TreeModel so that the old tree
630  // can be torn down before the severity changes.
631  //
632  // It's not clear this is required, but we've had a lot of issues with wxDataView
633  // being cranky on various platforms.
634 
638 
640 }
641 
642 
643 void DIALOG_DRC::OnSaveReport( wxCommandEvent& aEvent )
644 {
645  wxFileName fn( "./DRC." + ReportFileExtension );
646 
647  wxFileDialog dlg( this, _( "Save Report to File" ), fn.GetPath(), fn.GetFullName(),
648  ReportFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
649 
650  if( dlg.ShowModal() != wxID_OK )
651  return;
652 
653  fn = dlg.GetPath();
654 
655  if( fn.GetExt().IsEmpty() )
656  fn.SetExt( ReportFileExtension );
657 
658  if( !fn.IsAbsolute() )
659  {
660  wxString prj_path = Prj().GetProjectPath();
661  fn.MakeAbsolute( prj_path );
662  }
663 
664  if( writeReport( fn.GetFullPath() ) )
665  {
666  m_messages->Report( wxString::Format( _( "Report file '%s' created<br>" ),
667  fn.GetFullPath() ) );
668  }
669  else
670  {
671  DisplayError( this, wxString::Format( _( "Failed to create file '%s'." ),
672  fn.GetFullPath() ) );
673  }
674 }
675 
676 
677 void DIALOG_DRC::OnClose( wxCloseEvent& aEvent )
678 {
679  if( m_running )
680  aEvent.Veto();
681 
682  wxCommandEvent dummy;
683 
684  OnCancelClick( dummy );
685 }
686 
687 
688 void DIALOG_DRC::OnCancelClick( wxCommandEvent& aEvent )
689 {
690  if( m_running )
691  {
692  m_cancelled = true;
693  return;
694  }
695 
696  m_frame->FocusOnItem( nullptr );
697 
698  SetReturnCode( wxID_CANCEL );
699 
700  // The dialog can be modal or not modal.
701  // Leave the DRC caller destroy (or not) the dialog
702  DRC_TOOL* drcTool = m_frame->GetToolManager()->GetTool<DRC_TOOL>();
703  drcTool->DestroyDRCDialog();
704 }
705 
706 
707 void DIALOG_DRC::OnChangingNotebookPage( wxNotebookEvent& aEvent )
708 {
709  // Shouldn't be necessary, but is on at least OSX
710  if( aEvent.GetSelection() >= 0 )
711  m_Notebook->ChangeSelection( (unsigned) aEvent.GetSelection() );
712 
713  m_markerDataView->UnselectAll();
714  m_unconnectedDataView->UnselectAll();
715  m_footprintsDataView->UnselectAll();
716 }
717 
718 
720 {
721  WINDOW_THAWER thawer( m_frame );
722 
723  m_frame->GetCanvas()->Refresh();
724 }
725 
726 
728 {
729  if( m_Notebook->IsShown() )
730  {
731  switch( m_Notebook->GetSelection() )
732  {
733  case 0: m_markersTreeModel->PrevMarker(); break;
734  case 1: m_unconnectedTreeModel->PrevMarker(); break;
735  case 2: m_footprintWarningsTreeModel->PrevMarker(); break;
736  }
737  }
738 }
739 
740 
742 {
743  if( m_Notebook->IsShown() )
744  {
745  switch( m_Notebook->GetSelection() )
746  {
747  case 0: m_markersTreeModel->NextMarker(); break;
748  case 1: m_unconnectedTreeModel->NextMarker(); break;
749  case 2: m_footprintWarningsTreeModel->NextMarker(); break;
750  }
751  }
752 }
753 
754 
755 void DIALOG_DRC::SelectMarker( const PCB_MARKER* aMarker )
756 {
757  if( m_Notebook->IsShown() )
758  {
759  m_Notebook->SetSelection( 0 );
760  m_markersTreeModel->SelectMarker( aMarker );
761 
762  // wxWidgets on some platforms fails to correctly ensure that a selected item is
763  // visible, so we have to do it in a separate idle event.
764  m_centerMarkerOnIdle = aMarker;
765  Bind( wxEVT_IDLE, &DIALOG_DRC::centerMarkerIdleHandler, this );
766  }
767 }
768 
769 
770 void DIALOG_DRC::centerMarkerIdleHandler( wxIdleEvent& aEvent )
771 {
773  m_centerMarkerOnIdle = nullptr;
774  Unbind( wxEVT_IDLE, &DIALOG_DRC::centerMarkerIdleHandler, this );
775 }
776 
777 
779 {
780  if( !m_Notebook->IsShown() || m_Notebook->GetSelection() != 0 )
781  return;
782 
783  RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( m_markerDataView->GetCurrentItem() );
784  PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() );
785 
786  if( marker && !marker->IsExcluded() )
787  {
788  marker->SetExcluded( true );
789  m_frame->GetCanvas()->GetView()->Update( marker );
790 
791  // Update view
794  else
796 
798  refreshEditor();
799  m_frame->OnModify();
800  }
801 }
802 
803 
804 void DIALOG_DRC::deleteAllMarkers( bool aIncludeExclusions )
805 {
806  // Clear current selection list to avoid selection of deleted items
808 
809  m_markersTreeModel->DeleteItems( false, aIncludeExclusions, true );
810 }
811 
812 
813 bool DIALOG_DRC::writeReport( const wxString& aFullFileName )
814 {
815  FILE* fp = wxFopen( aFullFileName, wxT( "w" ) );
816 
817  if( fp == nullptr )
818  return false;
819 
820  std::map<KIID, EDA_ITEM*> itemMap;
821  m_frame->GetBoard()->FillItemMap( itemMap );
822 
823  EDA_UNITS units = GetUserUnits();
825  int count;
826 
827  fprintf( fp, "** Drc report for %s **\n", TO_UTF8( m_frame->GetBoard()->GetFileName() ) );
828 
829  wxDateTime now = wxDateTime::Now();
830 
831  fprintf( fp, "** Created on %s **\n", TO_UTF8( now.Format( wxT( "%F %T" ) ) ) );
832 
833  count = m_markersProvider->GetCount();
834 
835  fprintf( fp, "\n** Found %d DRC violations **\n", count );
836 
837  for( int i = 0; i < count; ++i )
838  {
839  const std::shared_ptr<RC_ITEM>& item = m_markersProvider->GetItem( i );
840  SEVERITY severity = bds.GetSeverity( item->GetErrorCode() );
841 
842  fprintf( fp, "%s", TO_UTF8( item->ShowReport( units, severity, itemMap ) ) );
843  }
844 
846 
847  fprintf( fp, "\n** Found %d unconnected pads **\n", count );
848 
849  for( int i = 0; i < count; ++i )
850  {
851  const std::shared_ptr<RC_ITEM>& item = m_unconnectedItemsProvider->GetItem( i );
852  SEVERITY severity = bds.GetSeverity( item->GetErrorCode() );
853 
854  fprintf( fp, "%s", TO_UTF8( item->ShowReport( units, severity, itemMap ) ) );
855  }
856 
858 
859  fprintf( fp, "\n** Found %d Footprint errors **\n", count );
860 
861  for( int i = 0; i < count; ++i )
862  {
863  const std::shared_ptr<RC_ITEM>& item = m_footprintWarningsProvider->GetItem( i );
864  SEVERITY severity = bds.GetSeverity( item->GetErrorCode() );
865 
866  fprintf( fp, "%s", TO_UTF8( item->ShowReport( units, severity, itemMap ) ) );
867  }
868 
869 
870  fprintf( fp, "\n** End of Report **\n" );
871 
872  fclose( fp );
873 
874  return true;
875 }
876 
877 
878 void DIALOG_DRC::OnDeleteOneClick( wxCommandEvent& aEvent )
879 {
880  if( m_Notebook->GetSelection() == 0 )
881  {
882  // Clear the selection. It may be the selected DRC marker.
884 
886 
887  // redraw the pcb
888  refreshEditor();
889  }
890  else if( m_Notebook->GetSelection() == 1 )
891  {
893  }
894  else if( m_Notebook->GetSelection() == 2 )
895  {
897  }
898 
900 }
901 
902 
903 void DIALOG_DRC::OnDeleteAllClick( wxCommandEvent& aEvent )
904 {
905  static bool s_includeExclusions = false;
906 
907  int numExcluded = 0;
908 
909  if( m_markersProvider )
911 
914 
917 
918  if( numExcluded > 0 )
919  {
920  wxRichMessageDialog dlg( this, _( "Do you wish to delete excluded markers as well?" ),
921  _( "Delete All Markers" ),
922  wxOK | wxCANCEL | wxCENTER | wxICON_QUESTION );
923  dlg.ShowCheckBox( _( "Delete exclusions" ), s_includeExclusions );
924 
925  int ret = dlg.ShowModal();
926 
927  if( ret == wxID_CANCEL )
928  return;
929  else
930  s_includeExclusions = dlg.IsCheckBoxChecked();
931  }
932 
933  deleteAllMarkers( s_includeExclusions );
934 
935  m_drcRun = false;
936  refreshEditor();
938 }
939 
940 
942 {
943  // Collect counts:
944 
945  int numMarkers = 0;
946  int numUnconnected = 0;
947  int numFootprints = 0;
948 
949  int numErrors = 0;
950  int numWarnings = 0;
951  int numExcluded = 0;
952 
953  if( m_markersProvider )
954  {
955  numMarkers += m_markersProvider->GetCount();
959  }
960 
962  {
963  numUnconnected += m_unconnectedItemsProvider->GetCount();
967  }
968 
970  {
971  numFootprints += m_footprintWarningsProvider->GetCount();
975  }
976 
977  wxString msg;
978 
979  // Update tab headers:
980 
981  if( m_drcRun )
982  {
983  msg.sprintf( m_markersTitleTemplate, numMarkers );
984  m_Notebook->SetPageText( 0, msg );
985 
986  msg.sprintf( m_unconnectedTitleTemplate, numUnconnected );
987  m_Notebook->SetPageText( 1, msg );
988 
989  if( m_footprintTestsRun )
990  {
991  msg.sprintf( m_footprintsTitleTemplate, numFootprints );
992  }
993  else
994  {
996  msg.Replace( wxT( "%d" ), _( "not run" ) );
997  }
998  m_Notebook->SetPageText( 2, msg );
999  }
1000  else
1001  {
1002  msg = m_markersTitleTemplate;
1003  msg.Replace( wxT( "(%d)" ), wxEmptyString );
1004  m_Notebook->SetPageText( 0, msg );
1005 
1007  msg.Replace( wxT( "(%d)" ), wxEmptyString );
1008  m_Notebook->SetPageText( 1, msg );
1009 
1011  msg.Replace( wxT( "(%d)" ), wxEmptyString );
1012  m_Notebook->SetPageText( 2, msg );
1013  }
1014 
1015  // Update badges:
1016 
1017  if( !m_drcRun && numErrors == 0 )
1018  numErrors = -1;
1019 
1020  if( !m_drcRun && numWarnings == 0 )
1021  numWarnings = -1;
1022 
1023  m_errorsBadge->SetMaximumNumber( numErrors );
1025 
1026  m_warningsBadge->SetMaximumNumber( numWarnings );
1028 
1029  m_exclusionsBadge->SetMaximumNumber( numExcluded );
1031 }
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
wxCheckBox * m_showWarnings
BOARD_ITEM * GetItem(const KIID &aID) const
Definition: board.cpp:845
void initValues()
Definition: dialog_drc.cpp:131
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:279
void DeleteItems(bool aCurrentOnly, bool aIncludeExclusions, bool aDeep)
Deletes the current item or all items.
Definition: rc_item.cpp:459
void syncCheckboxes()
Definition: dialog_drc.cpp:182
wxCheckBox * m_cbTestFootprints
void OnModify() override
Must be called after a board change to set the modified flag.
void NextMarker()
Definition: rc_item.cpp:569
wxNotebook * m_Notebook
void NextMarker()
Definition: dialog_drc.cpp:741
void updateDisplayedCounts()
Definition: dialog_drc.cpp:941
BOARD_DESIGN_SETTINGS & bds()
Definition: dialog_drc.h:109
static int RPT_SEVERITY_ALL
Definition: dialog_drc.cpp:179
KIID niluuid(0)
void OnDRCItemRClick(wxDataViewEvent &aEvent) override
Definition: dialog_drc.cpp:429
#define MALFORMED_B_COURTYARD
void SetProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: rc_item.cpp:292
void OnErrorLinkClicked(wxHtmlLinkEvent &event) override
Definition: dialog_drc.cpp:191
wxCheckBox * m_cbReportAllTrackErrors
void deleteAllMarkers(bool aIncludeExclusions)
Definition: dialog_drc.cpp:804
wxButton * m_DeleteCurrentMarkerButton
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
void CenterMarker(const MARKER_BASE *aMarker)
Definition: rc_item.cpp:610
This file is part of the common library.
void Clear()
Delete the stored messages.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
Class DIALOG_DRC_BASE.
virtual void AdvancePhase() override
Use the next available virtual zone of the dialog progress bar.
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
wxSimplebook * m_runningResultsBook
MARKERS & Markers()
Definition: board.h:242
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
#define MALFORMED_F_COURTYARD
bool writeReport(const wxString &aFullFileName)
Function writeReport outputs the MARKER items and unconnecte DRC_ITEMs with commentary to an open tex...
Definition: dialog_drc.cpp:813
void Flush()
Build the HTML messages page.
void UpdateNumber(int aNumber, SEVERITY aSeverity)
Update the number displayed on the badge.
void PrevMarker()
Definition: dialog_drc.cpp:727
void InspectDRCError(const std::shared_ptr< RC_ITEM > &aDRCItem)
Show the clearance resolution for two selected items.
void OnDeleteOneClick(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:878
bool m_footprintTestsRun
Definition: dialog_drc.h:116
wxString m_footprintsTitleTemplate
Definition: dialog_drc.h:120
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:481
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
class PAD, a pad in a footprint
Definition: typeinfo.h:89
wxButton * m_sdbSizerCancel
static KIID ToUUID(wxDataViewItem aItem)
Definition: rc_item.cpp:147
void ExcludeMarker()
Definition: dialog_drc.cpp:778
RC_ITEMS_PROVIDER * m_markersProvider
Definition: dialog_drc.h:122
void OnDRCItemDClick(wxDataViewEvent &aEvent) override
Definition: dialog_drc.cpp:414
void RecordDRCExclusions()
Scan existing markers and record data from any that are Excluded.
virtual int GetCount(int aSeverity=-1) const =0
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
APPEARANCE_CONTROLS * GetAppearancePanel()
const wxString & GetFileName() const
Definition: board.h:228
BOARD * m_currentBoard
Definition: dialog_drc.h:111
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:122
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition: pcb_view.cpp:75
void DeleteCurrentItem(bool aDeep)
Definition: rc_item.cpp:453
void SetSeverities(int aSeverities)
Definition: rc_item.cpp:298
This file contains miscellaneous commonly used macros and functions.
Provide an abstract interface of a RC_ITEM* list manager.
Definition: rc_item.h:45
void OnChangingNotebookPage(wxNotebookEvent &aEvent) override
Definition: dialog_drc.cpp:707
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:121
RC_ITEMS_PROVIDER * m_unconnectedItemsProvider
Definition: dialog_drc.h:125
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
Master controller class:
Definition: tool_manager.h:54
wxCheckBox * m_showExclusions
Definition: kiid.h:44
wxString m_markersTitleTemplate
Definition: dialog_drc.h:118
void SetImmediateMode()
In immediate mode, messages are flushed as they are added.
wxCheckBox * m_cbRefillZones
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: pcb_view.cpp:92
Handle actions specific to filling copper zones.
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:504
void SetExcluded(bool aExcluded)
Definition: marker_base.h:95
void ShowBoardSetupDialog(const wxString &aInitialPage=wxEmptyString)
std::shared_ptr< RC_ITEM > m_RcItem
Definition: rc_item.h:195
wxDataViewCtrl * m_footprintsDataView
RC_ITEMS_PROVIDER * m_footprintWarningsProvider
Definition: dialog_drc.h:128
wxBoxSizer * m_sizerButtons
wxButton * m_DeleteAllMarkersButton
wxButton * m_sdbSizerOK
void OnDeleteAllClick(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:903
static RC_TREE_NODE * ToNode(wxDataViewItem aItem)
Definition: rc_item.h:210
wxString ReportFileWildcard()
void OnDRCItemSelected(wxDataViewEvent &aEvent) override
Definition: dialog_drc.cpp:310
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
DIALOG_DRC(PCB_EDIT_FRAME *aEditorFrame, wxWindow *aParent)
Constructors.
Definition: dialog_drc.cpp:50
RC_TREE_MODEL * m_footprintWarningsTreeModel
Definition: dialog_drc.h:129
void SetFootprintsProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: dialog_drc.cpp:302
std::atomic< bool > m_cancelled
Definition: dialog_drc.h:114
Definition of file extensions used in Kicad.
NUMBER_BADGE * m_exclusionsBadge
void SelectMarker(const MARKER_BASE *aMarker)
Definition: rc_item.cpp:597
#define DIALOG_DRC_WINDOW_NAME
Definition: dialog_drc.h:41
Functions to provide common constants and other functions to assist in making a consistent UI.
#define _(s)
NUMBER_BADGE * m_errorsBadge
static LSET AllLayersMask()
Definition: lset.cpp:787
SEVERITY GetSeverity(int aDRCErrorCode)
void OnClose(wxCloseEvent &event) override
Definition: dialog_drc.cpp:677
SEVERITY
void PrevMarker()
Definition: rc_item.cpp:548
std::shared_ptr< DRC_ENGINE > GetDRCEngine()
Definition: drc_tool.h:78
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
void OnRunDRCClick(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:197
bool Show(bool show) override
void FocusOnItem(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
void RunTests(PROGRESS_REPORTER *aProgressReporter, bool aRefillZones, bool aReportAllTrackErrors, bool aTestFootprints)
Run the DRC tests.
Definition: drc_tool.cpp:132
RC_TREE_MODEL * m_unconnectedTreeModel
Definition: dialog_drc.h:126
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:155
This implements all the tricky bits for thread safety, but the GUI is left to derived classes.
wxDataViewCtrl * m_unconnectedDataView
void OnCancelClick(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:688
wxButton * m_saveReport
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
EDA_UNITS
Definition: eda_units.h:38
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void SetMarkersProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: dialog_drc.cpp:286
wxDataViewCtrl * m_markerDataView
virtual std::shared_ptr< RC_ITEM > GetItem(int aIndex) const =0
Retrieve a RC_ITEM by index.
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:118
WX_HTML_REPORT_BOX * m_messages
const std::string ReportFileExtension
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
void ForceFocus(wxWindow *aWindow)
Pass the current focus to the window.
Definition: gtk/ui.cpp:44
void refreshEditor()
Definition: dialog_drc.cpp:719
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
wxCheckBox * m_showErrors
std::map< int, SEVERITY > m_DRCSeverities
NUMBER_BADGE * m_warningsBadge
wxCheckBox * m_showAll
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
The main frame for Pcbnew.
PCBNEW_SETTINGS * GetPcbNewSettings() const
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
void OnActivateDlg(wxActivateEvent &aEvent) override
Definition: dialog_drc.cpp:116
bool m_drcRun
Definition: dialog_drc.h:115
void SelectMarker(const PCB_MARKER *aMarker)
Definition: dialog_drc.cpp:755
int m_severities
Definition: dialog_drc.h:133
void SetLayerVisible(LAYER_NUM aLayer, bool isVisible)
void ValueChanged(const RC_TREE_NODE *aNode)
Definition: rc_item.cpp:436
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
virtual void SetCurrentProgress(double aProgress) override
Set the progress value to aProgress (0..1).
RC_TREE_MODEL * m_markersTreeModel
Definition: dialog_drc.h:123
DIALOG_DRC m_DrcDialog
BOARD * GetBoard() const
void DestroyDRCDialog()
Close and free the DRC dialog.
Definition: drc_tool.cpp:122
Definition: pad.h:57
PCB_EDIT_FRAME * m_frame
Definition: dialog_drc.h:112
void OnSaveReport(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:643
void centerMarkerIdleHandler(wxIdleEvent &aEvent)
Definition: dialog_drc.cpp:770
const PCB_MARKER * m_centerMarkerOnIdle
Definition: dialog_drc.h:131
void SetMaximumNumber(int aMax)
Set the maximum number to be shown on the badge.
bool m_running
Definition: dialog_drc.h:113
bool updateUI() override
Definition: dialog_drc.cpp:157
void SetActiveLayer(PCB_LAYER_ID aLayer) override
Change the currently active layer to aLayer and also update the APPEARANCE_CONTROLS.
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Definition: board.cpp:924
void SetUnconnectedProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: dialog_drc.cpp:294
wxString m_unconnectedTitleTemplate
Definition: dialog_drc.h:119
void OnSeverity(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:607
Container for design settings for a BOARD object.
Tool for pcb inspection.