KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_erc.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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 Wayne Stambaugh <[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
27#include <advanced_config.h>
28#include <gestfich.h>
29#include <sch_screen.h>
30#include <sch_edit_frame.h>
31#include <project.h>
32#include <kiface_base.h>
33#include <reporter.h>
35#include <sch_marker.h>
36#include <connection_graph.h>
37#include <tools/sch_actions.h>
39#include <dialog_erc.h>
40#include <erc/erc.h>
41#include <erc/erc_report.h>
42#include <id.h>
43#include <confirm.h>
47#include <string_utils.h>
48#include <kiplatform/ui.h>
49
50#include <wx/ffile.h>
51#include <wx/filedlg.h>
52#include <wx/hyperlink.h>
53#include <wx/msgdlg.h>
54#include <wx/wupdlock.h>
55
56
57wxDEFINE_EVENT( EDA_EVT_CLOSE_ERC_DIALOG, wxCommandEvent );
58
59
60// wxWidgets spends *far* too long calculating 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
65
66static SCHEMATIC* g_lastERCSchematic = nullptr;
67static bool g_lastERCRun = false;
68
69static std::vector<std::pair<wxString, int>> g_lastERCIgnored;
70
71
73 DIALOG_ERC_BASE( parent ),
75 m_parent( parent ),
76 m_markerTreeModel( nullptr ),
77 m_running( false ),
78 m_ercRun( false ),
79 m_centerMarkerOnIdle( nullptr ),
80 m_crossprobe( true ),
82{
83 m_currentSchematic = &parent->Schematic();
84
85 SetName( DIALOG_ERC_WINDOW_NAME ); // Set a window name to be able to find it
87
88 m_bMenu->SetBitmap( KiBitmapBundle( BITMAPS::config ) );
89
90 m_messages->SetImmediateMode();
91
92 m_markerProvider = std::make_shared<SHEETLIST_ERC_ITEMS_PROVIDER>( &m_parent->Schematic() );
93
95 m_markerDataView->AssociateModel( m_markerTreeModel );
97
98 m_ignoredList->InsertColumn( 0, wxEmptyString, wxLIST_FORMAT_LEFT, DEFAULT_SINGLE_COL_WIDTH );
99
101 {
103
104 for( const auto& [ str, code ] : g_lastERCIgnored )
105 {
106 wxListItem listItem;
107 listItem.SetId( m_ignoredList->GetItemCount() );
108 listItem.SetText( str );
109 listItem.SetData( code );
110
111 m_ignoredList->InsertItem( listItem );
112 }
113 }
114
115 m_notebook->SetSelection( 0 );
116
117 SetupStandardButtons( { { wxID_OK, _( "Run ERC" ) },
118 { wxID_CANCEL, _( "Close" ) } } );
119
120 m_violationsTitleTemplate = m_notebook->GetPageText( 0 );
121 m_ignoredTitleTemplate = m_notebook->GetPageText( 1 );
122
123 m_errorsBadge->SetMaximumNumber( 999 );
124 m_warningsBadge->SetMaximumNumber( 999 );
125 m_exclusionsBadge->SetMaximumNumber( 999 );
126
128
129 Layout();
130
131 SetFocus();
132
134 {
135 m_crossprobe = cfg->m_ERCDialog.crossprobe;
136 m_scroll_on_crossprobe = cfg->m_ERCDialog.scroll_on_crossprobe;
137 }
138
139 // Now all widgets have the size fixed, call FinishDialogSettings
141}
142
143
145{
148
149 g_lastERCIgnored.clear();
150
151 for( int ii = 0; ii < m_ignoredList->GetItemCount(); ++ii )
152 g_lastERCIgnored.push_back( { m_ignoredList->GetItemText( ii ), m_ignoredList->GetItemData( ii ) } );
153
155 {
156 cfg->m_ERCDialog.crossprobe = m_crossprobe;
157 cfg->m_ERCDialog.scroll_on_crossprobe = m_scroll_on_crossprobe;
158 }
159
160 m_markerTreeModel->DecRef();
161}
162
163
165{
166 if( m_parent->CheckAnnotate(
167 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
168 {
169 } ) )
170 {
171 if( !m_infoBar->IsShownOnScreen() )
172 {
173 wxHyperlinkCtrl* button = new wxHyperlinkCtrl( m_infoBar, wxID_ANY, _( "Show Annotation dialog" ),
174 wxEmptyString );
175
176 button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
177 [&]( wxHyperlinkEvent& aEvent )
178 {
179 wxHtmlLinkEvent htmlEvent( aEvent.GetId(), wxHtmlLinkInfo( aEvent.GetURL() ) );
180 OnLinkClicked( htmlEvent );
181 } ) );
182
183 m_infoBar->RemoveAllButtons();
184 m_infoBar->AddButton( button );
185 m_infoBar->ShowMessage( _( "Schematic is not fully annotated. ERC results will be incomplete." ) );
186 }
187 }
188 else
189 {
190 if( m_infoBar->IsShownOnScreen() )
191 {
192 m_infoBar->RemoveAllButtons();
193 m_infoBar->Hide();
194 }
195 }
196}
197
198
200{
201 int severities = 0;
202
203 if( m_showErrors->GetValue() )
204 severities |= RPT_SEVERITY_ERROR;
205
206 if( m_showWarnings->GetValue() )
207 severities |= RPT_SEVERITY_WARNING;
208
209 if( m_showExclusions->GetValue() )
210 severities |= RPT_SEVERITY_EXCLUSION;
211
212 return severities;
213}
214
215
216void DIALOG_ERC::OnMenu( wxCommandEvent& event )
217{
218 // Build a pop menu:
219 wxMenu menu;
220
221 menu.Append( 4206, _( "Cross-probe Selected Items" ),
222 _( "Highlight corresponding items on canvas when selected in the ERC list" ),
223 wxITEM_CHECK );
224 menu.Check( 4206, m_crossprobe );
225
226 menu.Append( 4207, _( "Center on Cross-probe" ),
227 _( "When cross-probing, scroll the canvas so that the item is visible" ),
228 wxITEM_CHECK );
229 menu.Check( 4207, m_scroll_on_crossprobe );
230
231 // menu_id is the selected submenu id from the popup menu or wxID_NONE
232 int menu_id = m_bMenu->GetPopupMenuSelectionFromUser( menu );
233
234 if( menu_id == 0 || menu_id == 4206 )
235 {
237 }
238 else if( menu_id == 1 || menu_id == 4207 )
239 {
241 }
242}
243
244
245void DIALOG_ERC::OnCharHook( wxKeyEvent& aEvt )
246{
247 if( int hotkey = aEvt.GetKeyCode() )
248 {
249 if( aEvt.ControlDown() )
250 hotkey |= MD_CTRL;
251 if( aEvt.ShiftDown() )
252 hotkey |= MD_SHIFT;
253 if( aEvt.AltDown() )
254 hotkey |= MD_ALT;
255
256 if( hotkey == ACTIONS::excludeMarker.GetHotKey() )
257 {
259 return;
260 }
261 }
262
264}
265
266
268{
269 UpdateData();
270 return true;
271}
272
273
275{
276 // If ERC checks ever get slow enough we'll want a progress indicator...
277 //
278 // double cur = (double) m_progress.load() / m_maxProgress;
279 // cur = std::max( 0.0, std::min( cur, 1.0 ) );
280 //
281 // m_gauge->SetValue( KiROUND( cur * 1000.0 ) );
282 // wxSafeYield( this );
283
284 return !m_cancelled;
285}
286
287
288void DIALOG_ERC::AdvancePhase( const wxString& aMessage )
289{
290 // Will also call Report( aMessage ):
292 SetCurrentProgress( 0.0 );
293}
294
295
296void DIALOG_ERC::Report( const wxString& aMessage )
297{
298 m_messages->Report( aMessage );
299}
300
301
307
308
310{
311 int numErrors = 0;
312 int numWarnings = 0;
313 int numExcluded = 0;
314
315 int numMarkers = 0;
316
317 if( m_markerProvider )
318 {
319 numMarkers += m_markerProvider->GetCount();
320 numErrors += m_markerProvider->GetCount( RPT_SEVERITY_ERROR );
321 numWarnings += m_markerProvider->GetCount( RPT_SEVERITY_WARNING );
322 numExcluded += m_markerProvider->GetCount( RPT_SEVERITY_EXCLUSION );
323 }
324
325 bool markersOverflowed = false;
326
327 // We don't currently have a limit on ERC violations, so the above is always false.
328
329 wxString num;
330 wxString msg;
331
332 if( m_ercRun )
333 {
334 num.Printf( markersOverflowed ? wxT( "%d+" ) : wxT( "%d" ), numMarkers );
335 msg.Printf( m_violationsTitleTemplate, num );
336 }
337 else
338 {
340 msg.Replace( wxT( "(%s)" ), wxEmptyString );
341 }
342
343 m_notebook->SetPageText( 0, msg );
344
345 if( m_ercRun )
346 {
347 num.Printf( wxT( "%d" ), m_ignoredList->GetItemCount() );
348 msg.sprintf( m_ignoredTitleTemplate, num );
349 }
350 else
351 {
353 msg.Replace( wxT( "(%s)" ), wxEmptyString );
354 }
355
356 m_notebook->SetPageText( 1, msg );
357
358 if( !m_ercRun && numErrors == 0 )
359 numErrors = -1;
360
361 if( !m_ercRun && numWarnings == 0 )
362 numWarnings = -1;
363
364 m_errorsBadge->UpdateNumber( numErrors, RPT_SEVERITY_ERROR );
365 m_warningsBadge->UpdateNumber( numWarnings, RPT_SEVERITY_WARNING );
366 m_exclusionsBadge->UpdateNumber( numExcluded, RPT_SEVERITY_EXCLUSION );
367}
368
369
370void DIALOG_ERC::OnDeleteOneClick( wxCommandEvent& aEvent )
371{
372 if( m_notebook->GetSelection() == 0 )
373 {
374 // Clear the selection. It may be the selected ERC marker.
375 m_parent->GetToolManager()->RunAction( ACTIONS::selectionClear );
376
377 m_markerTreeModel->DeleteCurrentItem( true );
378
379 // redraw the schematic
381 }
382
384}
385
386
387void DIALOG_ERC::OnDeleteAllClick( wxCommandEvent& event )
388{
389 bool includeExclusions = false;
390 int numExcluded = 0;
391
392 if( m_markerProvider )
393 numExcluded += m_markerProvider->GetCount( RPT_SEVERITY_EXCLUSION );
394
395 if( numExcluded > 0 )
396 {
397 wxMessageDialog dlg( this, _( "Delete exclusions too?" ), _( "Delete All Markers" ),
398 wxYES_NO | wxCANCEL | wxCENTER | wxICON_QUESTION );
399 dlg.SetYesNoLabels( _( "Errors and Warnings Only" ),
400 _( "Errors, Warnings and Exclusions" ) );
401
402 int ret = dlg.ShowModal();
403
404 if( ret == wxID_CANCEL )
405 return;
406 else if( ret == wxID_NO )
407 includeExclusions = true;
408 }
409
410 deleteAllMarkers( includeExclusions );
411 m_ercRun = false;
412
413 // redraw the schematic
416}
417
418
419void DIALOG_ERC::OnCancelClick( wxCommandEvent& aEvent )
420{
421 if( m_running )
422 {
423 m_cancelled = true;
424 return;
425 }
426
427 m_parent->ClearFocus();
428
429 aEvent.Skip();
430}
431
432
433void DIALOG_ERC::OnCloseErcDialog( wxCloseEvent& aEvent )
434{
435 m_parent->ClearFocus();
436
437 // Dialog is mode-less so let the parent know that it needs to be destroyed.
438 if( !IsModal() && !IsQuasiModal() )
439 {
440 if( wxWindow* parent = GetParent() )
441 wxQueueEvent( parent, new wxCommandEvent( EDA_EVT_CLOSE_ERC_DIALOG, wxID_ANY ) );
442 }
443
444 aEvent.Skip();
445}
446
447
448void DIALOG_ERC::OnLinkClicked( wxHtmlLinkEvent& event )
449{
450 m_parent->OnAnnotate();
451}
452
453
454void DIALOG_ERC::OnRunERCClick( wxCommandEvent& event )
455{
456 wxBusyCursor busy;
457
458 SCHEMATIC* sch = &m_parent->Schematic();
459
461
462 sch->RecordERCExclusions();
463 deleteAllMarkers( true );
464
465 std::vector<std::reference_wrapper<RC_ITEM>> violations = ERC_ITEM::GetItemsWithSeverities();
466 m_ignoredList->DeleteAllItems();
467
468 for( std::reference_wrapper<RC_ITEM>& item : violations )
469 {
470 if( sch->ErcSettings().GetSeverity( item.get().GetErrorCode() ) == RPT_SEVERITY_IGNORE )
471 {
472 wxListItem listItem;
473 listItem.SetId( m_ignoredList->GetItemCount() );
474 listItem.SetText( wxT( " • " ) + item.get().GetErrorText() );
475 listItem.SetData( item.get().GetErrorCode() );
476
477 m_ignoredList->InsertItem( listItem );
478 }
479 }
480
481 m_ignoredList->SetColumnWidth( 0, m_ignoredList->GetParent()->GetClientSize().x - 20 );
482
483 m_cancelled = false;
484 Raise();
485
486 m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
487 m_messages->Clear();
488 wxSafeYield(); // Allow time slice to refresh Messages
489
490 m_running = true;
491 m_sdbSizer1Cancel->SetLabel( _( "Cancel" ) );
492 m_sdbSizer1OK->Enable( false );
493 m_deleteOneMarker->Enable( false );
494 m_deleteAllMarkers->Enable( false );
495 m_saveReport->Enable( false );
496
497 int itemsNotAnnotated = m_parent->CheckAnnotate(
498 []( ERCE_T aType, const wxString& aMsg, SCH_REFERENCE* aItemA, SCH_REFERENCE* aItemB )
499 {
500 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( aType );
501 ercItem->SetErrorMessage( aMsg );
502
503 if( aItemB )
504 ercItem->SetItems( aItemA->GetSymbol(), aItemB->GetSymbol() );
505 else
506 ercItem->SetItems( aItemA->GetSymbol() );
507
508 SCH_MARKER* marker = new SCH_MARKER( std::move( ercItem ), aItemA->GetSymbol()->GetPosition() );
509 aItemA->GetSheetPath().LastScreen()->Append( marker );
510 } );
511
512 testErc();
513
514 if( itemsNotAnnotated )
515 {
516 m_messages->ReportHead( wxString::Format( _( "%d symbol(s) require annotation.<br><br>" ),
517 itemsNotAnnotated ),
519 }
520
521 if( m_cancelled )
522 m_messages->Report( _( "-------- ERC cancelled by user.<br><br>" ), RPT_SEVERITY_INFO );
523 else
524 m_messages->Report( _( "Done.<br><br>" ), RPT_SEVERITY_INFO );
525
526 Raise();
527 wxSafeYield(); // Allow time slice to refresh Messages
528
529 m_running = false;
530 m_sdbSizer1Cancel->SetLabel( _( "Close" ) );
531 m_sdbSizer1OK->Enable( true );
532 m_deleteOneMarker->Enable( true );
533 m_deleteAllMarkers->Enable( true );
534 m_saveReport->Enable( true );
535
536 if( !m_cancelled )
537 {
538 m_sdbSizer1Cancel->SetDefault();
539
540 // wxWidgets has a tendency to keep both buttons highlighted without the following:
541 m_sdbSizer1OK->Enable( false );
542
543 wxMilliSleep( 500 );
544 m_runningResultsBook->ChangeSelection( 1 );
546
547 // now re-enable m_sdbSizerOK button
548 m_sdbSizer1OK->Enable( true );
549 }
550
551 m_ercRun = true;
554 // set float level again, it can be lost due to window events during test run
556}
557
558
560{
561 WINDOW_THAWER thawer( m_parent );
562
563 m_parent->GetCanvas()->Refresh();
564}
565
566
568{
569 wxFileName fn;
570
571 SCHEMATIC* sch = &m_parent->Schematic();
572
573 SCH_SCREENS screens( sch->Root() );
574 ERC_TESTER tester( sch );
575
576 {
577 wxBusyCursor dummy;
578 tester.RunTests( m_parent->GetCanvas()->GetView()->GetDrawingSheet(), m_parent,
579 m_parent->Kiway().KiFACE( KIWAY::FACE_CVPCB ), &m_parent->Prj(), this );
580 }
581
582 // Update marker list:
584
585 // Display new markers from the current screen:
586 for( SCH_ITEM* marker : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
587 {
588 m_parent->GetCanvas()->GetView()->Remove( marker );
589 m_parent->GetCanvas()->GetView()->Add( marker );
590 }
591
592 m_parent->GetCanvas()->Refresh();
593}
594
595
596void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent )
597{
598 if( !m_crossprobe )
599 {
600 aEvent.Skip();
601 return;
602 }
603
604 const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() );
605 SCH_SHEET_PATH sheet;
606 SCH_ITEM* item = m_parent->Schematic().ResolveItem( itemID, &sheet, true );
607
609 {
610 // we already came from a cross-probe of the marker in the document; don't go
611 // around in circles
612 }
613 else if( item && item->GetClass() != wxT( "DELETED_SHEET_ITEM" ) )
614 {
615 const RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
616
617 if( node )
618 {
619 // Determine the owning sheet for sheet-specific items
620 std::shared_ptr<ERC_ITEM> ercItem = std::static_pointer_cast<ERC_ITEM>( node->m_RcItem );
621
622 switch( node->m_Type )
623 {
625 if( ercItem->IsSheetSpecific() )
626 sheet = ercItem->GetSpecificSheetPath();
627 break;
629 if( ercItem->MainItemHasSheetPath() )
630 sheet = ercItem->GetMainItemSheetPath();
631 break;
633 if( ercItem->AuxItemHasSheetPath() )
634 sheet = ercItem->GetAuxItemSheetPath();
635 break;
636 default:
637 break;
638 }
639 }
640
641 WINDOW_THAWER thawer( m_parent );
642
643 if( !sheet.empty() && sheet != m_parent->GetCurrentSheet() )
644 {
645 m_parent->GetToolManager()->RunAction<SCH_SHEET_PATH*>( SCH_ACTIONS::changeSheet, &sheet );
646 m_parent->RedrawScreen( m_parent->GetScreen()->m_ScrollCenter, false );
647 }
648
649 m_parent->FocusOnItem( item, m_scroll_on_crossprobe );
651 }
652
653 aEvent.Skip();
654}
655
656
657void DIALOG_ERC::OnERCItemDClick( wxDataViewEvent& aEvent )
658{
659 if( aEvent.GetItem().IsOk() )
660 {
661 // turn control over to m_parent, hide this DIALOG_ERC window,
662 // no destruction so we can preserve listbox cursor
663 if( !IsModal() )
664 Show( false );
665 }
666
667 aEvent.Skip();
668}
669
670
671void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
672{
673 TOOL_MANAGER* toolMgr = m_parent->GetToolManager();
674 SCH_INSPECTION_TOOL* inspectionTool = toolMgr->GetTool<SCH_INSPECTION_TOOL>();
675 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
676
677 if( !node )
678 return;
679
680 ERC_SETTINGS& settings = m_parent->Schematic().ErcSettings();
681
682 std::shared_ptr<RC_ITEM> rcItem = node->m_RcItem;
683 wxString listName;
684 wxMenu menu;
685
686 switch( settings.GetSeverity( rcItem->GetErrorCode() ) )
687 {
688 case RPT_SEVERITY_ERROR: listName = _( "errors" ); break;
689 case RPT_SEVERITY_WARNING: listName = _( "warnings" ); break;
690 default: listName = _( "appropriate" ); break;
691 }
692
693 enum MENU_IDS
694 {
695 ID_EDIT_EXCLUSION_COMMENT = 4467,
696 ID_REMOVE_EXCLUSION,
697 ID_REMOVE_EXCLUSION_ALL,
698 ID_ADD_EXCLUSION,
699 ID_ADD_EXCLUSION_WITH_COMMENT,
700 ID_ADD_EXCLUSION_ALL,
701 ID_INSPECT_VIOLATION,
702 ID_EDIT_PIN_CONFLICT_MAP,
703 ID_EDIT_CONNECTION_GRID,
704 ID_SET_SEVERITY_TO_ERROR,
705 ID_SET_SEVERITY_TO_WARNING,
706 ID_SET_SEVERITY_TO_IGNORE,
707 ID_EDIT_SEVERITIES,
708 };
709
710 if( rcItem->GetParent()->IsExcluded() )
711 {
712 menu.Append( ID_REMOVE_EXCLUSION,
713 _( "Remove exclusion for this violation" ),
714 wxString::Format( _( "It will be placed back in the %s list" ), listName ) );
715
716 menu.Append( ID_EDIT_EXCLUSION_COMMENT,
717 _( "Edit exclusion comment..." ) );
718 }
719 else
720 {
721 menu.Append( ID_ADD_EXCLUSION,
722 _( "Exclude this violation" ),
723 wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
724
725 menu.Append( ID_ADD_EXCLUSION_WITH_COMMENT,
726 _( "Exclude with comment..." ),
727 wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
728 }
729
730 wxString inspectERCErrorMenuText = inspectionTool->InspectERCErrorMenuText( rcItem );
731
732 if( !inspectERCErrorMenuText.IsEmpty() )
733 menu.Append( ID_INSPECT_VIOLATION, inspectERCErrorMenuText );
734
735 menu.AppendSeparator();
736
737 if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_WARNING
738 || rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
739 {
740 // Pin to pin severities edited through pin conflict map
741 }
742 else if( settings.GetSeverity( rcItem->GetErrorCode() ) == RPT_SEVERITY_WARNING )
743 {
744 menu.Append( ID_SET_SEVERITY_TO_ERROR,
745 wxString::Format( _( "Change severity to Error for all '%s' violations" ),
746 rcItem->GetErrorText() ),
747 _( "Violation severities can also be edited in the Schematic Setup... dialog" ) );
748 }
749 else
750 {
751 menu.Append( ID_SET_SEVERITY_TO_WARNING,
752 wxString::Format( _( "Change severity to Warning for all '%s' violations" ),
753 rcItem->GetErrorText() ),
754 _( "Violation severities can also be edited in the Schematic Setup... "
755 "dialog" ) );
756 }
757
758 menu.Append( ID_SET_SEVERITY_TO_IGNORE,
759 wxString::Format( _( "Ignore all '%s' violations" ), rcItem->GetErrorText() ),
760 _( "Violations will not be checked or reported" ) );
761
762 menu.AppendSeparator();
763
764 if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_WARNING
765 || rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
766 {
767 menu.Append( ID_EDIT_PIN_CONFLICT_MAP,
768 _( "Edit pin-to-pin conflict map..." ),
769 _( "Open the Schematic Setup... dialog" ) );
770 }
771 else
772 {
773 menu.Append( ID_EDIT_SEVERITIES,
774 _( "Edit violation severities..." ),
775 _( "Open the Schematic Setup... dialog" ) );
776 }
777
778 if( rcItem->GetErrorCode() == ERCE_ENDPOINT_OFF_GRID )
779 {
780 menu.Append( ID_EDIT_CONNECTION_GRID,
781 _( "Edit connection grid spacing..." ),
782 _( "Open the Schematic Setup... dialog" ) );
783 }
784
785 bool modified = false;
786 int command = GetPopupMenuSelectionFromUser( menu );
787
788 switch( command )
789 {
790 case ID_EDIT_EXCLUSION_COMMENT:
791 if( SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() ) )
792 {
793 WX_TEXT_ENTRY_DIALOG dlg( this, wxEmptyString, _( "Exclusion Comment" ),
794 marker->GetComment(), true );
795
796 if( dlg.ShowModal() == wxID_CANCEL )
797 break;
798
799 marker->SetExcluded( true, dlg.GetValue() );
800
801 // Update view
802 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
803 modified = true;
804 }
805
806 break;
807
808 case ID_REMOVE_EXCLUSION:
809 if( SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() ) )
810 {
811 marker->SetExcluded( false );
812 m_parent->GetCanvas()->GetView()->Update( marker );
813
814 // Update view
815 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
816 modified = true;
817 }
818
819 break;
820
821 case ID_ADD_EXCLUSION:
822 case ID_ADD_EXCLUSION_WITH_COMMENT:
823 if( SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() ) )
824 {
825 wxString comment;
826
827 if( command == ID_ADD_EXCLUSION_WITH_COMMENT )
828 {
829 WX_TEXT_ENTRY_DIALOG dlg( this, wxEmptyString, _( "Exclusion Comment" ),
830 wxEmptyString, true );
831
832 if( dlg.ShowModal() == wxID_CANCEL )
833 break;
834
835 comment = dlg.GetValue();
836 }
837
838 marker->SetExcluded( true, comment );
839
840 m_parent->GetCanvas()->GetView()->Update( marker );
841
842 // Update view
844 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
845 else
846 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false );
847
848 modified = true;
849 }
850
851 break;
852
853 case ID_INSPECT_VIOLATION:
854 inspectionTool->InspectERCError( node->m_RcItem );
855 break;
856
857 case ID_SET_SEVERITY_TO_ERROR:
858 settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_ERROR );
859
860 for( SCH_ITEM* item : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
861 {
862 SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
863
864 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
865 m_parent->GetCanvas()->GetView()->Update( marker );
866 }
867
868 // Rebuild model and view
869 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
870 modified = true;
871 break;
872
873 case ID_SET_SEVERITY_TO_WARNING:
874 settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_WARNING );
875
876 for( SCH_ITEM* item : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
877 {
878 SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
879
880 if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
881 m_parent->GetCanvas()->GetView()->Update( marker );
882 }
883
884 // Rebuild model and view
885 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
886 modified = true;
887 break;
888
889 case ID_SET_SEVERITY_TO_IGNORE:
890 {
891 settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_IGNORE );
892
893 if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
895
896 wxListItem listItem;
897 listItem.SetId( m_ignoredList->GetItemCount() );
898 listItem.SetText( wxT( " • " ) + rcItem->GetErrorText() );
899 listItem.SetData( rcItem->GetErrorCode() );
900
901 m_ignoredList->InsertItem( listItem );
902
903 // Clear the selection before deleting markers. It may be some selected ERC markers.
904 // Deleting a selected marker without deselecting it first generates a crash
905 m_parent->GetToolManager()->RunAction( ACTIONS::selectionClear );
906
907 SCH_SCREENS ScreenList( m_parent->Schematic().Root() );
908 ScreenList.DeleteMarkers( MARKER_BASE::MARKER_ERC, rcItem->GetErrorCode() );
909
910 // Rebuild model and view
911 static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
912 modified = true;
913 }
914 break;
915
916 case ID_EDIT_PIN_CONFLICT_MAP:
917 m_parent->ShowSchematicSetupDialog( _( "Pin Conflicts Map" ) );
918 break;
919
920 case ID_EDIT_SEVERITIES:
921 m_parent->ShowSchematicSetupDialog( _( "Violation Severity" ) );
922 break;
923
924 case ID_EDIT_CONNECTION_GRID:
925 m_parent->ShowSchematicSetupDialog( _( "Formatting" ) );
926 break;
927 }
928
929 if( modified )
930 {
933 m_parent->OnModify();
934 }
935}
936
937
938void DIALOG_ERC::OnIgnoredItemRClick( wxListEvent& event )
939{
940 ERC_SETTINGS& settings = m_parent->Schematic().ErcSettings();
941 int errorCode = (int) event.m_item.GetData();
942 wxMenu menu;
943
944 menu.Append( RPT_SEVERITY_ERROR, _( "Error" ), wxEmptyString, wxITEM_CHECK );
945 menu.Append( RPT_SEVERITY_WARNING, _( "Warning" ), wxEmptyString, wxITEM_CHECK );
946 menu.Append( RPT_SEVERITY_IGNORE, _( "Ignore" ), wxEmptyString, wxITEM_CHECK );
947
948 menu.Check( settings.GetSeverity( errorCode ), true );
949
950 int severity = GetPopupMenuSelectionFromUser( menu );
951
952 if( severity > 0 )
953 {
954 if( settings.GetSeverity( errorCode ) != severity )
955 {
956 settings.SetSeverity( errorCode, (SEVERITY) severity );
957
960 m_parent->OnModify();
961 }
962 }
963}
964
965
967{
968 if( m_notebook->IsShown() )
969 {
970 if( m_notebook->GetSelection() != 0 )
971 m_notebook->SetSelection( 0 );
972
973 m_markerTreeModel->PrevMarker();
974 }
975}
976
977
979{
980 if( m_notebook->IsShown() )
981 {
982 if( m_notebook->GetSelection() != 0 )
983 m_notebook->SetSelection( 0 );
984
985 m_markerTreeModel->NextMarker();
986 }
987}
988
989
991{
992 if( m_notebook->IsShown() )
993 {
994 m_notebook->SetSelection( 0 );
995 m_markerTreeModel->SelectMarker( aMarker );
996
997 // wxWidgets on some platforms fails to correctly ensure that a selected item is
998 // visible, so we have to do it in a separate idle event.
999 m_centerMarkerOnIdle = aMarker;
1000 Bind( wxEVT_IDLE, &DIALOG_ERC::centerMarkerIdleHandler, this );
1001 }
1002}
1003
1004
1005void DIALOG_ERC::centerMarkerIdleHandler( wxIdleEvent& aEvent )
1006{
1007 if( m_markerTreeModel->GetView()->IsFrozen() )
1008 return;
1009
1010 m_markerTreeModel->CenterMarker( m_centerMarkerOnIdle );
1011 m_centerMarkerOnIdle = nullptr;
1012 Unbind( wxEVT_IDLE, &DIALOG_ERC::centerMarkerIdleHandler, this );
1013}
1014
1015
1017{
1018 SCH_MARKER* marker = aMarker;
1019
1020 if( marker != nullptr )
1021 m_markerTreeModel->SelectMarker( marker );
1022
1023 if( m_notebook->GetSelection() != 0 )
1024 return;
1025
1026 RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( m_markerDataView->GetCurrentItem() );
1027
1028 if( node && node->m_RcItem )
1029 marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() );
1030
1031 if( node && marker && !marker->IsExcluded() )
1032 {
1033 marker->SetExcluded( true );
1034 m_parent->GetCanvas()->GetView()->Update( marker );
1035
1036 // Update view
1038 m_markerTreeModel->ValueChanged( node );
1039 else
1040 m_markerTreeModel->DeleteCurrentItem( false );
1041
1044 m_parent->OnModify();
1045 }
1046}
1047
1048
1049void DIALOG_ERC::OnEditViolationSeverities( wxHyperlinkEvent& aEvent )
1050{
1051 m_parent->ShowSchematicSetupDialog( _( "Violation Severity" ) );
1052}
1053
1054
1055void DIALOG_ERC::OnSeverity( wxCommandEvent& aEvent )
1056{
1057 if( aEvent.GetEventObject() == m_showAll )
1058 {
1059 m_showErrors->SetValue( true );
1060 m_showWarnings->SetValue( aEvent.IsChecked() );
1061 m_showExclusions->SetValue( aEvent.IsChecked() );
1062 }
1063
1064 UpdateData();
1065}
1066
1067
1068void DIALOG_ERC::deleteAllMarkers( bool aIncludeExclusions )
1069{
1070 // Clear current selection list to avoid selection of deleted items
1071 // Freeze to avoid repainting the dialog, which can cause a RePaint()
1072 // of the screen as well
1073 wxWindowUpdateLocker updateLock( this );
1074
1075 m_parent->GetToolManager()->RunAction( ACTIONS::selectionClear );
1076
1077 m_markerTreeModel->DeleteItems( false, aIncludeExclusions, false );
1078
1079 SCH_SCREENS screens( m_parent->Schematic().Root() );
1080 screens.DeleteAllMarkers( MARKER_BASE::MARKER_ERC, aIncludeExclusions );
1081}
1082
1083
1084void DIALOG_ERC::OnSaveReport( wxCommandEvent& aEvent )
1085{
1086 wxFileName fn( wxS( "ERC." ) + wxString( FILEEXT::ReportFileExtension ) );
1087
1088 wxFileDialog dlg( this, _( "Save Report File" ), Prj().GetProjectPath(), fn.GetFullName(),
1090 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1091
1092 if( dlg.ShowModal() != wxID_OK )
1093 return;
1094
1095 fn = dlg.GetPath();
1096
1097 if( fn.GetExt().IsEmpty() )
1098 fn.SetExt( FILEEXT::ReportFileExtension );
1099
1100 if( !fn.IsAbsolute() )
1101 {
1102 wxString prj_path = Prj().GetProjectPath();
1103 fn.MakeAbsolute( prj_path );
1104 }
1105
1106 ERC_REPORT reportWriter( &m_parent->Schematic(), m_parent->GetUserUnits() );
1107
1108 bool success = false;
1109 if( fn.GetExt() == FILEEXT::JsonFileExtension )
1110 success = reportWriter.WriteJsonReport( fn.GetFullPath() );
1111 else
1112 success = reportWriter.WriteTextReport( fn.GetFullPath() );
1113
1114 if( success )
1115 {
1116 m_messages->Report( wxString::Format( _( "Report file '%s' created." ),
1117 fn.GetFullPath() ) );
1118 }
1119 else
1120 {
1121 DisplayErrorMessage( this, wxString::Format( _( "Failed to create file '%s'." ),
1122 fn.GetFullPath() ) );
1123 }
1124}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
static TOOL_ACTION excludeMarker
Definition actions.h:128
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:223
wxButton * m_saveReport
wxButton * m_sdbSizer1Cancel
wxSimplebook * m_runningResultsBook
wxCheckBox * m_showExclusions
NUMBER_BADGE * m_errorsBadge
WX_INFOBAR * m_infoBar
STD_BITMAP_BUTTON * m_bMenu
wxCheckBox * m_showErrors
wxNotebook * m_notebook
wxCheckBox * m_showAll
NUMBER_BADGE * m_exclusionsBadge
wxListCtrl * m_ignoredList
WX_HTML_REPORT_BOX * m_messages
wxDataViewCtrl * m_markerDataView
wxButton * m_deleteAllMarkers
NUMBER_BADGE * m_warningsBadge
wxButton * m_deleteOneMarker
wxCheckBox * m_showWarnings
wxButton * m_sdbSizer1OK
DIALOG_ERC_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Electrical Rules Checker"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
void OnMenu(wxCommandEvent &aEvent) override
void ExcludeMarker(SCH_MARKER *aMarker=nullptr)
Exclude aMarker from the ERC list.
void OnIgnoredItemRClick(wxListEvent &aEvent) override
const SCH_MARKER * m_centerMarkerOnIdle
Definition dialog_erc.h:119
void OnERCItemDClick(wxDataViewEvent &aEvent) override
std::shared_ptr< RC_ITEMS_PROVIDER > m_markerProvider
Definition dialog_erc.h:113
bool TransferDataToWindow() override
bool m_ercRun
Definition dialog_erc.h:117
bool m_crossprobe
Definition dialog_erc.h:121
DIALOG_ERC(SCH_EDIT_FRAME *parent)
bool m_scroll_on_crossprobe
Definition dialog_erc.h:122
void testErc()
void SelectMarker(const SCH_MARKER *aMarker)
bool updateUI() override
SCH_EDIT_FRAME * m_parent
Definition dialog_erc.h:107
wxString m_violationsTitleTemplate
Definition dialog_erc.h:110
void OnERCItemRClick(wxDataViewEvent &aEvent) override
void centerMarkerIdleHandler(wxIdleEvent &aEvent)
void OnDeleteAllClick(wxCommandEvent &event) override
void OnLinkClicked(wxHtmlLinkEvent &event) override
void OnCharHook(wxKeyEvent &aEvt) override
void OnRunERCClick(wxCommandEvent &event) override
void deleteAllMarkers(bool aIncludeExclusions)
wxString m_ignoredTitleTemplate
Definition dialog_erc.h:111
void OnDeleteOneClick(wxCommandEvent &event) override
void UpdateData()
void OnSaveReport(wxCommandEvent &aEvent) override
int getSeverities()
void PrevMarker()
void NextMarker()
SCHEMATIC * m_currentSchematic
Definition dialog_erc.h:108
void OnEditViolationSeverities(wxHyperlinkEvent &aEvent) override
void UpdateAnnotationWarning()
void redrawDrawPanel()
void Report(const wxString &aMessage) override
Display aMessage in the progress bar dialog.
void OnERCItemSelected(wxDataViewEvent &aEvent) override
RC_TREE_MODEL * m_markerTreeModel
Definition dialog_erc.h:114
void updateDisplayedCounts()
void OnSeverity(wxCommandEvent &aEvent) override
bool m_running
Definition dialog_erc.h:116
void OnCloseErcDialog(wxCloseEvent &event) override
void OnCancelClick(wxCommandEvent &event) override
bool Show(bool show) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
bool IsQuasiModal() const
Definition dialog_shim.h:93
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)
int ShowModal() override
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition erc_item.cpp:307
static std::vector< std::reference_wrapper< RC_ITEM > > GetItemsWithSeverities()
Definition erc_item.h:76
bool WriteJsonReport(const wxString &aFullFileName)
Writes a JSON formatted ERC Report to the given file path in the c-locale.
bool WriteTextReport(const wxString &aFullFileName)
Writes the text report also available via GetTextReport directly to a given file path.
Container for ERC settings.
SEVERITY GetSeverity(int aErrorCode) const
void SetSeverity(int aErrorCode, SEVERITY aSeverity)
void RunTests(DS_PROXY_VIEW_ITEM *aDrawingSheet, SCH_EDIT_FRAME *aEditFrame, KIFACE *aCvPcb, PROJECT *aProject, PROGRESS_REPORTER *aProgressReporter)
Definition erc.cpp:1927
A specialisation of the RC_TREE_MODEL class to enable ERC errors / warnings to be resolved in a speci...
Definition erc_item.h:38
Definition kiid.h:49
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
@ FACE_CVPCB
Definition kiway.h:295
bool IsExcluded() const
Definition marker_base.h:93
std::shared_ptr< RC_ITEM > GetRCItem() const
void SetExcluded(bool aExcluded, const wxString &aComment=wxEmptyString)
Definition marker_base.h:94
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
int GetErrorCode() const
Definition rc_item.h:154
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
Holds all the data relating to one schematic.
Definition schematic.h:88
void RecordERCExclusions()
Scan existing markers and record data from any that are Excluded.
SCH_SHEET & Root() const
Definition schematic.h:140
ERC_SETTINGS & ErcSettings() const
static TOOL_ACTION changeSheet
Schematic editor (Eeschema) main window.
SCHEMATIC & Schematic() const
void InspectERCError(const std::shared_ptr< RC_ITEM > &aERCItem)
wxString InspectERCErrorMenuText(const std::shared_ptr< RC_ITEM > &aERCItem)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
wxString GetClass() const override
Return the class name.
Definition sch_item.h:177
A helper to define a symbol's reference designator in a schematic.
const SCH_SHEET_PATH & GetSheetPath() const
SCH_SYMBOL * GetSymbol() const
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:758
void DeleteMarkers(enum MARKER_BASE::MARKER_T aMarkerTyp, int aErrorCode, bool aIncludeExclusions=true)
Delete all markers of a particular type and error code.
void DeleteAllMarkers(enum MARKER_BASE::MARKER_T aMarkerType, bool aIncludeExclusions)
Delete all electronic rules check markers of aMarkerType from all the screens in the list.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool empty() const
Forwarded method from std::vector.
SCH_SCREEN * LastScreen()
VECTOR2I GetPosition() const override
Definition sch_symbol.h:760
Master controller class:
A KICAD version of wxTextEntryDialog which supports the various improvements/work-arounds from DIALOG...
wxString GetValue() const
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:194
This file is part of the common library.
static bool g_lastERCRun
wxDEFINE_EVENT(EDA_EVT_CLOSE_ERC_DIALOG, wxCommandEvent)
static std::vector< std::pair< wxString, int > > g_lastERCIgnored
static SCHEMATIC * g_lastERCSchematic
#define DIALOG_ERC_WINDOW_NAME
Definition dialog_erc.h:39
#define _(s)
static int DEFAULT_SINGLE_COL_WIDTH
ERCE_T
ERC error codes.
@ ERCE_ENDPOINT_OFF_GRID
Pin or wire-end off grid.
@ ERCE_PIN_TO_PIN_WARNING
@ ERCE_PIN_TO_PIN_ERROR
static const std::string ReportFileExtension
static const std::string JsonFileExtension
static wxString JsonFileWildcard()
static wxString ReportFileWildcard()
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
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_EXCLUSION
@ RPT_SEVERITY_IGNORE
@ RPT_SEVERITY_INFO
T * GetAppSettings(const char *aFilename)
std::vector< FAB_LAYER_COLOR > dummy
@ MD_ALT
Definition tool_event.h:145
@ MD_CTRL
Definition tool_event.h:144
@ MD_SHIFT
Definition tool_event.h:143
@ SCH_MARKER_T
Definition typeinfo.h:160
Definition of file extensions used in Kicad.