633 lines
20 KiB
C++
633 lines
20 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
|
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
|
|
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
#include <fctsys.h>
|
|
#include <gestfich.h>
|
|
#include <pgm_base.h>
|
|
#include <sch_screen.h>
|
|
#include <sch_edit_frame.h>
|
|
#include <invoke_sch_dialog.h>
|
|
#include <project.h>
|
|
#include <kiface_i.h>
|
|
#include <bitmaps.h>
|
|
#include <reporter.h>
|
|
#include <wildcards_and_files_ext.h>
|
|
#include <sch_view.h>
|
|
#include <netlist_object.h>
|
|
#include <sch_marker.h>
|
|
#include <sch_component.h>
|
|
#include <connection_graph.h>
|
|
#include <tools/ee_actions.h>
|
|
#include <tool/tool_manager.h>
|
|
#include <dialog_erc.h>
|
|
#include <erc.h>
|
|
#include <id.h>
|
|
#include <confirm.h>
|
|
#include <wx/ffile.h>
|
|
#include <erc_item.h>
|
|
#include <eeschema_settings.h>
|
|
|
|
DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
|
|
DIALOG_ERC_BASE( parent, ID_DIALOG_ERC ), // parent looks for this ID explicitly
|
|
m_parent( parent ),
|
|
m_severities( RPT_SEVERITY_ERROR | RPT_SEVERITY_WARNING )
|
|
{
|
|
EESCHEMA_SETTINGS* settings = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
|
|
m_severities = settings->m_Appearance.erc_severities;
|
|
|
|
m_markerProvider = new SHEETLIST_ERC_ITEMS_PROVIDER();
|
|
m_markerTreeModel = new RC_TREE_MODEL( parent, m_markerDataView );
|
|
m_markerDataView->AssociateModel( m_markerTreeModel );
|
|
|
|
wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
|
|
infoFont.SetSymbolicSize( wxFONTSIZE_SMALL );
|
|
m_textMarkers->SetFont( infoFont );
|
|
m_titleMessages->SetFont( infoFont );
|
|
|
|
m_markerTreeModel->SetSeverities( m_severities );
|
|
m_markerTreeModel->SetProvider( m_markerProvider );
|
|
syncCheckboxes();
|
|
updateDisplayedCounts();
|
|
|
|
// We use a sdbSizer to get platform-dependent ordering of the action buttons, but
|
|
// that requires us to correct the button labels here.
|
|
m_sdbSizer1OK->SetLabel( _( "Run" ) );
|
|
m_sdbSizer1Cancel->SetLabel( _( "Close" ) );
|
|
m_sdbSizer1->Layout();
|
|
|
|
m_sdbSizer1OK->SetDefault();
|
|
|
|
// Now all widgets have the size fixed, call FinishDialogSettings
|
|
FinishDialogSettings();
|
|
}
|
|
|
|
|
|
DIALOG_ERC::~DIALOG_ERC()
|
|
{
|
|
EESCHEMA_SETTINGS* settings = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
|
|
wxASSERT( settings );
|
|
|
|
if( settings )
|
|
settings->m_Appearance.erc_severities = m_severities;
|
|
|
|
m_markerTreeModel->DecRef();
|
|
}
|
|
|
|
|
|
void DIALOG_ERC::updateDisplayedCounts()
|
|
{
|
|
int numErrors = 0;
|
|
int numWarnings = 0;
|
|
int numExcluded = 0;
|
|
|
|
if( m_markerProvider )
|
|
{
|
|
numErrors += m_markerProvider->GetCount( RPT_SEVERITY_ERROR );
|
|
numWarnings += m_markerProvider->GetCount( RPT_SEVERITY_WARNING );
|
|
numExcluded += m_markerProvider->GetCount( RPT_SEVERITY_EXCLUSION );
|
|
}
|
|
|
|
m_errorsBadge->SetBitmap( MakeBadge( RPT_SEVERITY_ERROR, numErrors, m_errorsBadge ) );
|
|
m_warningsBadge->SetBitmap( MakeBadge( RPT_SEVERITY_WARNING, numWarnings, m_warningsBadge ) );
|
|
m_exclusionsBadge->SetBitmap( MakeBadge( RPT_SEVERITY_EXCLUSION, numExcluded, m_exclusionsBadge ) );
|
|
}
|
|
|
|
|
|
/* Delete the old ERC markers, over the whole hierarchy
|
|
*/
|
|
void DIALOG_ERC::OnEraseDrcMarkersClick( wxCommandEvent& event )
|
|
{
|
|
deleteAllMarkers();
|
|
|
|
updateDisplayedCounts();
|
|
m_parent->GetCanvas()->Refresh();
|
|
}
|
|
|
|
|
|
// This is a modeless dialog so we have to handle these ourselves.
|
|
void DIALOG_ERC::OnButtonCloseClick( wxCommandEvent& event )
|
|
{
|
|
m_parent->FocusOnItem( nullptr );
|
|
|
|
Close();
|
|
}
|
|
|
|
|
|
void DIALOG_ERC::OnCloseErcDialog( wxCloseEvent& event )
|
|
{
|
|
m_parent->FocusOnItem( nullptr );
|
|
|
|
Destroy();
|
|
}
|
|
|
|
|
|
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 );
|
|
}
|
|
|
|
|
|
void DIALOG_ERC::OnRunERCClick( wxCommandEvent& event )
|
|
{
|
|
wxBusyCursor busy;
|
|
deleteAllMarkers();
|
|
|
|
m_MessagesList->Clear();
|
|
wxSafeYield(); // m_MarkersList must be redraw
|
|
|
|
WX_TEXT_CTRL_REPORTER reporter( m_MessagesList );
|
|
TestErc( reporter );
|
|
}
|
|
|
|
|
|
void DIALOG_ERC::RedrawDrawPanel()
|
|
{
|
|
WINDOW_THAWER thawer( m_parent );
|
|
|
|
m_parent->GetCanvas()->Refresh();
|
|
}
|
|
|
|
|
|
void DIALOG_ERC::TestErc( REPORTER& aReporter )
|
|
{
|
|
wxFileName fn;
|
|
|
|
// Build the whole sheet list in hierarchy (sheet, not screen)
|
|
SCH_SHEET_LIST sheets( g_RootSheet );
|
|
sheets.AnnotatePowerSymbols();
|
|
|
|
if( m_parent->CheckAnnotate( aReporter, false ) )
|
|
{
|
|
if( aReporter.HasMessage() )
|
|
aReporter.ReportTail( _( "Annotation required!" ), RPT_SEVERITY_ERROR );
|
|
|
|
return;
|
|
}
|
|
|
|
SCH_SCREENS screens;
|
|
|
|
// Test duplicate sheet names inside a given sheet. While one can have multiple references
|
|
// to the same file, each must have a unique name.
|
|
if( g_ErcSettings->IsTestEnabled( ERCE_DUPLICATE_SHEET_NAME ) )
|
|
{
|
|
aReporter.ReportTail( _( "Checking sheet names...\n" ), RPT_SEVERITY_INFO );
|
|
TestDuplicateSheetNames( true );
|
|
}
|
|
|
|
if( g_ErcSettings->IsTestEnabled( ERCE_BUS_ALIAS_CONFLICT ) )
|
|
{
|
|
aReporter.ReportTail( _( "Checking bus conflicts...\n" ), RPT_SEVERITY_INFO );
|
|
TestConflictingBusAliases();
|
|
}
|
|
|
|
// The connection graph has a whole set of ERC checks it can run
|
|
aReporter.ReportTail( _( "Checking conflicts...\n" ) );
|
|
m_parent->RecalculateConnections( NO_CLEANUP );
|
|
g_ConnectionGraph->RunERC();
|
|
|
|
// Test is all units of each multiunit component have the same footprint assigned.
|
|
if( g_ErcSettings->IsTestEnabled( ERCE_DIFFERENT_UNIT_FP ) )
|
|
{
|
|
aReporter.ReportTail( _( "Checking footprints...\n" ), RPT_SEVERITY_INFO );
|
|
TestMultiunitFootprints( sheets );
|
|
}
|
|
|
|
std::unique_ptr<NETLIST_OBJECT_LIST> objectsConnectedList( m_parent->BuildNetListBase() );
|
|
|
|
// Reset the connection type indicator
|
|
objectsConnectedList->ResetConnectionsType();
|
|
|
|
unsigned lastItemIdx = 0;
|
|
unsigned nextItemIdx = 0;
|
|
int MinConn = NOC;
|
|
|
|
// Check that a pin appears in only one net. This check is necessary because multi-unit
|
|
// components that have shared pins could be wired to different nets.
|
|
std::unordered_map<wxString, wxString> pin_to_net_map;
|
|
|
|
// The netlist generated by SCH_EDIT_FRAME::BuildNetListBase is sorted by net number, which
|
|
// means we can group netlist items into ranges that live in the same net. The range from
|
|
// nextItem to the current item (exclusive) needs to be checked against the current item.
|
|
// The lastItem variable is used as a helper to pass the last item's number from one loop
|
|
// iteration to the next, which simplifies the initial pass.
|
|
aReporter.ReportTail( _( "Checking connections...\n" ), RPT_SEVERITY_INFO );
|
|
for( unsigned itemIdx = 0; itemIdx < objectsConnectedList->size(); itemIdx++ )
|
|
{
|
|
auto item = objectsConnectedList->GetItem( itemIdx );
|
|
auto lastItem = objectsConnectedList->GetItem( lastItemIdx );
|
|
|
|
auto lastNet = lastItem->GetNet();
|
|
auto net = item->GetNet();
|
|
|
|
wxASSERT_MSG( lastNet <= net, wxT( "Netlist not correctly ordered" ) );
|
|
|
|
if( lastNet != net )
|
|
{
|
|
// New net found:
|
|
MinConn = NOC;
|
|
nextItemIdx = itemIdx;
|
|
}
|
|
|
|
switch( item->m_Type )
|
|
{
|
|
// These items do not create erc problems
|
|
case NETLIST_ITEM::ITEM_UNSPECIFIED:
|
|
case NETLIST_ITEM::SEGMENT:
|
|
case NETLIST_ITEM::BUS:
|
|
case NETLIST_ITEM::JUNCTION:
|
|
case NETLIST_ITEM::LABEL:
|
|
case NETLIST_ITEM::BUSLABELMEMBER:
|
|
case NETLIST_ITEM::PINLABEL:
|
|
case NETLIST_ITEM::GLOBBUSLABELMEMBER:
|
|
break;
|
|
|
|
// TODO(JE) Port this to the new system
|
|
case NETLIST_ITEM::PIN:
|
|
{
|
|
// Check if this pin has appeared before on a different net
|
|
if( item->m_Link && g_ErcSettings->IsTestEnabled( ERCE_DIFFERENT_UNIT_NET ) )
|
|
{
|
|
wxString ref = item->GetComponentParent()->GetRef( &item->m_SheetPath );
|
|
wxString pin_name = ref + "_" + item->m_PinNum;
|
|
wxString msg;
|
|
|
|
if( pin_to_net_map.count( pin_name ) == 0 )
|
|
{
|
|
pin_to_net_map[pin_name] = item->GetNetName();
|
|
}
|
|
else if( pin_to_net_map[pin_name] != item->GetNetName() )
|
|
{
|
|
msg.Printf( _( "Pin %s on %s is connected to both %s and %s" ),
|
|
item->m_PinNum,
|
|
ref,
|
|
pin_to_net_map[pin_name],
|
|
item->GetNetName() );
|
|
|
|
SCH_MARKER* marker = new SCH_MARKER( MARKER_BASE::MARKER_ERC );
|
|
marker->SetData( ERCE_DIFFERENT_UNIT_NET, item->m_Start, msg, item->m_Start );
|
|
item->m_SheetPath.LastScreen()->Append( marker );
|
|
}
|
|
}
|
|
|
|
// Look for ERC problems between pins:
|
|
TestOthersItems( objectsConnectedList.get(), itemIdx, nextItemIdx, &MinConn );
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
lastItemIdx = itemIdx;
|
|
}
|
|
|
|
// Test similar labels (i;e. labels which are identical when
|
|
// using case insensitive comparisons)
|
|
if( g_ErcSettings->IsTestEnabled( ERCE_SIMILAR_LABELS ) )
|
|
{
|
|
aReporter.ReportTail( _( "Checking labels...\n" ), RPT_SEVERITY_INFO );
|
|
objectsConnectedList->TestforSimilarLabels();
|
|
}
|
|
|
|
if( g_ErcSettings->IsTestEnabled( ERCE_UNRESOLVED_VARIABLE ) )
|
|
TestTextVars();
|
|
|
|
// Display diags:
|
|
m_markerTreeModel->SetProvider( m_markerProvider );
|
|
|
|
// Displays global results:
|
|
updateDisplayedCounts();
|
|
|
|
// Display new markers from the current screen:
|
|
KIGFX::VIEW* view = m_parent->GetCanvas()->GetView();
|
|
|
|
for( auto item : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
|
|
view->Add( item );
|
|
|
|
m_parent->GetCanvas()->Refresh();
|
|
|
|
// Display message
|
|
aReporter.ReportTail( _( "Finished" ), RPT_SEVERITY_INFO );
|
|
}
|
|
|
|
|
|
void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent )
|
|
{
|
|
const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() );
|
|
SCH_SHEET_LIST sheetList( g_RootSheet );
|
|
SCH_SHEET_PATH sheet;
|
|
SCH_ITEM* item = sheetList.GetItem( itemID, &sheet );
|
|
|
|
if( item )
|
|
{
|
|
WINDOW_THAWER thawer( m_parent );
|
|
|
|
if( sheet != m_parent->GetCurrentSheet() )
|
|
{
|
|
m_parent->GetToolManager()->RunAction( ACTIONS::cancelInteractive, true );
|
|
m_parent->GetToolManager()->RunAction( EE_ACTIONS::clearSelection, true );
|
|
|
|
m_parent->SetCurrentSheet( sheet );
|
|
m_parent->DisplayCurrentSheet();
|
|
sheet.LastScreen()->SetZoom( m_parent->GetScreen()->GetZoom() );
|
|
m_parent->RedrawScreen( (wxPoint) m_parent->GetScreen()->m_ScrollCenter, false );
|
|
}
|
|
|
|
m_parent->FocusOnItem( item );
|
|
RedrawDrawPanel();
|
|
}
|
|
|
|
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;
|
|
|
|
RC_ITEM* rcItem = node->m_RcItem;
|
|
wxString listName;
|
|
wxMenu menu;
|
|
|
|
switch( GetSeverity( rcItem->GetErrorCode() ) )
|
|
{
|
|
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();
|
|
|
|
if( GetSeverity( rcItem->GetErrorCode() ) == RPT_SEVERITY_WARNING )
|
|
{
|
|
menu.Append( 3, wxString::Format( _( "Change severity to Error for all '%s' violations" ),
|
|
rcItem->GetErrorText(),
|
|
_( "Violation severities can also be edited in the Board Setup... dialog" ) ) );
|
|
}
|
|
else
|
|
{
|
|
menu.Append( 4, wxString::Format( _( "Change severity to Warning for all '%s' violations" ),
|
|
rcItem->GetErrorText(),
|
|
_( "Violation severities can also be edited in the Board Setup... dialog" ) ) );
|
|
}
|
|
|
|
menu.Append( 5, wxString::Format( _( "Ignore all '%s' violations" ),
|
|
rcItem->GetErrorText() ),
|
|
_( "Violations will not be checked or reported" ) );
|
|
|
|
menu.AppendSeparator();
|
|
|
|
menu.Append( 6, _( "Edit violation severities..." ), _( "Open the Schematic Setup... dialog" ) );
|
|
|
|
switch( GetPopupMenuSelectionFromUser( menu ) )
|
|
{
|
|
case 1:
|
|
node->m_RcItem->GetParent()->SetExcluded( false );
|
|
|
|
// Update view
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
|
|
updateDisplayedCounts();
|
|
break;
|
|
|
|
case 2:
|
|
node->m_RcItem->GetParent()->SetExcluded( true );
|
|
|
|
// 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 );
|
|
|
|
updateDisplayedCounts();
|
|
break;
|
|
|
|
case 3:
|
|
SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_ERROR );
|
|
|
|
// Rebuild model and view
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markerProvider );
|
|
updateDisplayedCounts();
|
|
break;
|
|
|
|
case 4:
|
|
SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_WARNING );
|
|
|
|
// Rebuild model and view
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markerProvider );
|
|
updateDisplayedCounts();
|
|
break;
|
|
|
|
case 5:
|
|
{
|
|
SetSeverity( rcItem->GetErrorCode(), RPT_SEVERITY_IGNORE );
|
|
|
|
SCH_SCREENS ScreenList;
|
|
ScreenList.DeleteMarkers( MARKER_BASE::MARKER_ERC, rcItem->GetErrorCode() );
|
|
|
|
// Rebuild model and view
|
|
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->SetProvider( m_markerProvider );
|
|
updateDisplayedCounts();
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
m_parent->DoShowSchematicSetupDialog( _( "Violation Severity" ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
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();
|
|
|
|
// Set the provider's severity levels through the TreeModel so that the old tree
|
|
// can be torn down before the severity changes.
|
|
//
|
|
// It's not clear this is required, but we've had a lot of issues with wxDataView
|
|
// being cranky on various platforms.
|
|
|
|
m_markerTreeModel->SetSeverities( m_severities );
|
|
|
|
updateDisplayedCounts();
|
|
}
|
|
|
|
|
|
void DIALOG_ERC::deleteAllMarkers()
|
|
{
|
|
// Clear current selection list to avoid selection of deleted items
|
|
m_parent->GetToolManager()->RunAction( EE_ACTIONS::clearSelection, true );
|
|
|
|
m_markerTreeModel->DeleteAllItems();
|
|
}
|
|
|
|
|
|
void DIALOG_ERC::OnSaveReport( wxCommandEvent& aEvent )
|
|
{
|
|
wxFileName fn( "./ERC." + ReportFileExtension );
|
|
|
|
wxFileDialog dlg( this, _( "Save Report to File" ), fn.GetPath(), fn.GetFullName(),
|
|
ReportFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
|
|
if( dlg.ShowModal() != wxID_OK )
|
|
return;
|
|
|
|
fn = dlg.GetPath();
|
|
|
|
if( fn.GetExt().IsEmpty() )
|
|
fn.SetExt( ReportFileExtension );
|
|
|
|
if( !fn.IsAbsolute() )
|
|
{
|
|
wxString prj_path = Prj().GetProjectPath();
|
|
fn.MakeAbsolute( prj_path );
|
|
}
|
|
|
|
if( writeReport( fn.GetFullPath() ) )
|
|
{
|
|
m_MessagesList->AppendText( wxString::Format( _( "Report file '%s' created\n" ),
|
|
fn.GetFullPath() ) );
|
|
}
|
|
else
|
|
{
|
|
DisplayError( this, wxString::Format( _( "Unable to create report file '%s'" ),
|
|
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() );
|
|
|
|
int err_count = 0;
|
|
int warn_count = 0;
|
|
int total_count = 0;
|
|
SCH_SHEET_LIST sheetList( g_RootSheet );
|
|
|
|
for( unsigned i = 0; i < sheetList.size(); i++ )
|
|
{
|
|
msg << wxString::Format( _( "\n***** Sheet %s\n" ), sheetList[i].PathHumanReadable() );
|
|
|
|
for( auto aItem : sheetList[i].LastScreen()->Items().OfType( SCH_MARKER_T ) )
|
|
{
|
|
auto marker = static_cast<const SCH_MARKER*>( aItem );
|
|
|
|
if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC )
|
|
continue;
|
|
|
|
total_count++;
|
|
|
|
switch( g_ErcSettings->m_Severities[ marker->GetRCItem()->GetErrorCode() ] )
|
|
{
|
|
case RPT_SEVERITY_ERROR: err_count++; break;
|
|
case RPT_SEVERITY_WARNING: warn_count++; break;
|
|
default: break;
|
|
}
|
|
|
|
msg << marker->GetRCItem()->ShowReport( GetUserUnits() );
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
wxDialog* InvokeDialogERC( SCH_EDIT_FRAME* aCaller )
|
|
{
|
|
// This is a modeless dialog, so new it rather than instantiating on stack.
|
|
DIALOG_ERC* dlg = new DIALOG_ERC( aCaller );
|
|
|
|
dlg->Show( true );
|
|
|
|
return dlg; // wxDialog is information hiding about DIALOG_ERC.
|
|
}
|