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, dick@softplc.com
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_i.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 ),
52  PROGRESS_REPORTER( 1 ),
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 ),
64 {
65  SetName( DIALOG_DRC_WINDOW_NAME ); // Set a window name to be able to find it
66 
67  m_frame = aEditorFrame;
69 
71 
73  m_markerDataView->AssociateModel( m_markersTreeModel );
74 
77 
80 
81  if( Kiface().IsSingle() )
82  m_cbTestFootprints->Hide();
83 
84  // We use a sdbSizer here to get the order right, which is platform-dependent
85  m_sdbSizerOK->SetLabel( _( "Run DRC" ) );
86  m_sdbSizerCancel->SetLabel( _( "Close" ) );
87  m_sizerButtons->Layout();
88 
89  m_sdbSizerOK->SetDefault();
90 
91  initValues();
93 
95 }
96 
97 
99 {
100  m_frame->FocusOnItem( nullptr );
101 
103  settings->m_DrcDialog.refill_zones = m_cbRefillZones->GetValue();
105 
106  if( !Kiface().IsSingle() )
107  settings->m_DrcDialog.test_footprints = m_cbTestFootprints->GetValue();
108 
109  settings->m_DrcDialog.severities = m_severities;
110 
111  m_markersTreeModel->DecRef();
112 }
113 
114 
115 void DIALOG_DRC::OnActivateDlg( wxActivateEvent& aEvent )
116 {
117  if( m_currentBoard != m_frame->GetBoard() )
118  {
119  // If m_currentBoard is not the current board, (for instance because a new board
120  // was loaded), close the dialog, because many pointers are now invalid in lists
121  SetReturnCode( wxID_CANCEL );
122  Close();
123 
124  DRC_TOOL* drcTool = m_frame->GetToolManager()->GetTool<DRC_TOOL>();
125  drcTool->DestroyDRCDialog();
126  }
127 }
128 
129 
131 {
132  m_markersTitleTemplate = m_Notebook->GetPageText( 0 );
133  m_unconnectedTitleTemplate = m_Notebook->GetPageText( 1 );
134  m_footprintsTitleTemplate = m_Notebook->GetPageText( 2 );
135 
136  auto cfg = m_frame->GetPcbNewSettings();
137 
138  m_cbRefillZones->SetValue( cfg->m_DrcDialog.refill_zones );
139  m_cbReportAllTrackErrors->SetValue( cfg->m_DrcDialog.test_all_track_errors );
140 
141 
142  if( !Kiface().IsSingle() )
143  m_cbTestFootprints->SetValue( cfg->m_DrcDialog.test_footprints );
144 
145  m_severities = cfg->m_DrcDialog.severities;
149 
150  Layout(); // adding the units above expanded Clearance text, now resize.
151 
152  SetFocus();
153 }
154 
155 
157 {
158  double cur = (double) m_progress.load() / m_maxProgress;
159  cur = std::max( 0.0, std::min( cur, 1.0 ) );
160 
161  m_gauge->SetValue( KiROUND( cur * 1000.0 ) );
162  wxSafeYield( this );
163 
164  return !m_cancelled;
165 }
166 
167 
168 void DIALOG_DRC::AdvancePhase( const wxString& aMessage )
169 {
171  SetCurrentProgress( 0.0 );
172 
173  m_messages->Report( aMessage );
174 }
175 
176 
177 // Don't globally define this; different facilities use different definitions of "ALL"
179 
180 
182 {
183  m_showAll->SetValue( m_severities == RPT_SEVERITY_ALL );
187 }
188 
189 
190 void DIALOG_DRC::OnErrorLinkClicked( wxHtmlLinkEvent& event )
191 {
192  m_frame->ShowBoardSetupDialog( _( "Rules" ) );
193 }
194 
195 
196 void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
197 {
198  TOOL_MANAGER* toolMgr = m_frame->GetToolManager();
199  DRC_TOOL* drcTool = toolMgr->GetTool<DRC_TOOL>();
200  ZONE_FILLER_TOOL* zoneFillerTool = toolMgr->GetTool<ZONE_FILLER_TOOL>();
201  bool refillZones = m_cbRefillZones->GetValue();
202  bool reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue();
203  bool testFootprints = m_cbTestFootprints->GetValue();
204 
205  if( zoneFillerTool->IsBusy() )
206  {
207  wxBell();
208  return;
209  }
210 
211  // This is not the time to have stale or buggy rules. Ensure they're up-to-date
212  // and that they at least parse.
213  try
214  {
215  drcTool->GetDRCEngine()->InitEngine( m_frame->GetDesignRulesPath() );
216  }
217  catch( PARSE_ERROR& )
218  {
219  m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
220  m_DeleteCurrentMarkerButton->Enable( false );
221  m_DeleteAllMarkersButton->Enable( false );
222  m_saveReport->Enable( false );
223 
224  m_messages->Clear();
225  m_messages->Report( _( "DRC incomplete: could not compile custom design rules. " )
226  + wxT( "<a href='boardsetup'>" )
227  + _( "Show design rules." )
228  + wxT( "</a>" ) );
229  m_messages->Flush();
230 
231  Raise();
232  return;
233  }
234 
235  m_drcRun = false;
236  m_footprintTestsRun = false;
237  m_cancelled = false;
238 
240  deleteAllMarkers( true );
241  m_unconnectedTreeModel->DeleteItems( false, true, true );
242  m_footprintWarningsTreeModel->DeleteItems( false, true, true );
243 
244  Raise();
245 
246  m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
247  m_messages->Clear();
248  wxYield(); // Allow time slice to refresh Messages
249 
250  m_running = true;
251  m_sdbSizerCancel->SetLabel( _( "Cancel" ) );
252  m_sdbSizerOK->Enable( false );
253  m_DeleteCurrentMarkerButton->Enable( false );
254  m_DeleteAllMarkersButton->Enable( false );
255  m_saveReport->Enable( false );
256 
257  drcTool->RunTests( this, refillZones, reportAllTrackErrors, testFootprints );
258 
259  if( m_cancelled )
260  m_messages->Report( _( "-------- DRC cancelled by user.<br><br>" ) );
261  else
262  m_messages->Report( _( "Done.<br><br>" ) );
263 
264  Raise();
265  wxYield(); // Allow time slice to refresh Messages
266 
267  m_running = false;
268  m_sdbSizerCancel->SetLabel( _( "Close" ) );
269  m_sdbSizerOK->Enable( true );
270  m_DeleteCurrentMarkerButton->Enable( true );
271  m_DeleteAllMarkersButton->Enable( true );
272  m_saveReport->Enable( true );
273 
274  if( !m_cancelled )
275  {
276  wxMilliSleep( 500 );
277  m_runningResultsBook->ChangeSelection( 1 );
279  }
280 
281  refreshEditor();
282 }
283 
284 
286 {
287  m_markersProvider = aProvider;
290 }
291 
292 
294 {
295  m_unconnectedItemsProvider = aProvider;
298 }
299 
300 
302 {
303  m_footprintWarningsProvider = aProvider;
306 }
307 
308 
309 void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
310 {
311  BOARD* board = m_frame->GetBoard();
312  RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
313  const KIID& itemID = node ? RC_TREE_MODEL::ToUUID( aEvent.GetItem() ) : niluuid;
314  BOARD_ITEM* item = board->GetItem( itemID );
315 
316  auto getActiveLayers =
317  []( BOARD_ITEM* aItem ) -> LSET
318  {
319  if( aItem->Type() == PCB_PAD_T )
320  {
321  PAD* pad = static_cast<PAD*>( aItem );
322  LSET layers;
323 
324  for( int layer : aItem->GetLayerSet().Seq() )
325  {
326  if( pad->FlashLayer( layer ) )
327  layers.set( layer );
328  }
329 
330  return layers;
331  }
332  else
333  {
334  return aItem->GetLayerSet();
335  }
336  };
337 
338  if( node && item )
339  {
340  PCB_LAYER_ID principalLayer = item->GetLayer();
341  LSET violationLayers;
342  std::shared_ptr<RC_ITEM> rc_item = node->m_RcItem;
343 
344  if( rc_item->GetErrorCode() == DRCE_MALFORMED_COURTYARD )
345  {
346  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
347 
348  if( a && ( a->GetFlags() & MALFORMED_B_COURTYARD ) > 0
349  && ( a->GetFlags() & MALFORMED_F_COURTYARD ) == 0 )
350  {
351  principalLayer = B_CrtYd;
352  }
353  else
354  {
355  principalLayer = F_CrtYd;
356  }
357  }
358  else if (rc_item->GetErrorCode() == DRCE_INVALID_OUTLINE )
359  {
360  principalLayer = Edge_Cuts;
361  }
362  else
363  {
364  BOARD_ITEM* a = board->GetItem( rc_item->GetMainItemID() );
365  BOARD_ITEM* b = board->GetItem( rc_item->GetAuxItemID() );
366  BOARD_ITEM* c = board->GetItem( rc_item->GetAuxItem2ID() );
367  BOARD_ITEM* d = board->GetItem( rc_item->GetAuxItem3ID() );
368 
369  if( a || b || c || d )
370  violationLayers = LSET::AllLayersMask();
371 
372  if( a )
373  violationLayers &= getActiveLayers( a );
374 
375  if( b )
376  violationLayers &= getActiveLayers( b );
377 
378  if( c )
379  violationLayers &= getActiveLayers( c );
380 
381  if( d )
382  violationLayers &= getActiveLayers( d );
383  }
384 
385  if( violationLayers.count() )
386  principalLayer = violationLayers.Seq().front();
387  else
388  violationLayers.set( principalLayer );
389 
390  WINDOW_THAWER thawer( m_frame );
391 
392  m_frame->FocusOnItem( item );
393  m_frame->GetCanvas()->Refresh();
394 
395  if( ( violationLayers & board->GetVisibleLayers() ) == 0 )
396  {
397  m_frame->GetAppearancePanel()->SetLayerVisible( principalLayer, true );
398  m_frame->GetCanvas()->Refresh();
399  }
400 
401  if( board->GetVisibleLayers().test( principalLayer ) )
402  m_frame->SetActiveLayer( principalLayer );
403  }
404 
405  aEvent.Skip();
406 }
407 
408 
409 void DIALOG_DRC::OnDRCItemDClick( wxDataViewEvent& aEvent )
410 {
411  if( aEvent.GetItem().IsOk() )
412  {
413  // turn control over to m_frame, hide this DIALOG_DRC window,
414  // no destruction so we can preserve listbox cursor
415  if( !IsModal() )
416  Show( false );
417  }
418 
419  // Do not skip aVent here: this is not useful, and Pcbnew crashes
420  // if skipped (at least on Windows)
421 }
422 
423 
424 void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
425 {
426  RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
427 
428  if( !node )
429  return;
430 
431  std::shared_ptr<RC_ITEM> rcItem = node->m_RcItem;
432  wxString listName;
433  wxMenu menu;
434  wxString msg;
435 
436  switch( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] )
437  {
438  case RPT_SEVERITY_ERROR: listName = _( "errors" ); break;
439  case RPT_SEVERITY_WARNING: listName = _( "warnings" ); break;
440  default: listName = _( "appropriate" ); break;
441  }
442 
443  if( rcItem->GetParent()->IsExcluded() )
444  {
445  menu.Append( 1, _( "Remove exclusion for this violation" ),
446  wxString::Format( _( "It will be placed back in the %s list" ), listName ) );
447  }
448  else
449  {
450  menu.Append( 2, _( "Exclude this violation" ),
451  wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
452  }
453 
454  if( rcItem->GetErrorCode() == DRCE_CLEARANCE
455  || rcItem->GetErrorCode() == DRCE_COPPER_EDGE_CLEARANCE )
456  {
457  menu.Append( 3, _( "Run clearance resolution tool..." ) );
458  }
459 
460  menu.AppendSeparator();
461 
462  if( bds().m_DRCSeverities[ rcItem->GetErrorCode() ] == RPT_SEVERITY_WARNING )
463  {
464  msg.Printf( _( "Change severity to Error for all '%s' violations" ),
465  rcItem->GetErrorText(),
466  _( "Violation severities can also be edited in the Board Setup... dialog" ) );
467  menu.Append( 4, msg );
468  }
469  else
470  {
471  msg.Printf( _( "Change severity to Warning for all '%s' violations" ),
472  rcItem->GetErrorText(),
473  _( "Violation severities can also be edited in the Board Setup... dialog" ) );
474  menu.Append( 5, msg );
475  }
476 
477  msg.Printf( _( "Ignore all '%s' violations" ),
478  rcItem->GetErrorText(),
479  _( "Violations will not be checked or reported" ) );
480  menu.Append( 6, msg );
481 
482  menu.AppendSeparator();
483 
484  menu.Append( 7, _( "Edit violation severities..." ), _( "Open the Board Setup... dialog" ) );
485 
486  bool modified = false;
487 
488  switch( GetPopupMenuSelectionFromUser( menu ) )
489  {
490  case 1:
491  {
492  PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() );
493 
494  if( marker )
495  {
496  marker->SetExcluded( false );
497  m_frame->GetCanvas()->GetView()->Update( marker );
498 
499  // Update view
500  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
501  modified = true;
502  }
503 
504  break;
505  }
506 
507  case 2:
508  {
509  PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() );
510 
511  if( marker )
512  {
513  marker->SetExcluded( true );
514  m_frame->GetCanvas()->GetView()->Update( marker );
515 
516  // Update view
518  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
519  else
520  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false );
521 
522  modified = true;
523  }
524 
525  break;
526  }
527 
528  case 3:
529  {
530  TOOL_MANAGER* toolMgr = m_frame->GetToolManager();
531  BOARD_INSPECTION_TOOL* inspectionTool = toolMgr->GetTool<BOARD_INSPECTION_TOOL>();
532 
533  inspectionTool->InspectDRCError( node->m_RcItem );
534  break;
535  }
536 
537  case 4:
538  bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_ERROR;
539 
540  for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
541  {
542  if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
543  m_frame->GetCanvas()->GetView()->Update( marker );
544  }
545 
546  // Rebuild model and view
547  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markersProvider );
548  modified = true;
549  break;
550 
551  case 5:
552  bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_WARNING;
553 
554  for( PCB_MARKER* marker : m_frame->GetBoard()->Markers() )
555  {
556  if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
557  m_frame->GetCanvas()->GetView()->Update( marker );
558  }
559 
560  // Rebuild model and view
561  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markersProvider );
562  modified = true;
563  break;
564 
565  case 6:
566  {
567  bds().m_DRCSeverities[ rcItem->GetErrorCode() ] = RPT_SEVERITY_IGNORE;
568 
569  std::vector<PCB_MARKER*>& markers = m_frame->GetBoard()->Markers();
570 
571  for( unsigned i = 0; i < markers.size(); )
572  {
573  if( markers[i]->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
574  {
575  m_frame->GetCanvas()->GetView()->Remove( markers.at( i ) );
576  markers.erase( markers.begin() + i );
577  }
578  else
579  ++i;
580  }
581 
582  // Rebuild model and view
583  static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markersProvider );
584  modified = true;
585  break;
586  }
587 
588  case 7:
589  m_frame->ShowBoardSetupDialog( _( "Violation Severity" ) );
590  break;
591  }
592 
593  if( modified )
594  {
596  refreshEditor();
597  m_frame->OnModify();
598  }
599 }
600 
601 
602 void DIALOG_DRC::OnSeverity( wxCommandEvent& aEvent )
603 {
604  int flag = 0;
605 
606  if( aEvent.GetEventObject() == m_showAll )
608  else if( aEvent.GetEventObject() == m_showErrors )
610  else if( aEvent.GetEventObject() == m_showWarnings )
612  else if( aEvent.GetEventObject() == m_showExclusions )
614 
615  if( aEvent.IsChecked() )
616  m_severities |= flag;
617  else if( aEvent.GetEventObject() == m_showAll )
619  else
620  m_severities &= ~flag;
621 
622  syncCheckboxes();
623 
624  // Set the provider's severity levels through the TreeModel so that the old tree
625  // can be torn down before the severity changes.
626  //
627  // It's not clear this is required, but we've had a lot of issues with wxDataView
628  // being cranky on various platforms.
629 
633 
635 }
636 
637 
638 void DIALOG_DRC::OnSaveReport( wxCommandEvent& aEvent )
639 {
640  wxFileName fn( "./DRC." + ReportFileExtension );
641 
642  wxFileDialog dlg( this, _( "Save Report to File" ), fn.GetPath(), fn.GetFullName(),
643  ReportFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
644 
645  if( dlg.ShowModal() != wxID_OK )
646  return;
647 
648  fn = dlg.GetPath();
649 
650  if( fn.GetExt().IsEmpty() )
651  fn.SetExt( ReportFileExtension );
652 
653  if( !fn.IsAbsolute() )
654  {
655  wxString prj_path = Prj().GetProjectPath();
656  fn.MakeAbsolute( prj_path );
657  }
658 
659  if( writeReport( fn.GetFullPath() ) )
660  {
661  m_messages->Report( wxString::Format( _( "Report file '%s' created<br>" ),
662  fn.GetFullPath() ) );
663  }
664  else
665  {
666  DisplayError( this, wxString::Format( _( "Failed to create file '%s'." ),
667  fn.GetFullPath() ) );
668  }
669 }
670 
671 
672 void DIALOG_DRC::OnClose( wxCloseEvent& aEvent )
673 {
674  if( m_running )
675  aEvent.Veto();
676 
677  wxCommandEvent dummy;
678 
679  OnCancelClick( dummy );
680 }
681 
682 
683 void DIALOG_DRC::OnCancelClick( wxCommandEvent& aEvent )
684 {
685  if( m_running )
686  {
687  m_cancelled = true;
688  return;
689  }
690 
691  m_frame->FocusOnItem( nullptr );
692 
693  SetReturnCode( wxID_CANCEL );
694 
695  // The dialog can be modal or not modal.
696  // Leave the DRC caller destroy (or not) the dialog
697  DRC_TOOL* drcTool = m_frame->GetToolManager()->GetTool<DRC_TOOL>();
698  drcTool->DestroyDRCDialog();
699 }
700 
701 
702 void DIALOG_DRC::OnChangingNotebookPage( wxNotebookEvent& aEvent )
703 {
704  // Shouldn't be necessary, but is on at least OSX
705  if( aEvent.GetSelection() >= 0 )
706  m_Notebook->ChangeSelection( (unsigned) aEvent.GetSelection() );
707 
708  m_markerDataView->UnselectAll();
709  m_unconnectedDataView->UnselectAll();
710  m_footprintsDataView->UnselectAll();
711 }
712 
713 
715 {
716  WINDOW_THAWER thawer( m_frame );
717 
718  m_frame->GetCanvas()->Refresh();
719 }
720 
721 
723 {
724  if( m_Notebook->IsShown() )
725  {
726  switch( m_Notebook->GetSelection() )
727  {
728  case 0: m_markersTreeModel->PrevMarker(); break;
729  case 1: m_unconnectedTreeModel->PrevMarker(); break;
730  case 2: m_footprintWarningsTreeModel->PrevMarker(); break;
731  }
732  }
733 }
734 
735 
737 {
738  if( m_Notebook->IsShown() )
739  {
740  switch( m_Notebook->GetSelection() )
741  {
742  case 0: m_markersTreeModel->NextMarker(); break;
743  case 1: m_unconnectedTreeModel->NextMarker(); break;
744  case 2: m_footprintWarningsTreeModel->NextMarker(); break;
745  }
746  }
747 }
748 
749 
751 {
752  if( !m_Notebook->IsShown() || m_Notebook->GetSelection() != 0 )
753  return;
754 
755  RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( m_markerDataView->GetCurrentItem() );
756  PCB_MARKER* marker = dynamic_cast<PCB_MARKER*>( node->m_RcItem->GetParent() );
757 
758  if( marker && !marker->IsExcluded() )
759  {
760  marker->SetExcluded( true );
761  m_frame->GetCanvas()->GetView()->Update( marker );
762 
763  // Update view
766  else
768 
770  refreshEditor();
771  m_frame->OnModify();
772  }
773 }
774 
775 
776 void DIALOG_DRC::deleteAllMarkers( bool aIncludeExclusions )
777 {
778  // Clear current selection list to avoid selection of deleted items
780 
781  m_markersTreeModel->DeleteItems( false, aIncludeExclusions, true );
782 }
783 
784 
785 bool DIALOG_DRC::writeReport( const wxString& aFullFileName )
786 {
787  FILE* fp = wxFopen( aFullFileName, wxT( "w" ) );
788 
789  if( fp == nullptr )
790  return false;
791 
792  std::map<KIID, EDA_ITEM*> itemMap;
793  m_frame->GetBoard()->FillItemMap( itemMap );
794 
795  EDA_UNITS units = GetUserUnits();
797  int count;
798 
799  fprintf( fp, "** Drc report for %s **\n", TO_UTF8( m_frame->GetBoard()->GetFileName() ) );
800 
801  wxDateTime now = wxDateTime::Now();
802 
803  fprintf( fp, "** Created on %s **\n", TO_UTF8( now.Format( wxT( "%F %T" ) ) ) );
804 
805  count = m_markersProvider->GetCount();
806 
807  fprintf( fp, "\n** Found %d DRC violations **\n", count );
808 
809  for( int i = 0; i < count; ++i )
810  {
811  const std::shared_ptr<RC_ITEM>& item = m_markersProvider->GetItem( i );
812  SEVERITY severity = bds.GetSeverity( item->GetErrorCode() );
813 
814  fprintf( fp, "%s", TO_UTF8( item->ShowReport( units, severity, itemMap ) ) );
815  }
816 
818 
819  fprintf( fp, "\n** Found %d unconnected pads **\n", count );
820 
821  for( int i = 0; i < count; ++i )
822  {
823  const std::shared_ptr<RC_ITEM>& item = m_unconnectedItemsProvider->GetItem( i );
824  SEVERITY severity = bds.GetSeverity( item->GetErrorCode() );
825 
826  fprintf( fp, "%s", TO_UTF8( item->ShowReport( units, severity, itemMap ) ) );
827  }
828 
830 
831  fprintf( fp, "\n** Found %d Footprint errors **\n", count );
832 
833  for( int i = 0; i < count; ++i )
834  {
835  const std::shared_ptr<RC_ITEM>& item = m_footprintWarningsProvider->GetItem( i );
836  SEVERITY severity = bds.GetSeverity( item->GetErrorCode() );
837 
838  fprintf( fp, "%s", TO_UTF8( item->ShowReport( units, severity, itemMap ) ) );
839  }
840 
841 
842  fprintf( fp, "\n** End of Report **\n" );
843 
844  fclose( fp );
845 
846  return true;
847 }
848 
849 
850 void DIALOG_DRC::OnDeleteOneClick( wxCommandEvent& aEvent )
851 {
852  if( m_Notebook->GetSelection() == 0 )
853  {
854  // Clear the selection. It may be the selected DRC marker.
856 
858 
859  // redraw the pcb
860  refreshEditor();
861  }
862  else if( m_Notebook->GetSelection() == 1 )
863  {
865  }
866  else if( m_Notebook->GetSelection() == 2 )
867  {
869  }
870 
872 }
873 
874 
875 void DIALOG_DRC::OnDeleteAllClick( wxCommandEvent& aEvent )
876 {
877  static bool s_includeExclusions = false;
878 
879  int numExcluded = 0;
880 
881  if( m_markersProvider )
883 
886 
889 
890  if( numExcluded > 0 )
891  {
892  wxRichMessageDialog dlg( this, _( "Do you wish to delete excluded markers as well?" ),
893  _( "Delete All Markers" ),
894  wxOK | wxCANCEL | wxCENTER | wxICON_QUESTION );
895  dlg.ShowCheckBox( _( "Delete exclusions" ), s_includeExclusions );
896 
897  int ret = dlg.ShowModal();
898 
899  if( ret == wxID_CANCEL )
900  return;
901  else
902  s_includeExclusions = dlg.IsCheckBoxChecked();
903  }
904 
905  deleteAllMarkers( s_includeExclusions );
906 
907  m_drcRun = false;
908  refreshEditor();
910 }
911 
912 
914 {
915  // Collect counts:
916 
917  int numMarkers = 0;
918  int numUnconnected = 0;
919  int numFootprints = 0;
920 
921  int numErrors = 0;
922  int numWarnings = 0;
923  int numExcluded = 0;
924 
925  if( m_markersProvider )
926  {
927  numMarkers += m_markersProvider->GetCount();
931  }
932 
934  {
935  numUnconnected += m_unconnectedItemsProvider->GetCount();
939  }
940 
942  {
943  numFootprints += m_footprintWarningsProvider->GetCount();
947  }
948 
949  wxString msg;
950 
951  // Update tab headers:
952 
953  if( m_drcRun )
954  {
955  msg.sprintf( m_markersTitleTemplate, numMarkers );
956  m_Notebook->SetPageText( 0, msg );
957 
958  msg.sprintf( m_unconnectedTitleTemplate, numUnconnected );
959  m_Notebook->SetPageText( 1, msg );
960 
961  if( m_footprintTestsRun )
962  {
963  msg.sprintf( m_footprintsTitleTemplate, numFootprints );
964  }
965  else
966  {
968  msg.Replace( wxT( "%d" ), _( "not run" ) );
969  }
970  m_Notebook->SetPageText( 2, msg );
971  }
972  else
973  {
975  msg.Replace( wxT( "(%d)" ), wxEmptyString );
976  m_Notebook->SetPageText( 0, msg );
977 
979  msg.Replace( wxT( "(%d)" ), wxEmptyString );
980  m_Notebook->SetPageText( 1, msg );
981 
983  msg.Replace( wxT( "(%d)" ), wxEmptyString );
984  m_Notebook->SetPageText( 2, msg );
985  }
986 
987  // Update badges:
988 
989  if( !m_drcRun && numErrors == 0 )
990  numErrors = -1;
991 
992  if( !m_drcRun && numWarnings == 0 )
993  numWarnings = -1;
994 
995  m_errorsBadge->SetMaximumNumber( numErrors );
997 
998  m_warningsBadge->SetMaximumNumber( numWarnings );
1000 
1001  m_exclusionsBadge->SetMaximumNumber( numExcluded );
1003 }
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:867
void initValues()
Definition: dialog_drc.cpp:130
virtual void AdvancePhase()
Use the next available virtual zone of the dialog progress bar.
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:252
void DeleteItems(bool aCurrentOnly, bool aIncludeExclusions, bool aDeep)
Deletes the current item or all items.
Definition: rc_item.cpp:456
void syncCheckboxes()
Definition: dialog_drc.cpp:181
wxCheckBox * m_cbTestFootprints
void OnModify() override
Must be called after a board change to set the modified flag.
void NextMarker()
Definition: rc_item.cpp:566
wxNotebook * m_Notebook
void NextMarker()
Definition: dialog_drc.cpp:736
void updateDisplayedCounts()
Definition: dialog_drc.cpp:913
BOARD_DESIGN_SETTINGS & bds()
Definition: dialog_drc.h:105
static int RPT_SEVERITY_ALL
Definition: dialog_drc.cpp:178
KIID niluuid(0)
void OnDRCItemRClick(wxDataViewEvent &aEvent) override
Definition: dialog_drc.cpp:424
#define MALFORMED_B_COURTYARD
void SetProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: rc_item.cpp:289
void OnErrorLinkClicked(wxHtmlLinkEvent &event) override
Definition: dialog_drc.cpp:190
wxCheckBox * m_cbReportAllTrackErrors
void deleteAllMarkers(bool aIncludeExclusions)
Definition: dialog_drc.cpp:776
wxButton * m_DeleteCurrentMarkerButton
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
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:80
Class DIALOG_DRC_BASE.
SEVERITY
Definition: ui_common.h:100
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
A progress reporter for use in multi-threaded environments.
std::atomic_int m_progress
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:785
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:722
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:850
bool m_footprintTestsRun
Definition: dialog_drc.h:112
wxString m_footprintsTitleTemplate
Definition: dialog_drc.h:116
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:479
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:144
void ExcludeMarker()
Definition: dialog_drc.cpp:750
RC_ITEMS_PROVIDER * m_markersProvider
Definition: dialog_drc.h:118
void OnDRCItemDClick(wxDataViewEvent &aEvent) override
Definition: dialog_drc.cpp:409
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:107
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:588
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:450
void SetSeverities(int aSeverities)
Definition: rc_item.cpp:295
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:702
EDA_UNITS GetUserUnits() const
Definition: dialog_shim.h:119
RC_ITEMS_PROVIDER * m_unconnectedItemsProvider
Definition: dialog_drc.h:121
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:71
#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:114
virtual void SetCurrentProgress(double aProgress)
Set the progress value to aProgress (0..1).
void SetImmediateMode()
In immediate mode, messages are flushed as they are added.
PCB_LAYER_ID
A quick note on layer IDs:
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.
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:190
wxDataViewCtrl * m_footprintsDataView
RC_ITEMS_PROVIDER * m_footprintWarningsProvider
Definition: dialog_drc.h:124
wxBoxSizer * m_sizerButtons
wxButton * m_DeleteAllMarkersButton
wxButton * m_sdbSizerOK
void OnDeleteAllClick(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:875
static RC_TREE_NODE * ToNode(wxDataViewItem aItem)
Definition: rc_item.h:205
wxString ReportFileWildcard()
void OnDRCItemSelected(wxDataViewEvent &aEvent) override
Definition: dialog_drc.cpp:309
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
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
RC_TREE_MODEL * m_footprintWarningsTreeModel
Definition: dialog_drc.h:125
void SetFootprintsProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: dialog_drc.cpp:301
std::atomic< bool > m_cancelled
Definition: dialog_drc.h:110
Definition of file extensions used in Kicad.
NUMBER_BADGE * m_exclusionsBadge
#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:672
void PrevMarker()
Definition: rc_item.cpp:545
std::shared_ptr< DRC_ENGINE > GetDRCEngine()
Definition: drc_tool.h:89
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:196
bool Show(bool show) override
void RunTests(PROGRESS_REPORTER *aProgressReporter, bool aRefillZones, bool aReportAllTrackErrors, bool aTestFootprints)
Run the DRC tests.
Definition: drc_tool.cpp:131
RC_TREE_MODEL * m_unconnectedTreeModel
Definition: dialog_drc.h:122
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:155
wxDataViewCtrl * m_unconnectedDataView
void OnCancelClick(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:683
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:285
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:714
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:115
bool m_drcRun
Definition: dialog_drc.h:111
int m_severities
Definition: dialog_drc.h:127
void SetLayerVisible(LAYER_NUM aLayer, bool isVisible)
void ValueChanged(const RC_TREE_NODE *aNode)
Definition: rc_item.cpp:433
std::atomic_int m_maxProgress
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
RC_TREE_MODEL * m_markersTreeModel
Definition: dialog_drc.h:119
DIALOG_DRC m_DrcDialog
BOARD * GetBoard() const
void DestroyDRCDialog()
Close and free the DRC dialog.
Definition: drc_tool.cpp:121
Definition: pad.h:57
PCB_EDIT_FRAME * m_frame
Definition: dialog_drc.h:108
void OnSaveReport(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:638
void SetMaximumNumber(int aMax)
Set the maximum number to be shown on the badge.
bool m_running
Definition: dialog_drc.h:109
bool updateUI() override
Definition: dialog_drc.cpp:156
void SetActiveLayer(PCB_LAYER_ID aLayer) override
Change the currently active layer to aLayer and also update the APPEARANCE_CONTROLS.
void FocusOnItem(BOARD_ITEM *aItem)
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Definition: board.cpp:946
void SetUnconnectedProvider(RC_ITEMS_PROVIDER *aProvider)
Definition: dialog_drc.cpp:293
wxString m_unconnectedTitleTemplate
Definition: dialog_drc.h:115
void OnSeverity(wxCommandEvent &aEvent) override
Definition: dialog_drc.cpp:602
Container for design settings for a BOARD object.
Tool for pcb inspection.