2011-10-07 14:41:30 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2015-12-20 12:40:17 +00:00
|
|
|
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
2017-11-12 00:31:38 +00:00
|
|
|
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
|
2023-01-24 17:21:52 +00:00
|
|
|
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
2011-10-07 14:41:30 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <gestfich.h>
|
2018-01-30 08:56:43 +00:00
|
|
|
#include <sch_screen.h>
|
2018-01-30 10:49:51 +00:00
|
|
|
#include <sch_edit_frame.h>
|
2020-05-13 02:00:37 +00:00
|
|
|
#include <schematic.h>
|
Modular KiCad Blueprint Milestone B), major portions:
*) When kicad.exe closes a project, close any open KIFACEs so that they cannot
get disassociated from their true PROJECT.
*) Allow loading eeschema library editor from kicad.exe
*) Allow loading pcbnew library editor from kicad.exe
*) Rename LIB_COMPONENT to LIB_PART.
*) Add class PART_LIBS, and PART_LIB.
*) Make PART_LIBS non-global, i.e. PROJECT specific.
*) Implement "data on demand" for PART_LIBS
*) Implement "data on demand" for schematic SEARCH_STACK.
*) Use RSTRINGs to retain eeschema editor's notion of last library and part being edited.
*) Get rid of library search on every SCH_COMPONENT::Draw() call, instead use
a weak pointer.
*) Remove all chdir() calls so projects don't need to be CWD.
*) Romove APPEND support from OpenProjectFiles().
*) Make OpenProjectFiles() robust, even for creating new projects.
*) Load EESCHEMA colors in the KIWAY::OnKiwayStart() rather in window open,
and save them in the .eeschema config file, not in the project file.
*) Fix bug with wxDir() while accessing protected dirs in kicad.exe
*) Consolidate template copying into PROJECT class, not in kicad.exe source.
*) Generally untangle eeschema, making its libraries not global but rather
held in the PROJECT.
2014-08-13 20:28:54 +00:00
|
|
|
#include <project.h>
|
2021-09-14 22:45:14 +00:00
|
|
|
#include <kiface_base.h>
|
2018-02-17 11:43:56 +00:00
|
|
|
#include <reporter.h>
|
2017-11-12 00:31:38 +00:00
|
|
|
#include <wildcards_and_files_ext.h>
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <sch_marker.h>
|
2019-03-11 21:32:05 +00:00
|
|
|
#include <connection_graph.h>
|
2019-06-13 21:04:31 +00:00
|
|
|
#include <tools/ee_actions.h>
|
2020-11-04 01:07:46 +00:00
|
|
|
#include <tools/ee_inspection_tool.h>
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <dialog_erc.h>
|
|
|
|
#include <erc.h>
|
2013-06-07 20:56:55 +00:00
|
|
|
#include <id.h>
|
2020-03-16 11:05:01 +00:00
|
|
|
#include <confirm.h>
|
2023-03-12 14:49:57 +00:00
|
|
|
#include <common.h>
|
2022-09-03 18:29:02 +00:00
|
|
|
#include <widgets/wx_html_report_box.h>
|
2020-03-16 11:05:01 +00:00
|
|
|
#include <wx/ffile.h>
|
2021-06-07 21:56:43 +00:00
|
|
|
#include <wx/filedlg.h>
|
2020-10-19 14:17:49 +00:00
|
|
|
#include <wx/hyperlink.h>
|
2020-03-16 11:05:01 +00:00
|
|
|
#include <erc_item.h>
|
|
|
|
#include <eeschema_settings.h>
|
2021-07-29 09:56:22 +00:00
|
|
|
#include <string_utils.h>
|
2020-10-19 14:17:49 +00:00
|
|
|
#include <kiplatform/ui.h>
|
Eeschema: ERC dialog code improvements.
* Rename the "net", "lastNet" and "nextNet" variables to "item", "lastItem"
and "nextItem", respectively, because these refer to netlist items, not
nets.
* This adds a suffix "Idx" to the indexes into the list, and introduces local
copies of the pointers to the objects we are looking at, in order to have a
shorter way of addressing them.
* The ERC code depends on netlist items to be sorted by net code, so verify
that in debug builds. While this condition is stricter than necessary, it
should still hold with the current code, and provide a good canary if a
change to the sorting code might break ERC.
2016-06-28 12:52:22 +00:00
|
|
|
|
2023-03-13 16:03:48 +00:00
|
|
|
|
|
|
|
wxDEFINE_EVENT( EDA_EVT_CLOSE_ERC_DIALOG, wxCommandEvent );
|
|
|
|
|
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
// wxWidgets spends *far* too long calcuating column widths (most of it, believe it or
|
|
|
|
// not, in repeatedly creating/destroying a wxDC to do the measurement in).
|
|
|
|
// Use default column widths instead.
|
|
|
|
static int DEFAULT_SINGLE_COL_WIDTH = 660;
|
|
|
|
|
|
|
|
|
2022-06-28 03:06:46 +00:00
|
|
|
static SCHEMATIC* g_lastERCSchematic = nullptr;
|
|
|
|
static bool g_lastERCRun = false;
|
|
|
|
static std::vector<wxString> g_lastERCIgnored;
|
|
|
|
|
|
|
|
|
2011-10-07 14:41:30 +00:00
|
|
|
DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
|
2020-11-03 19:24:05 +00:00
|
|
|
DIALOG_ERC_BASE( parent ),
|
2021-08-14 20:05:21 +00:00
|
|
|
PROGRESS_REPORTER_BASE( 1 ),
|
2020-03-16 11:05:01 +00:00
|
|
|
m_parent( parent ),
|
2022-08-30 11:03:40 +00:00
|
|
|
m_markerTreeModel( nullptr ),
|
2020-10-19 14:17:49 +00:00
|
|
|
m_running( false ),
|
2020-09-21 10:37:20 +00:00
|
|
|
m_ercRun( false ),
|
2022-04-16 23:22:27 +00:00
|
|
|
m_centerMarkerOnIdle( nullptr ),
|
2022-08-30 11:03:40 +00:00
|
|
|
m_severities( 0 )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2022-06-28 03:06:46 +00:00
|
|
|
m_currentSchematic = &parent->Schematic();
|
|
|
|
|
2021-11-29 13:41:02 +00:00
|
|
|
SetName( DIALOG_ERC_WINDOW_NAME ); // Set a window name to be able to find it
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
EESCHEMA_SETTINGS* settings = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
|
|
|
|
m_severities = settings->m_Appearance.erc_severities;
|
|
|
|
|
2020-10-19 14:17:49 +00:00
|
|
|
m_messages->SetImmediateMode();
|
|
|
|
|
2022-08-30 11:03:40 +00:00
|
|
|
m_markerProvider = std::make_shared<SHEETLIST_ERC_ITEMS_PROVIDER>( &m_parent->Schematic() );
|
|
|
|
|
2023-01-21 23:25:40 +00:00
|
|
|
m_markerTreeModel = new ERC_TREE_MODEL( parent, m_markerDataView );
|
2020-03-16 11:05:01 +00:00
|
|
|
m_markerDataView->AssociateModel( m_markerTreeModel );
|
2022-08-30 11:03:40 +00:00
|
|
|
m_markerTreeModel->Update( m_markerProvider, m_severities );
|
2022-01-22 21:34:01 +00:00
|
|
|
|
|
|
|
m_ignoredList->InsertColumn( 0, wxEmptyString, wxLIST_FORMAT_LEFT, DEFAULT_SINGLE_COL_WIDTH );
|
|
|
|
|
2022-06-28 03:06:46 +00:00
|
|
|
if( m_currentSchematic == g_lastERCSchematic )
|
|
|
|
{
|
|
|
|
m_ercRun = g_lastERCRun;
|
|
|
|
|
|
|
|
for( const wxString& str : g_lastERCIgnored )
|
|
|
|
m_ignoredList->InsertItem( m_ignoredList->GetItemCount(), str );
|
|
|
|
}
|
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
m_notebook->SetSelection( 0 );
|
2009-07-03 18:25:06 +00:00
|
|
|
|
2021-11-16 19:39:58 +00:00
|
|
|
SetupStandardButtons( { { wxID_OK, _( "Run ERC" ) },
|
|
|
|
{ wxID_CANCEL, _( "Close" ) } } );
|
2018-07-27 13:52:30 +00:00
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
m_violationsTitleTemplate = m_notebook->GetPageText( 0 );
|
|
|
|
m_ignoredTitleTemplate = m_notebook->GetPageText( 1 );
|
|
|
|
|
2020-10-20 01:32:49 +00:00
|
|
|
m_errorsBadge->SetMaximumNumber( 999 );
|
|
|
|
m_warningsBadge->SetMaximumNumber( 999 );
|
|
|
|
m_exclusionsBadge->SetMaximumNumber( 999 );
|
|
|
|
|
2021-11-29 13:41:02 +00:00
|
|
|
UpdateAnnotationWarning();
|
2020-08-26 01:17:40 +00:00
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
Layout();
|
|
|
|
|
|
|
|
SetFocus();
|
|
|
|
|
|
|
|
syncCheckboxes();
|
|
|
|
updateDisplayedCounts();
|
|
|
|
|
2016-07-16 10:54:55 +00:00
|
|
|
// Now all widgets have the size fixed, call FinishDialogSettings
|
2020-11-16 11:16:44 +00:00
|
|
|
finishDialogSettings();
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
Eeschema: ERC dialog code improvements.
* Rename the "net", "lastNet" and "nextNet" variables to "item", "lastItem"
and "nextItem", respectively, because these refer to netlist items, not
nets.
* This adds a suffix "Idx" to the indexes into the list, and introduces local
copies of the pointers to the objects we are looking at, in order to have a
shorter way of addressing them.
* The ERC code depends on netlist items to be sorted by net code, so verify
that in debug builds. While this condition is stricter than necessary, it
should still hold with the current code, and provide a good canary if a
change to the sorting code might break ERC.
2016-06-28 12:52:22 +00:00
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
DIALOG_ERC::~DIALOG_ERC()
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2022-06-28 03:06:46 +00:00
|
|
|
g_lastERCSchematic = m_currentSchematic;
|
|
|
|
g_lastERCRun = m_ercRun;
|
|
|
|
|
|
|
|
g_lastERCIgnored.clear();
|
|
|
|
|
|
|
|
for( int ii = 0; ii < m_ignoredList->GetItemCount(); ++ii )
|
|
|
|
g_lastERCIgnored.push_back( m_ignoredList->GetItemText( ii ) );
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
EESCHEMA_SETTINGS* settings = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
|
2020-03-21 16:31:48 +00:00
|
|
|
wxASSERT( settings );
|
|
|
|
|
|
|
|
if( settings )
|
|
|
|
settings->m_Appearance.erc_severities = m_severities;
|
2014-10-08 22:40:47 +00:00
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
m_markerTreeModel->DecRef();
|
2019-08-07 19:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 13:41:02 +00:00
|
|
|
void DIALOG_ERC::UpdateAnnotationWarning()
|
|
|
|
{
|
|
|
|
if( m_parent->CheckAnnotate( []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
|
|
|
|
{ } ) )
|
|
|
|
{
|
|
|
|
if( !m_infoBar->IsShown() )
|
|
|
|
{
|
|
|
|
wxHyperlinkCtrl* button = new wxHyperlinkCtrl( m_infoBar, wxID_ANY,
|
2022-09-15 22:43:00 +00:00
|
|
|
_( "Show Annotation dialog" ),
|
2021-11-29 13:41:02 +00:00
|
|
|
wxEmptyString );
|
|
|
|
|
|
|
|
button->Bind( wxEVT_COMMAND_HYPERLINK, std::function<void( wxHyperlinkEvent& aEvent )>(
|
|
|
|
[&]( wxHyperlinkEvent& aEvent )
|
|
|
|
{
|
|
|
|
wxHtmlLinkEvent htmlEvent( aEvent.GetId(),
|
|
|
|
wxHtmlLinkInfo( aEvent.GetURL() ) );
|
|
|
|
OnLinkClicked( htmlEvent );
|
|
|
|
} ) );
|
|
|
|
|
|
|
|
m_infoBar->RemoveAllButtons();
|
|
|
|
m_infoBar->AddButton( button );
|
|
|
|
m_infoBar->ShowMessage( _( "Schematic is not fully annotated. "
|
|
|
|
"ERC results will be incomplete." ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( m_infoBar->IsShown() )
|
|
|
|
{
|
|
|
|
m_infoBar->RemoveAllButtons();
|
|
|
|
m_infoBar->Hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-19 14:17:49 +00:00
|
|
|
bool DIALOG_ERC::updateUI()
|
|
|
|
{
|
|
|
|
// If ERC checks ever get slow enough we'll want a progress indicator...
|
|
|
|
//
|
|
|
|
// double cur = (double) m_progress.load() / m_maxProgress;
|
|
|
|
// cur = std::max( 0.0, std::min( cur, 1.0 ) );
|
|
|
|
//
|
|
|
|
// m_gauge->SetValue( KiROUND( cur * 1000.0 ) );
|
|
|
|
// wxSafeYield( this );
|
|
|
|
|
|
|
|
return !m_cancelled;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::AdvancePhase( const wxString& aMessage )
|
|
|
|
{
|
2021-02-28 14:52:14 +00:00
|
|
|
// Will also call Report( aMessage ):
|
2021-08-14 20:05:21 +00:00
|
|
|
PROGRESS_REPORTER_BASE::AdvancePhase( aMessage );
|
2020-10-19 14:17:49 +00:00
|
|
|
SetCurrentProgress( 0.0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::Report( const wxString& aMessage )
|
|
|
|
{
|
|
|
|
m_messages->Report( aMessage );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
void DIALOG_ERC::updateDisplayedCounts()
|
2014-10-08 22:40:47 +00:00
|
|
|
{
|
2020-03-16 11:05:01 +00:00
|
|
|
int numErrors = 0;
|
|
|
|
int numWarnings = 0;
|
|
|
|
int numExcluded = 0;
|
|
|
|
|
2022-06-28 03:06:46 +00:00
|
|
|
int numMarkers = 0;
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
if( m_markerProvider )
|
|
|
|
{
|
2022-06-28 03:06:46 +00:00
|
|
|
numMarkers += m_markerProvider->GetCount();
|
2020-03-16 11:05:01 +00:00
|
|
|
numErrors += m_markerProvider->GetCount( RPT_SEVERITY_ERROR );
|
|
|
|
numWarnings += m_markerProvider->GetCount( RPT_SEVERITY_WARNING );
|
|
|
|
numExcluded += m_markerProvider->GetCount( RPT_SEVERITY_EXCLUSION );
|
|
|
|
}
|
|
|
|
|
2022-06-28 03:06:46 +00:00
|
|
|
bool markersOverflowed = false;
|
|
|
|
|
|
|
|
// We don't currently have a limit on ERC violations, so the above is always false.
|
|
|
|
|
|
|
|
wxString num;
|
2022-01-22 21:34:01 +00:00
|
|
|
wxString msg;
|
|
|
|
|
2022-06-28 03:06:46 +00:00
|
|
|
if( m_ercRun )
|
2022-01-22 21:34:01 +00:00
|
|
|
{
|
2022-06-28 03:06:46 +00:00
|
|
|
num.Printf( markersOverflowed ? wxT( "%d+" ) : wxT( "%d" ), numMarkers );
|
|
|
|
msg.Printf( m_violationsTitleTemplate, num );
|
2022-01-22 21:34:01 +00:00
|
|
|
}
|
|
|
|
else
|
2020-09-21 10:37:20 +00:00
|
|
|
{
|
2022-01-22 21:34:01 +00:00
|
|
|
msg = m_violationsTitleTemplate;
|
2022-06-28 03:06:46 +00:00
|
|
|
msg.Replace( wxT( "(%s)" ), wxEmptyString );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_notebook->SetPageText( 0, msg );
|
2022-01-22 21:34:01 +00:00
|
|
|
|
2022-06-28 03:06:46 +00:00
|
|
|
if( m_ercRun )
|
|
|
|
{
|
|
|
|
num.Printf( wxT( "%d" ), m_ignoredList->GetItemCount() );
|
|
|
|
msg.sprintf( m_ignoredTitleTemplate, num );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-22 21:34:01 +00:00
|
|
|
msg = m_ignoredTitleTemplate;
|
2022-06-28 03:06:46 +00:00
|
|
|
msg.Replace( wxT( "(%s)" ), wxEmptyString );
|
2022-01-22 21:34:01 +00:00
|
|
|
}
|
|
|
|
|
2022-06-28 03:06:46 +00:00
|
|
|
m_notebook->SetPageText( 1, msg );
|
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
if( !m_ercRun && numErrors == 0 )
|
2020-09-21 10:37:20 +00:00
|
|
|
numErrors = -1;
|
2022-01-22 21:34:01 +00:00
|
|
|
|
|
|
|
if( !m_ercRun && numWarnings == 0 )
|
2020-09-21 10:37:20 +00:00
|
|
|
numWarnings = -1;
|
|
|
|
|
2020-10-20 01:32:49 +00:00
|
|
|
m_errorsBadge->UpdateNumber( numErrors, RPT_SEVERITY_ERROR );
|
|
|
|
m_warningsBadge->UpdateNumber( numWarnings, RPT_SEVERITY_WARNING );
|
|
|
|
m_exclusionsBadge->UpdateNumber( numExcluded, RPT_SEVERITY_EXCLUSION );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2014-10-08 23:54:51 +00:00
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
void DIALOG_ERC::OnDeleteOneClick( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
if( m_notebook->GetSelection() == 0 )
|
|
|
|
{
|
|
|
|
// Clear the selection. It may be the selected ERC marker.
|
|
|
|
m_parent->GetToolManager()->RunAction( EE_ACTIONS::clearSelection, true );
|
|
|
|
|
|
|
|
m_markerTreeModel->DeleteCurrentItem( true );
|
|
|
|
|
|
|
|
// redraw the schematic
|
|
|
|
redrawDrawPanel();
|
|
|
|
}
|
|
|
|
|
|
|
|
updateDisplayedCounts();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::OnDeleteAllClick( wxCommandEvent& event )
|
2011-10-07 14:41:30 +00:00
|
|
|
{
|
2020-08-02 21:45:06 +00:00
|
|
|
bool includeExclusions = false;
|
|
|
|
int numExcluded = 0;
|
|
|
|
|
|
|
|
if( m_markerProvider )
|
|
|
|
numExcluded += m_markerProvider->GetCount( RPT_SEVERITY_EXCLUSION );
|
|
|
|
|
|
|
|
if( numExcluded > 0 )
|
|
|
|
{
|
|
|
|
wxMessageDialog dlg( this, _( "Delete exclusions too?" ), _( "Delete All Markers" ),
|
|
|
|
wxYES_NO | wxCANCEL | wxCENTER | wxICON_QUESTION );
|
2023-01-24 17:21:52 +00:00
|
|
|
dlg.SetYesNoLabels( _( "Errors and Warnings Only" ),
|
|
|
|
_( "Errors, Warnings and Exclusions" ) );
|
2020-08-02 21:45:06 +00:00
|
|
|
|
|
|
|
int ret = dlg.ShowModal();
|
|
|
|
|
|
|
|
if( ret == wxID_CANCEL )
|
|
|
|
return;
|
|
|
|
else if( ret == wxID_NO )
|
|
|
|
includeExclusions = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteAllMarkers( includeExclusions );
|
2014-10-08 22:40:47 +00:00
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
// redraw the schematic
|
|
|
|
redrawDrawPanel();
|
2020-03-16 11:05:01 +00:00
|
|
|
updateDisplayedCounts();
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2009-07-08 15:42:45 +00:00
|
|
|
|
2020-10-19 14:17:49 +00:00
|
|
|
void DIALOG_ERC::OnCancelClick( wxCommandEvent& aEvent )
|
2018-08-06 20:30:49 +00:00
|
|
|
{
|
2020-10-19 14:17:49 +00:00
|
|
|
if( m_running )
|
|
|
|
{
|
|
|
|
m_cancelled = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
m_parent->FocusOnItem( nullptr );
|
|
|
|
|
2023-03-13 16:03:48 +00:00
|
|
|
aEvent.Skip();
|
2018-08-06 20:30:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-03-13 16:03:48 +00:00
|
|
|
void DIALOG_ERC::OnCloseErcDialog( wxCloseEvent& aEvent )
|
2018-08-06 20:30:49 +00:00
|
|
|
{
|
2020-03-16 11:05:01 +00:00
|
|
|
m_parent->FocusOnItem( nullptr );
|
|
|
|
|
2023-03-13 16:03:48 +00:00
|
|
|
// Dialog is mode-less so let the parent know that it needs to be destroyed.
|
|
|
|
if( !IsModal() && !IsQuasiModal() )
|
|
|
|
{
|
|
|
|
wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_CLOSE_ERC_DIALOG, wxID_ANY );
|
|
|
|
|
|
|
|
wxWindow* parent = GetParent();
|
|
|
|
|
|
|
|
if( parent )
|
|
|
|
wxQueueEvent( parent, evt );
|
|
|
|
}
|
|
|
|
|
|
|
|
aEvent.Skip();
|
2018-08-06 20:30:49 +00:00
|
|
|
}
|
|
|
|
|
2015-09-10 12:03:16 +00:00
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
static int RPT_SEVERITY_ALL = RPT_SEVERITY_WARNING | RPT_SEVERITY_ERROR | RPT_SEVERITY_EXCLUSION;
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::syncCheckboxes()
|
|
|
|
{
|
|
|
|
m_showAll->SetValue( m_severities == RPT_SEVERITY_ALL );
|
|
|
|
m_showErrors->SetValue( m_severities & RPT_SEVERITY_ERROR );
|
|
|
|
m_showWarnings->SetValue( m_severities & RPT_SEVERITY_WARNING );
|
|
|
|
m_showExclusions->SetValue( m_severities & RPT_SEVERITY_EXCLUSION );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-19 14:17:49 +00:00
|
|
|
void DIALOG_ERC::OnLinkClicked( wxHtmlLinkEvent& event )
|
|
|
|
{
|
|
|
|
wxCommandEvent dummy;
|
|
|
|
m_parent->OnAnnotate( dummy );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
void DIALOG_ERC::OnRunERCClick( wxCommandEvent& event )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2019-06-13 13:34:38 +00:00
|
|
|
wxBusyCursor busy;
|
2020-10-19 14:17:49 +00:00
|
|
|
|
|
|
|
SCHEMATIC* sch = &m_parent->Schematic();
|
|
|
|
|
2021-11-29 13:41:02 +00:00
|
|
|
UpdateAnnotationWarning();
|
2020-10-19 14:17:49 +00:00
|
|
|
|
2020-11-18 22:55:38 +00:00
|
|
|
m_parent->RecordERCExclusions();
|
2020-08-02 21:45:06 +00:00
|
|
|
deleteAllMarkers( true );
|
2015-09-10 12:03:16 +00:00
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
std::vector<std::reference_wrapper<RC_ITEM>> violations = ERC_ITEM::GetItemsWithSeverities();
|
|
|
|
m_ignoredList->DeleteAllItems();
|
|
|
|
|
|
|
|
for( std::reference_wrapper<RC_ITEM>& item : violations )
|
|
|
|
{
|
|
|
|
if( sch->ErcSettings().GetSeverity( item.get().GetErrorCode() ) == RPT_SEVERITY_IGNORE )
|
|
|
|
{
|
|
|
|
m_ignoredList->InsertItem( m_ignoredList->GetItemCount(),
|
|
|
|
wxT( " • " ) + item.get().GetErrorText() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Raise();
|
|
|
|
|
|
|
|
m_runningResultsBook->ChangeSelection( 0 ); // Display the "Tests Running..." tab
|
2020-10-19 14:17:49 +00:00
|
|
|
m_messages->Clear();
|
2022-01-22 21:34:01 +00:00
|
|
|
wxYield(); // Allow time slice to refresh Messages
|
2020-10-19 14:17:49 +00:00
|
|
|
|
|
|
|
m_running = true;
|
|
|
|
m_sdbSizer1Cancel->SetLabel( _( "Cancel" ) );
|
|
|
|
m_sdbSizer1OK->Enable( false );
|
2022-01-22 21:34:01 +00:00
|
|
|
m_deleteOneMarker->Enable( false );
|
|
|
|
m_deleteAllMarkers->Enable( false );
|
2020-10-19 14:17:49 +00:00
|
|
|
m_saveReport->Enable( false );
|
|
|
|
|
2021-01-24 22:25:32 +00:00
|
|
|
sch->GetSheets().AnnotatePowerSymbols();
|
2021-02-24 22:36:11 +00:00
|
|
|
|
|
|
|
int itemsNotAnnotated = m_parent->CheckAnnotate(
|
2021-01-24 22:25:32 +00:00
|
|
|
[]( ERCE_T aType, const wxString& aMsg, SCH_REFERENCE* aItemA, SCH_REFERENCE* aItemB )
|
|
|
|
{
|
|
|
|
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( aType );
|
|
|
|
ercItem->SetErrorMessage( aMsg );
|
|
|
|
|
|
|
|
if( aItemB )
|
|
|
|
ercItem->SetItems( aItemA->GetSymbol(), aItemB->GetSymbol() );
|
|
|
|
else
|
|
|
|
ercItem->SetItems( aItemA->GetSymbol() );
|
|
|
|
|
|
|
|
SCH_MARKER* marker = new SCH_MARKER( ercItem, aItemA->GetSymbol()->GetPosition() );
|
|
|
|
aItemA->GetSheetPath().LastScreen()->Append( marker );
|
|
|
|
} );
|
|
|
|
|
2020-10-19 14:17:49 +00:00
|
|
|
testErc();
|
2011-10-07 14:41:30 +00:00
|
|
|
|
2021-02-24 22:36:11 +00:00
|
|
|
if( itemsNotAnnotated )
|
|
|
|
m_messages->ReportHead( wxString::Format( _( "%d symbol(s) require annotation.<br><br>" ),
|
|
|
|
itemsNotAnnotated ), RPT_SEVERITY_INFO );
|
|
|
|
|
2020-10-19 14:17:49 +00:00
|
|
|
if( m_cancelled )
|
2021-02-24 22:36:11 +00:00
|
|
|
m_messages->Report( _( "-------- ERC cancelled by user.<br><br>" ), RPT_SEVERITY_INFO );
|
2020-10-19 14:17:49 +00:00
|
|
|
else
|
2022-01-22 21:34:01 +00:00
|
|
|
m_messages->Report( _( "Done.<br><br>" ), RPT_SEVERITY_INFO );
|
2020-10-19 14:17:49 +00:00
|
|
|
|
|
|
|
Raise();
|
|
|
|
wxYield(); // Allow time slice to refresh Messages
|
|
|
|
|
|
|
|
m_running = false;
|
|
|
|
m_sdbSizer1Cancel->SetLabel( _( "Close" ) );
|
|
|
|
m_sdbSizer1OK->Enable( true );
|
2022-01-22 21:34:01 +00:00
|
|
|
m_deleteOneMarker->Enable( true );
|
|
|
|
m_deleteAllMarkers->Enable( true );
|
2020-10-19 14:17:49 +00:00
|
|
|
m_saveReport->Enable( true );
|
|
|
|
|
|
|
|
if( !m_cancelled )
|
|
|
|
{
|
|
|
|
wxMilliSleep( 500 );
|
2022-01-22 21:34:01 +00:00
|
|
|
m_runningResultsBook->ChangeSelection( 1 );
|
2020-10-19 14:17:49 +00:00
|
|
|
KIPLATFORM::UI::ForceFocus( m_markerDataView );
|
|
|
|
}
|
2020-09-21 10:37:20 +00:00
|
|
|
|
|
|
|
m_ercRun = true;
|
2022-01-22 21:34:01 +00:00
|
|
|
redrawDrawPanel();
|
2020-09-21 10:37:20 +00:00
|
|
|
updateDisplayedCounts();
|
2009-07-08 15:42:45 +00:00
|
|
|
}
|
|
|
|
|
2014-10-08 23:54:51 +00:00
|
|
|
|
2020-09-21 10:37:20 +00:00
|
|
|
void DIALOG_ERC::redrawDrawPanel()
|
2018-11-14 23:34:32 +00:00
|
|
|
{
|
|
|
|
WINDOW_THAWER thawer( m_parent );
|
|
|
|
|
|
|
|
m_parent->GetCanvas()->Refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-19 14:17:49 +00:00
|
|
|
void DIALOG_ERC::testErc()
|
2010-11-11 21:10:27 +00:00
|
|
|
{
|
|
|
|
wxFileName fn;
|
|
|
|
|
2020-05-13 02:00:37 +00:00
|
|
|
SCHEMATIC* sch = &m_parent->Schematic();
|
|
|
|
|
Modular KiCad Blueprint Milestone B), major portions:
*) When kicad.exe closes a project, close any open KIFACEs so that they cannot
get disassociated from their true PROJECT.
*) Allow loading eeschema library editor from kicad.exe
*) Allow loading pcbnew library editor from kicad.exe
*) Rename LIB_COMPONENT to LIB_PART.
*) Add class PART_LIBS, and PART_LIB.
*) Make PART_LIBS non-global, i.e. PROJECT specific.
*) Implement "data on demand" for PART_LIBS
*) Implement "data on demand" for schematic SEARCH_STACK.
*) Use RSTRINGs to retain eeschema editor's notion of last library and part being edited.
*) Get rid of library search on every SCH_COMPONENT::Draw() call, instead use
a weak pointer.
*) Remove all chdir() calls so projects don't need to be CWD.
*) Romove APPEND support from OpenProjectFiles().
*) Make OpenProjectFiles() robust, even for creating new projects.
*) Load EESCHEMA colors in the KIWAY::OnKiwayStart() rather in window open,
and save them in the .eeschema config file, not in the project file.
*) Fix bug with wxDir() while accessing protected dirs in kicad.exe
*) Consolidate template copying into PROJECT class, not in kicad.exe source.
*) Generally untangle eeschema, making its libraries not global but rather
held in the PROJECT.
2014-08-13 20:28:54 +00:00
|
|
|
// Build the whole sheet list in hierarchy (sheet, not screen)
|
2020-05-13 02:00:37 +00:00
|
|
|
sch->GetSheets().AnnotatePowerSymbols();
|
2010-11-11 21:10:27 +00:00
|
|
|
|
2020-05-13 02:00:37 +00:00
|
|
|
SCH_SCREENS screens( sch->Root() );
|
2020-06-08 02:19:46 +00:00
|
|
|
ERC_SETTINGS& settings = sch->ErcSettings();
|
2020-07-03 21:08:17 +00:00
|
|
|
ERC_TESTER tester( sch );
|
2010-11-11 21:10:27 +00:00
|
|
|
|
2019-08-07 18:23:59 +00:00
|
|
|
// Test duplicate sheet names inside a given sheet. While one can have multiple references
|
|
|
|
// to the same file, each must have a unique name.
|
2020-06-08 02:19:46 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_DUPLICATE_SHEET_NAME ) )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
2020-10-19 14:17:49 +00:00
|
|
|
AdvancePhase( _( "Checking sheet names..." ) );
|
2020-07-03 21:08:17 +00:00
|
|
|
tester.TestDuplicateSheetNames( true );
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
2010-11-11 21:10:27 +00:00
|
|
|
|
2020-06-08 02:19:46 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_BUS_ALIAS_CONFLICT ) )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
2020-10-19 14:17:49 +00:00
|
|
|
AdvancePhase( _( "Checking bus conflicts..." ) );
|
2020-07-03 21:08:17 +00:00
|
|
|
tester.TestConflictingBusAliases();
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
2019-03-11 21:32:05 +00:00
|
|
|
|
|
|
|
// The connection graph has a whole set of ERC checks it can run
|
2020-10-19 14:17:49 +00:00
|
|
|
AdvancePhase( _( "Checking conflicts..." ) );
|
2019-11-10 23:24:27 +00:00
|
|
|
m_parent->RecalculateConnections( NO_CLEANUP );
|
2020-05-13 02:00:37 +00:00
|
|
|
sch->ConnectionGraph()->RunERC();
|
2019-03-11 21:32:05 +00:00
|
|
|
|
2022-11-26 04:40:01 +00:00
|
|
|
AdvancePhase( _( "Checking units..." ) );
|
|
|
|
|
2021-05-05 21:41:51 +00:00
|
|
|
// Test is all units of each multiunit symbol have the same footprint assigned.
|
2020-06-08 02:19:46 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_DIFFERENT_UNIT_FP ) )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
2020-10-19 14:17:49 +00:00
|
|
|
AdvancePhase( _( "Checking footprints..." ) );
|
2020-07-03 21:08:17 +00:00
|
|
|
tester.TestMultiunitFootprints();
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
2018-01-19 15:12:36 +00:00
|
|
|
|
2022-11-26 04:40:01 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_MISSING_UNIT )
|
|
|
|
|| settings.IsTestEnabled( ERCE_MISSING_INPUT_PIN )
|
|
|
|
|| settings.IsTestEnabled( ERCE_MISSING_POWER_INPUT_PIN )
|
|
|
|
|| settings.IsTestEnabled( ERCE_MISSING_BIDI_PIN ) )
|
|
|
|
{
|
|
|
|
tester.TestMissingUnits();
|
|
|
|
}
|
|
|
|
|
2020-10-19 14:17:49 +00:00
|
|
|
AdvancePhase( _( "Checking pins..." ) );
|
2019-03-29 01:15:36 +00:00
|
|
|
|
2020-08-30 19:25:31 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_DIFFERENT_UNIT_NET ) )
|
|
|
|
tester.TestMultUnitPinConflicts();
|
2010-11-11 21:10:27 +00:00
|
|
|
|
2020-08-30 19:25:31 +00:00
|
|
|
// Test pins on each net against the pin connection table
|
2021-11-04 16:23:25 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_PIN_TO_PIN_ERROR )
|
2023-03-13 16:03:48 +00:00
|
|
|
|| settings.IsTestEnabled( ERCE_POWERPIN_NOT_DRIVEN )
|
|
|
|
|| settings.IsTestEnabled( ERCE_PIN_NOT_DRIVEN ) )
|
2021-11-04 16:23:25 +00:00
|
|
|
{
|
2022-04-06 23:51:44 +00:00
|
|
|
tester.TestPinToPin();
|
2021-11-04 16:23:25 +00:00
|
|
|
}
|
2010-11-11 21:10:27 +00:00
|
|
|
|
2015-12-20 12:40:17 +00:00
|
|
|
// Test similar labels (i;e. labels which are identical when
|
|
|
|
// using case insensitive comparisons)
|
2020-06-08 02:19:46 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_SIMILAR_LABELS ) )
|
2020-03-10 18:46:57 +00:00
|
|
|
{
|
2020-10-19 14:17:49 +00:00
|
|
|
AdvancePhase( _( "Checking labels..." ) );
|
2020-08-30 19:42:46 +00:00
|
|
|
tester.TestSimilarLabels();
|
2020-03-10 18:46:57 +00:00
|
|
|
}
|
2015-12-20 12:40:17 +00:00
|
|
|
|
2020-06-08 02:19:46 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_UNRESOLVED_VARIABLE ) )
|
2020-10-07 13:15:31 +00:00
|
|
|
{
|
2020-10-19 14:17:49 +00:00
|
|
|
AdvancePhase( _( "Checking for unresolved variables..." ) );
|
2021-02-22 16:37:43 +00:00
|
|
|
tester.TestTextVars( m_parent->GetCanvas()->GetView()->GetDrawingSheet() );
|
2020-10-07 13:15:31 +00:00
|
|
|
}
|
2020-03-29 01:12:29 +00:00
|
|
|
|
2022-11-07 12:27:58 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_SIMULATION_MODEL ) )
|
|
|
|
{
|
|
|
|
AdvancePhase( _( "Checking SPICE models..." ) );
|
|
|
|
tester.TestSimModelIssues();
|
|
|
|
}
|
|
|
|
|
2020-07-07 00:10:08 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED ) )
|
2020-10-07 13:15:31 +00:00
|
|
|
{
|
2020-10-19 14:17:49 +00:00
|
|
|
AdvancePhase( _( "Checking no connect pins for connections..." ) );
|
2020-07-07 00:10:08 +00:00
|
|
|
tester.TestNoConnectPins();
|
2020-10-07 13:15:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( settings.IsTestEnabled( ERCE_LIB_SYMBOL_ISSUES ) )
|
|
|
|
{
|
2020-10-19 14:17:49 +00:00
|
|
|
AdvancePhase( _( "Checking for library symbol issues..." ) );
|
2020-10-07 13:15:31 +00:00
|
|
|
tester.TestLibSymbolIssues();
|
|
|
|
}
|
2020-07-07 00:10:08 +00:00
|
|
|
|
2022-03-17 20:23:14 +00:00
|
|
|
if( settings.IsTestEnabled( ERCE_ENDPOINT_OFF_GRID ) )
|
|
|
|
{
|
|
|
|
AdvancePhase( _( "Checking for off grid pins and wires..." ) );
|
|
|
|
tester.TestOffGridEndpoints( m_parent->GetCanvas()->GetView()->GetGAL()->GetGridSize().x );
|
|
|
|
}
|
|
|
|
|
2020-11-18 22:55:38 +00:00
|
|
|
m_parent->ResolveERCExclusions();
|
|
|
|
|
2022-08-30 11:03:40 +00:00
|
|
|
// Update marker list:
|
|
|
|
m_markerTreeModel->Update( m_markerProvider, m_severities );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2018-09-04 20:53:04 +00:00
|
|
|
// Display new markers from the current screen:
|
2020-12-20 17:48:15 +00:00
|
|
|
for( SCH_ITEM* marker : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
|
|
|
|
{
|
|
|
|
m_parent->GetCanvas()->GetView()->Remove( marker );
|
|
|
|
m_parent->GetCanvas()->GetView()->Add( marker );
|
|
|
|
}
|
2018-09-04 20:53:04 +00:00
|
|
|
|
2012-11-30 12:28:23 +00:00
|
|
|
m_parent->GetCanvas()->Refresh();
|
2010-11-11 21:10:27 +00:00
|
|
|
}
|
2013-06-07 20:56:55 +00:00
|
|
|
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent )
|
|
|
|
{
|
|
|
|
const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() );
|
|
|
|
SCH_SHEET_PATH sheet;
|
2020-05-13 02:00:37 +00:00
|
|
|
SCH_ITEM* item = m_parent->Schematic().GetSheets().GetItem( itemID, &sheet );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2022-04-16 23:22:27 +00:00
|
|
|
if( m_centerMarkerOnIdle )
|
|
|
|
{
|
|
|
|
// we already came from a cross-probe of the marker in the document; don't go
|
|
|
|
// around in circles
|
|
|
|
}
|
|
|
|
else if( item && item->GetClass() != wxT( "DELETED_SHEET_ITEM" ) )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
2023-01-21 23:25:40 +00:00
|
|
|
const RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
|
|
|
|
|
|
|
|
if( node )
|
|
|
|
{
|
|
|
|
// Determine the owning sheet for sheet-specific items
|
|
|
|
std::shared_ptr<ERC_ITEM> ercItem =
|
|
|
|
std::static_pointer_cast<ERC_ITEM>( node->m_RcItem );
|
|
|
|
switch( node->m_Type )
|
|
|
|
{
|
|
|
|
case RC_TREE_NODE::MARKER:
|
|
|
|
if( ercItem->IsSheetSpecific() )
|
|
|
|
sheet = ercItem->GetSpecificSheetPath();
|
|
|
|
break;
|
|
|
|
case RC_TREE_NODE::MAIN_ITEM:
|
|
|
|
if( ercItem->MainItemHasSheetPath() )
|
|
|
|
sheet = ercItem->GetMainItemSheetPath();
|
|
|
|
break;
|
|
|
|
case RC_TREE_NODE::AUX_ITEM:
|
|
|
|
if( ercItem->AuxItemHasSheetPath() )
|
|
|
|
sheet = ercItem->GetAuxItemSheetPath();
|
|
|
|
break;
|
2023-01-24 17:21:52 +00:00
|
|
|
default:
|
|
|
|
break;
|
2023-01-21 23:25:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
WINDOW_THAWER thawer( m_parent );
|
|
|
|
|
2020-06-19 21:00:41 +00:00
|
|
|
if( !sheet.empty() && sheet != m_parent->GetCurrentSheet() )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
|
|
|
m_parent->GetToolManager()->RunAction( ACTIONS::cancelInteractive, true );
|
|
|
|
m_parent->GetToolManager()->RunAction( EE_ACTIONS::clearSelection, true );
|
|
|
|
|
|
|
|
m_parent->SetCurrentSheet( sheet );
|
|
|
|
m_parent->DisplayCurrentSheet();
|
2023-02-19 03:40:07 +00:00
|
|
|
m_parent->RedrawScreen( m_parent->GetScreen()->m_ScrollCenter, false );
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_parent->FocusOnItem( item );
|
2020-09-21 10:37:20 +00:00
|
|
|
redrawDrawPanel();
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
aEvent.Skip();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::OnERCItemDClick( wxDataViewEvent& aEvent )
|
|
|
|
{
|
|
|
|
if( aEvent.GetItem().IsOk() )
|
|
|
|
{
|
|
|
|
// turn control over to m_parent, hide this DIALOG_ERC window,
|
|
|
|
// no destruction so we can preserve listbox cursor
|
|
|
|
if( !IsModal() )
|
|
|
|
Show( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
aEvent.Skip();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
|
|
|
|
{
|
|
|
|
RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
|
|
|
|
|
|
|
|
if( !node )
|
|
|
|
return;
|
|
|
|
|
2020-06-08 02:19:46 +00:00
|
|
|
ERC_SETTINGS& settings = m_parent->Schematic().ErcSettings();
|
2020-05-13 02:00:37 +00:00
|
|
|
|
2020-08-11 13:33:16 +00:00
|
|
|
std::shared_ptr<RC_ITEM> rcItem = node->m_RcItem;
|
2020-03-16 11:05:01 +00:00
|
|
|
wxString listName;
|
|
|
|
wxMenu menu;
|
|
|
|
|
2020-06-08 02:19:46 +00:00
|
|
|
switch( settings.GetSeverity( rcItem->GetErrorCode() ) )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
|
|
|
case RPT_SEVERITY_ERROR: listName = _( "errors" ); break;
|
|
|
|
case RPT_SEVERITY_WARNING: listName = _( "warnings" ); break;
|
|
|
|
default: listName = _( "appropriate" ); break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( rcItem->GetParent()->IsExcluded() )
|
|
|
|
{
|
|
|
|
menu.Append( 1, _( "Remove exclusion for this violation" ),
|
|
|
|
wxString::Format( _( "It will be placed back in the %s list" ), listName ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
menu.Append( 2, _( "Exclude this violation" ),
|
|
|
|
wxString::Format( _( "It will be excluded from the %s list" ), listName ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
menu.AppendSeparator();
|
|
|
|
|
2020-04-28 08:55:44 +00:00
|
|
|
if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_WARNING
|
2023-03-13 16:03:48 +00:00
|
|
|
|| rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
2020-04-28 08:55:44 +00:00
|
|
|
// Pin to pin severities edited through pin conflict map
|
|
|
|
}
|
2020-06-08 02:19:46 +00:00
|
|
|
else if( settings.GetSeverity( rcItem->GetErrorCode() ) == RPT_SEVERITY_WARNING )
|
2020-04-28 08:55:44 +00:00
|
|
|
{
|
|
|
|
menu.Append( 4, wxString::Format( _( "Change severity to Error for all '%s' violations" ),
|
2020-06-08 02:19:46 +00:00
|
|
|
rcItem->GetErrorText() ),
|
2023-03-13 23:35:07 +00:00
|
|
|
_( "Violation severities can also be edited in the Schematic Setup... dialog" ) );
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-28 08:55:44 +00:00
|
|
|
menu.Append( 5, wxString::Format( _( "Change severity to Warning for all '%s' violations" ),
|
2020-06-08 02:19:46 +00:00
|
|
|
rcItem->GetErrorText() ),
|
2023-03-13 23:35:07 +00:00
|
|
|
_( "Violation severities can also be edited in the Schematic Setup... dialog" ) );
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
|
|
|
|
2020-06-08 02:19:46 +00:00
|
|
|
menu.Append( 6, wxString::Format( _( "Ignore all '%s' violations" ), rcItem->GetErrorText() ),
|
2020-04-28 08:55:44 +00:00
|
|
|
_( "Violations will not be checked or reported" ) );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
|
|
|
menu.AppendSeparator();
|
|
|
|
|
2020-04-28 08:55:44 +00:00
|
|
|
if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_WARNING
|
|
|
|
|| rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
|
|
|
|
{
|
|
|
|
menu.Append( 7, _( "Edit pin-to-pin conflict map..." ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
menu.Append( 8, _( "Edit violation severities..." ),
|
|
|
|
_( "Open the Schematic Setup... dialog" ) );
|
|
|
|
}
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2020-12-01 22:35:11 +00:00
|
|
|
bool modified = false;
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
switch( GetPopupMenuSelectionFromUser( menu ) )
|
|
|
|
{
|
|
|
|
case 1:
|
2020-12-01 22:35:11 +00:00
|
|
|
{
|
|
|
|
SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2020-12-01 22:35:11 +00:00
|
|
|
if( marker )
|
|
|
|
{
|
|
|
|
marker->SetExcluded( false );
|
|
|
|
m_parent->GetCanvas()->GetView()->Update( marker );
|
|
|
|
|
|
|
|
// Update view
|
|
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
|
|
|
|
modified = true;
|
|
|
|
}
|
|
|
|
}
|
2020-03-16 11:05:01 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
2020-12-01 22:35:11 +00:00
|
|
|
{
|
|
|
|
SCH_MARKER* marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2020-12-01 22:35:11 +00:00
|
|
|
if( marker )
|
|
|
|
{
|
|
|
|
marker->SetExcluded( true );
|
|
|
|
m_parent->GetCanvas()->GetView()->Update( marker );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2020-12-01 22:35:11 +00:00
|
|
|
// Update view
|
|
|
|
if( m_severities & RPT_SEVERITY_EXCLUSION )
|
|
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
|
|
|
|
else
|
|
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false );
|
|
|
|
|
|
|
|
modified = true;
|
|
|
|
}
|
|
|
|
}
|
2020-03-16 11:05:01 +00:00
|
|
|
break;
|
|
|
|
|
2020-04-28 08:55:44 +00:00
|
|
|
case 4:
|
2020-06-08 02:19:46 +00:00
|
|
|
settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_ERROR );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2020-12-01 22:35:11 +00:00
|
|
|
for( SCH_ITEM* item : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
|
|
|
|
{
|
|
|
|
SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
|
|
|
|
|
|
|
|
if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
|
|
|
|
m_parent->GetCanvas()->GetView()->Update( marker );
|
|
|
|
}
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
// Rebuild model and view
|
2022-08-30 11:03:40 +00:00
|
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, m_severities );
|
2020-12-01 22:35:11 +00:00
|
|
|
modified = true;
|
2020-03-16 11:05:01 +00:00
|
|
|
break;
|
|
|
|
|
2020-04-28 08:55:44 +00:00
|
|
|
case 5:
|
2020-06-08 02:19:46 +00:00
|
|
|
settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_WARNING );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2020-12-01 22:35:11 +00:00
|
|
|
for( SCH_ITEM* item : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
|
|
|
|
{
|
|
|
|
SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
|
|
|
|
|
|
|
|
if( marker->GetRCItem()->GetErrorCode() == rcItem->GetErrorCode() )
|
|
|
|
m_parent->GetCanvas()->GetView()->Update( marker );
|
|
|
|
}
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
// Rebuild model and view
|
2022-08-30 11:03:40 +00:00
|
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, m_severities );
|
2020-12-01 22:35:11 +00:00
|
|
|
modified = true;
|
2020-03-16 11:05:01 +00:00
|
|
|
break;
|
|
|
|
|
2020-04-28 08:55:44 +00:00
|
|
|
case 6:
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
2020-06-08 02:19:46 +00:00
|
|
|
settings.SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_IGNORE );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2020-04-28 08:55:44 +00:00
|
|
|
if( rcItem->GetErrorCode() == ERCE_PIN_TO_PIN_ERROR )
|
2020-06-08 02:19:46 +00:00
|
|
|
settings.SetSeverity( ERCE_PIN_TO_PIN_WARNING, RPT_SEVERITY_IGNORE );
|
2020-04-28 08:55:44 +00:00
|
|
|
|
2020-06-08 02:19:46 +00:00
|
|
|
SCH_SCREENS ScreenList( m_parent->Schematic().Root() );
|
2020-03-16 11:05:01 +00:00
|
|
|
ScreenList.DeleteMarkers( MARKER_BASE::MARKER_ERC, rcItem->GetErrorCode() );
|
|
|
|
|
|
|
|
// Rebuild model and view
|
2022-08-30 11:03:40 +00:00
|
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, m_severities );
|
2020-12-01 22:35:11 +00:00
|
|
|
modified = true;
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-04-28 08:55:44 +00:00
|
|
|
case 7:
|
2020-05-24 14:54:26 +00:00
|
|
|
m_parent->ShowSchematicSetupDialog( _( "Pin Conflicts Map" ) );
|
2020-04-28 08:55:44 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 8:
|
2020-05-24 14:54:26 +00:00
|
|
|
m_parent->ShowSchematicSetupDialog( _( "Violation Severity" ) );
|
2020-03-16 11:05:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-12-01 22:35:11 +00:00
|
|
|
|
|
|
|
if( modified )
|
|
|
|
{
|
|
|
|
updateDisplayedCounts();
|
|
|
|
redrawDrawPanel();
|
|
|
|
m_parent->OnModify();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::PrevMarker()
|
|
|
|
{
|
2022-01-22 21:34:01 +00:00
|
|
|
if( m_notebook->IsShown() )
|
|
|
|
{
|
|
|
|
if( m_notebook->GetSelection() != 0 )
|
|
|
|
m_notebook->SetSelection( 0 );
|
2020-12-01 22:35:11 +00:00
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
m_markerTreeModel->PrevMarker();
|
|
|
|
}
|
2020-12-01 22:35:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::NextMarker()
|
|
|
|
{
|
2022-01-22 21:34:01 +00:00
|
|
|
if( m_notebook->IsShown() )
|
|
|
|
{
|
|
|
|
if( m_notebook->GetSelection() != 0 )
|
|
|
|
m_notebook->SetSelection( 0 );
|
2020-12-01 22:35:11 +00:00
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
m_markerTreeModel->NextMarker();
|
|
|
|
}
|
2020-12-01 22:35:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-16 23:22:27 +00:00
|
|
|
void DIALOG_ERC::SelectMarker( const SCH_MARKER* aMarker )
|
|
|
|
{
|
|
|
|
if( m_notebook->IsShown() )
|
|
|
|
{
|
|
|
|
m_notebook->SetSelection( 0 );
|
|
|
|
m_markerTreeModel->SelectMarker( aMarker );
|
|
|
|
|
|
|
|
// wxWidgets on some platforms fails to correctly ensure that a selected item is
|
|
|
|
// visible, so we have to do it in a separate idle event.
|
|
|
|
m_centerMarkerOnIdle = aMarker;
|
|
|
|
Bind( wxEVT_IDLE, &DIALOG_ERC::centerMarkerIdleHandler, this );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::centerMarkerIdleHandler( wxIdleEvent& aEvent )
|
|
|
|
{
|
|
|
|
m_markerTreeModel->CenterMarker( m_centerMarkerOnIdle );
|
|
|
|
m_centerMarkerOnIdle = nullptr;
|
|
|
|
Unbind( wxEVT_IDLE, &DIALOG_ERC::centerMarkerIdleHandler, this );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-30 16:51:04 +00:00
|
|
|
void DIALOG_ERC::ExcludeMarker( SCH_MARKER* aMarker )
|
2020-12-01 22:35:11 +00:00
|
|
|
{
|
2021-12-30 16:51:04 +00:00
|
|
|
SCH_MARKER* marker = aMarker;
|
|
|
|
|
|
|
|
if( marker != nullptr )
|
|
|
|
m_markerTreeModel->SelectMarker( marker );
|
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
if( m_notebook->GetSelection() != 0 )
|
2020-12-01 22:35:11 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( m_markerDataView->GetCurrentItem() );
|
|
|
|
|
2021-12-30 16:51:04 +00:00
|
|
|
if( node && node->m_RcItem )
|
|
|
|
marker = dynamic_cast<SCH_MARKER*>( node->m_RcItem->GetParent() );
|
|
|
|
|
|
|
|
if( node && marker && !marker->IsExcluded() )
|
2020-12-01 22:35:11 +00:00
|
|
|
{
|
|
|
|
marker->SetExcluded( true );
|
|
|
|
m_parent->GetCanvas()->GetView()->Update( marker );
|
|
|
|
|
|
|
|
// Update view
|
|
|
|
if( m_severities & RPT_SEVERITY_EXCLUSION )
|
|
|
|
m_markerTreeModel->ValueChanged( node );
|
|
|
|
else
|
|
|
|
m_markerTreeModel->DeleteCurrentItem( false );
|
|
|
|
|
|
|
|
updateDisplayedCounts();
|
|
|
|
redrawDrawPanel();
|
|
|
|
m_parent->OnModify();
|
|
|
|
}
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-22 21:34:01 +00:00
|
|
|
void DIALOG_ERC::OnIgnoreItemRClick( wxListEvent& event )
|
|
|
|
{
|
|
|
|
wxMenu menu;
|
|
|
|
|
|
|
|
menu.Append( 1, _( "Edit ignored violations..." ), _( "Open the Schematic Setup... dialog" ) );
|
|
|
|
|
|
|
|
switch( GetPopupMenuSelectionFromUser( menu ) )
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
m_parent->ShowSchematicSetupDialog( _( "Violation Severity" ) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
void DIALOG_ERC::OnSeverity( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
int flag = 0;
|
|
|
|
|
|
|
|
if( aEvent.GetEventObject() == m_showAll )
|
|
|
|
flag = RPT_SEVERITY_ALL;
|
|
|
|
else if( aEvent.GetEventObject() == m_showErrors )
|
|
|
|
flag = RPT_SEVERITY_ERROR;
|
|
|
|
else if( aEvent.GetEventObject() == m_showWarnings )
|
|
|
|
flag = RPT_SEVERITY_WARNING;
|
|
|
|
else if( aEvent.GetEventObject() == m_showExclusions )
|
|
|
|
flag = RPT_SEVERITY_EXCLUSION;
|
|
|
|
|
|
|
|
if( aEvent.IsChecked() )
|
|
|
|
m_severities |= flag;
|
|
|
|
else if( aEvent.GetEventObject() == m_showAll )
|
|
|
|
m_severities = RPT_SEVERITY_ERROR;
|
|
|
|
else
|
|
|
|
m_severities &= ~flag;
|
|
|
|
|
|
|
|
syncCheckboxes();
|
|
|
|
|
2022-08-30 11:03:40 +00:00
|
|
|
m_markerTreeModel->Update( m_markerProvider, m_severities );
|
2020-03-16 11:05:01 +00:00
|
|
|
updateDisplayedCounts();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-02 21:45:06 +00:00
|
|
|
void DIALOG_ERC::deleteAllMarkers( bool aIncludeExclusions )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
|
|
|
// Clear current selection list to avoid selection of deleted items
|
|
|
|
m_parent->GetToolManager()->RunAction( EE_ACTIONS::clearSelection, true );
|
|
|
|
|
2022-08-08 21:00:37 +00:00
|
|
|
m_markerTreeModel->DeleteItems( false, aIncludeExclusions, false );
|
|
|
|
|
|
|
|
SCH_SCREENS screens( m_parent->Schematic().Root() );
|
|
|
|
screens.DeleteAllMarkers( MARKER_BASE::MARKER_ERC, aIncludeExclusions );
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_ERC::OnSaveReport( wxCommandEvent& aEvent )
|
|
|
|
{
|
2023-01-17 04:14:38 +00:00
|
|
|
wxFileName fn( wxS( "ERC." ) + ReportFileExtension );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2021-02-28 14:52:14 +00:00
|
|
|
wxFileDialog dlg( this, _( "Save Report to File" ), Prj().GetProjectPath(), fn.GetFullName(),
|
2020-03-16 11:05:01 +00:00
|
|
|
ReportFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
|
|
|
|
|
|
if( dlg.ShowModal() != wxID_OK )
|
|
|
|
return;
|
|
|
|
|
2023-03-12 14:49:57 +00:00
|
|
|
fn = EnsureFileExtension( dlg.GetPath(), ReportFileExtension );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
|
|
|
if( !fn.IsAbsolute() )
|
|
|
|
{
|
|
|
|
wxString prj_path = Prj().GetProjectPath();
|
|
|
|
fn.MakeAbsolute( prj_path );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( writeReport( fn.GetFullPath() ) )
|
|
|
|
{
|
2021-07-05 12:40:38 +00:00
|
|
|
m_messages->Report( wxString::Format( _( "Report file '%s' created." ),
|
2020-10-19 14:17:49 +00:00
|
|
|
fn.GetFullPath() ) );
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-07-05 12:40:38 +00:00
|
|
|
DisplayError( this, wxString::Format( _( "Failed to create file '%s'." ),
|
2020-03-16 11:05:01 +00:00
|
|
|
fn.GetFullPath() ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool DIALOG_ERC::writeReport( const wxString& aFullFileName )
|
|
|
|
{
|
|
|
|
wxFFile file( aFullFileName, wxT( "wt" ) );
|
|
|
|
|
|
|
|
if( !file.IsOpened() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
wxString msg = wxString::Format( _( "ERC report (%s, Encoding UTF8)\n" ), DateAndTime() );
|
|
|
|
|
2020-04-24 13:36:10 +00:00
|
|
|
std::map<KIID, EDA_ITEM*> itemMap;
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
int err_count = 0;
|
|
|
|
int warn_count = 0;
|
|
|
|
int total_count = 0;
|
2020-05-13 02:00:37 +00:00
|
|
|
SCH_SHEET_LIST sheetList = m_parent->Schematic().GetSheets();
|
2020-03-16 11:05:01 +00:00
|
|
|
|
2020-04-24 13:36:10 +00:00
|
|
|
sheetList.FillItemMap( itemMap );
|
|
|
|
|
2020-06-08 02:19:46 +00:00
|
|
|
ERC_SETTINGS& settings = m_parent->Schematic().ErcSettings();
|
|
|
|
|
2020-03-16 11:05:01 +00:00
|
|
|
for( unsigned i = 0; i < sheetList.size(); i++ )
|
|
|
|
{
|
|
|
|
msg << wxString::Format( _( "\n***** Sheet %s\n" ), sheetList[i].PathHumanReadable() );
|
|
|
|
|
2020-04-24 13:36:10 +00:00
|
|
|
for( SCH_ITEM* aItem : sheetList[i].LastScreen()->Items().OfType( SCH_MARKER_T ) )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
2020-04-24 13:36:10 +00:00
|
|
|
const SCH_MARKER* marker = static_cast<const SCH_MARKER*>( aItem );
|
2020-09-21 10:36:07 +00:00
|
|
|
RC_ITEM* item = marker->GetRCItem().get();
|
2020-12-14 13:33:51 +00:00
|
|
|
SEVERITY severity = settings.GetSeverity( item->GetErrorCode() );
|
2020-03-16 11:05:01 +00:00
|
|
|
|
|
|
|
if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
total_count++;
|
|
|
|
|
2020-09-21 10:36:07 +00:00
|
|
|
switch( severity )
|
2020-03-16 11:05:01 +00:00
|
|
|
{
|
|
|
|
case RPT_SEVERITY_ERROR: err_count++; break;
|
|
|
|
case RPT_SEVERITY_WARNING: warn_count++; break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
2022-09-19 16:09:59 +00:00
|
|
|
msg << marker->GetRCItem()->ShowReport( m_parent, severity, itemMap );
|
2020-03-16 11:05:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
msg << wxString::Format( _( "\n ** ERC messages: %d Errors %d Warnings %d\n" ),
|
|
|
|
total_count, err_count, warn_count );
|
|
|
|
|
|
|
|
// Currently: write report using UTF8 (as usual in Kicad).
|
|
|
|
// TODO: see if we can use the current encoding page (mainly for Windows users),
|
|
|
|
// Or other format (HTML?)
|
|
|
|
file.Write( msg );
|
|
|
|
|
|
|
|
// wxFFile dtor will close the file.
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|