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