Improve simulation error reporting.
1) More REPORTER, less exception processing 2) Remove UI calls from SPICE_MODEL 3) Don't replace netlist with errors; show both 4) Don't bail out of netlist generation after single error Fixes https://gitlab.com/kicad/code/kicad/issues/14295
This commit is contained in:
parent
8b144539e8
commit
6d296038f3
|
@ -140,6 +140,9 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
|
|||
wxString pinMap;
|
||||
bool storeInValue = false;
|
||||
|
||||
wxString msg;
|
||||
WX_STRING_REPORTER reporter( &msg );
|
||||
|
||||
// Infer RLC and VI models if they aren't specified
|
||||
if( SIM_MODEL::InferSimModel( m_symbol, &m_fields, false, SIM_VALUE_GRAMMAR::NOTATION::SI,
|
||||
&deviceType, &modelType, &modelParams, &pinMap ) )
|
||||
|
@ -184,7 +187,7 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
|
|||
if( !loadLibrary( libraryFilename ) )
|
||||
{
|
||||
m_libraryPathText->ChangeValue( libraryFilename );
|
||||
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields );
|
||||
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields, &reporter );
|
||||
m_libraryModelsMgr.CreateModel( nullptr, sourcePins, m_fields );
|
||||
|
||||
m_modelNameChoice->Append( _( "<unknown>" ) );
|
||||
|
@ -260,25 +263,32 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
|
|||
{
|
||||
// The model is sourced from the instance.
|
||||
m_useInstanceModelRadioButton->SetValue( true );
|
||||
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields );
|
||||
|
||||
msg.clear();
|
||||
m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields, &reporter );
|
||||
|
||||
if( reporter.HasMessage() )
|
||||
DisplayErrorMessage( this, msg );
|
||||
}
|
||||
|
||||
m_builtinModelsMgr.SetReporter( &reporter );
|
||||
|
||||
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
|
||||
{
|
||||
wxString msg;
|
||||
WX_STRING_REPORTER reporter( &msg );
|
||||
|
||||
m_builtinModelsMgr.SetReporter( &reporter );
|
||||
|
||||
if( m_useInstanceModelRadioButton->GetValue() && type == m_curModelType )
|
||||
m_builtinModelsMgr.CreateModel( m_fields, sourcePins, false );
|
||||
else
|
||||
m_builtinModelsMgr.CreateModel( type, sourcePins );
|
||||
|
||||
if( reporter.HasMessage() )
|
||||
{
|
||||
DisplayErrorMessage( this, _( "Failed to read simulation model from fields." )
|
||||
+ wxT( "\n\n" ) + msg );
|
||||
msg.clear();
|
||||
m_builtinModelsMgr.CreateModel( m_fields, sourcePins, false );
|
||||
|
||||
if( reporter.HasMessage() )
|
||||
{
|
||||
DisplayErrorMessage( this, _( "Failed to read simulation model from fields." )
|
||||
+ wxT( "\n\n" ) + msg );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_builtinModelsMgr.CreateModel( type, sourcePins );
|
||||
}
|
||||
|
||||
SIM_MODEL::DEVICE_T deviceTypeT = SIM_MODEL::TypeInfo( type ).deviceType;
|
||||
|
|
|
@ -83,20 +83,13 @@ namespace NETLIST_EXPORTER_SPICE_PARSER
|
|||
|
||||
std::string NAME_GENERATOR::Generate( const std::string& aProposedName )
|
||||
{
|
||||
if( !m_names.count( aProposedName ) )
|
||||
return aProposedName;
|
||||
std::string name = aProposedName;
|
||||
int ii = 1;
|
||||
|
||||
for( uint64_t i = 1; i < UINT64_MAX; ++i )
|
||||
{
|
||||
std::string name = fmt::format( "{}#{}", aProposedName, i );
|
||||
while( m_names.count( name ) )
|
||||
name = fmt::format( "{}#{}", aProposedName, ii++ );
|
||||
|
||||
if( !m_names.count( name ) )
|
||||
return name;
|
||||
}
|
||||
|
||||
// Should never happen.
|
||||
THROW_IO_ERROR( wxString::Format( _( "Failed to generate a name for '%s': exceeded UINT64_MAX" ),
|
||||
aProposedName ) );
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,8 +119,7 @@ bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsign
|
|||
// Cleanup list to avoid duplicate if the netlist exporter is run more than once.
|
||||
m_rawIncludes.clear();
|
||||
|
||||
if( !ReadSchematicAndLibraries( aNetlistOptions, aReporter ) )
|
||||
return false;
|
||||
bool result = ReadSchematicAndLibraries( aNetlistOptions, aReporter );
|
||||
|
||||
WriteHead( aFormatter, aNetlistOptions );
|
||||
|
||||
|
@ -142,7 +134,7 @@ bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsign
|
|||
|
||||
WriteTail( aFormatter, aNetlistOptions );
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -165,6 +157,8 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
|
|||
std::set<std::string> refNames; // Set of reference names to check for duplication.
|
||||
int ncCounter = 1;
|
||||
|
||||
m_libMgr.SetReporter( &aReporter );
|
||||
|
||||
ReadDirectives( aNetlistOptions );
|
||||
|
||||
m_nets.clear();
|
||||
|
@ -240,27 +234,19 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
|
|||
wxString modelParams;
|
||||
wxString pinMap;
|
||||
|
||||
try
|
||||
{
|
||||
readRefName( sheet, *symbol, spiceItem, refNames );
|
||||
readModel( sheet, *symbol, spiceItem );
|
||||
readPinNumbers( *symbol, spiceItem, pins );
|
||||
readPinNetNames( *symbol, spiceItem, pins, ncCounter );
|
||||
readRefName( sheet, *symbol, spiceItem, refNames );
|
||||
readModel( sheet, *symbol, spiceItem );
|
||||
readPinNumbers( *symbol, spiceItem, pins );
|
||||
readPinNetNames( *symbol, spiceItem, pins, ncCounter );
|
||||
|
||||
// TODO: transmission line handling?
|
||||
// TODO: transmission line handling?
|
||||
|
||||
m_items.push_back( std::move( spiceItem ) );
|
||||
}
|
||||
catch( const IO_ERROR& e )
|
||||
{
|
||||
msg.Printf( _( "Error reading simulation model from symbol '%s':\n%s" ),
|
||||
symbol->GetRef( &sheet ),
|
||||
e.Problem() );
|
||||
aReporter.Report( msg, RPT_SEVERITY_ERROR );
|
||||
}
|
||||
m_items.push_back( std::move( spiceItem ) );
|
||||
}
|
||||
}
|
||||
|
||||
m_libMgr.SetReporter( nullptr );
|
||||
|
||||
return !aReporter.HasMessage();
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath, REPORTER* aRepor
|
|||
|
||||
for( KIBIS_COMPONENT& kcomp : m_kibis.m_components )
|
||||
{
|
||||
m_models.push_back( SIM_MODEL::Create( SIM_MODEL::TYPE::KIBIS_DEVICE, pins, nullptr ) );
|
||||
m_models.push_back( SIM_MODEL::Create( SIM_MODEL::TYPE::KIBIS_DEVICE, pins, aReporter ) );
|
||||
m_modelNames.emplace_back( kcomp.m_name );
|
||||
|
||||
SIM_MODEL_KIBIS* libcomp = dynamic_cast<SIM_MODEL_KIBIS*>( m_models.back().get() );
|
||||
|
|
|
@ -361,11 +361,13 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType )
|
|||
}
|
||||
|
||||
|
||||
template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<SCH_FIELD>& aFields );
|
||||
template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<LIB_FIELD>& aFields );
|
||||
template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<SCH_FIELD>& aFields,
|
||||
REPORTER* aReporter );
|
||||
template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<LIB_FIELD>& aFields,
|
||||
REPORTER* aReporter );
|
||||
|
||||
template <typename T>
|
||||
TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<T>& aFields )
|
||||
TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<T>& aFields, REPORTER* aReporter )
|
||||
{
|
||||
std::string deviceTypeFieldValue = GetFieldValue( &aFields, SIM_DEVICE_TYPE_FIELD );
|
||||
std::string typeFieldValue = GetFieldValue( &aFields, SIM_TYPE_FIELD );
|
||||
|
@ -392,6 +394,22 @@ TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<T>& aFields )
|
|||
if( typeFromLegacyFields != TYPE::NONE )
|
||||
return typeFromLegacyFields;
|
||||
|
||||
if( aReporter )
|
||||
{
|
||||
if( aFields.size() > REFERENCE_FIELD )
|
||||
{
|
||||
aReporter->Report( wxString::Format( _( "No simulation model definition found for "
|
||||
"symbol '%s'." ),
|
||||
aFields[REFERENCE_FIELD].GetText() ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
}
|
||||
else
|
||||
{
|
||||
aReporter->Report( _( "No simulation model definition found." ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
}
|
||||
}
|
||||
|
||||
return TYPE::NONE;
|
||||
}
|
||||
|
||||
|
@ -455,10 +473,7 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( TYPE aType, const std::vector<LIB_
|
|||
}
|
||||
catch( IO_ERROR& err )
|
||||
{
|
||||
if( aReporter )
|
||||
aReporter->Report( err.What(), RPT_SEVERITY_ERROR );
|
||||
else
|
||||
DisplayErrorMessage( nullptr, err.What() );
|
||||
wxFAIL_MSG( "Shouldn't throw reading empty fields!" );
|
||||
}
|
||||
|
||||
return model;
|
||||
|
@ -481,19 +496,16 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL* aBaseModel,
|
|||
else
|
||||
model = Create( type );
|
||||
|
||||
if( aBaseModel )
|
||||
model->SetBaseModel( *aBaseModel );
|
||||
|
||||
try
|
||||
{
|
||||
if( aBaseModel )
|
||||
model->SetBaseModel( *aBaseModel );
|
||||
|
||||
model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
|
||||
}
|
||||
catch( IO_ERROR& err )
|
||||
{
|
||||
if( aReporter )
|
||||
aReporter->Report( err.What(), RPT_SEVERITY_ERROR );
|
||||
else
|
||||
DisplayErrorMessage( nullptr, err.What() );
|
||||
wxFAIL_MSG( "Shouldn't throw reading empty fields!" );
|
||||
}
|
||||
|
||||
return model;
|
||||
|
@ -506,7 +518,7 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL* aBaseModel,
|
|||
const std::vector<T>& aFields,
|
||||
REPORTER* aReporter )
|
||||
{
|
||||
TYPE type = ReadTypeFromFields( aFields );
|
||||
TYPE type = ReadTypeFromFields( aFields, aReporter );
|
||||
|
||||
// If the model has a specified type, it takes priority over the type of its base class.
|
||||
if( type == TYPE::NONE && aBaseModel )
|
||||
|
@ -523,19 +535,23 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL* aBaseModel,
|
|||
else
|
||||
model = Create( type );
|
||||
|
||||
if( aBaseModel )
|
||||
model->SetBaseModel( *aBaseModel );
|
||||
|
||||
try
|
||||
{
|
||||
if( aBaseModel )
|
||||
model->SetBaseModel( *aBaseModel );
|
||||
|
||||
model->ReadDataFields( &aFields, aPins );
|
||||
}
|
||||
catch( IO_ERROR& err )
|
||||
{
|
||||
if( aReporter )
|
||||
aReporter->Report( err.What(), RPT_SEVERITY_ERROR );
|
||||
else
|
||||
DisplayErrorMessage( nullptr, err.What() );
|
||||
{
|
||||
aReporter->Report( wxString::Format( _( "Error reading simulation model from "
|
||||
"symbol '%s':\n%s" ),
|
||||
aFields[REFERENCE_FIELD].GetText(),
|
||||
err.Problem() ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
|
@ -557,7 +573,7 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& aFields,
|
|||
const std::vector<LIB_PIN*>& aPins,
|
||||
bool aResolved, REPORTER* aReporter )
|
||||
{
|
||||
TYPE type = ReadTypeFromFields( aFields );
|
||||
TYPE type = ReadTypeFromFields( aFields, aReporter );
|
||||
std::unique_ptr<SIM_MODEL> model = SIM_MODEL::Create( type );
|
||||
|
||||
try
|
||||
|
@ -589,11 +605,15 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& aFields,
|
|||
}
|
||||
catch( const IO_ERROR& err )
|
||||
{
|
||||
// We own the pin syntax, so if we can't parse it then there's an error, full stop.
|
||||
// We own the pin syntax, so if we can't parse it then there's an error.
|
||||
if( aReporter )
|
||||
aReporter->Report( err.Problem(), RPT_SEVERITY_ERROR );
|
||||
else
|
||||
THROW_IO_ERROR( err.Problem() );
|
||||
{
|
||||
aReporter->Report( wxString::Format( _( "Error reading simulation model from "
|
||||
"symbol '%s':\n%s" ),
|
||||
aFields[REFERENCE_FIELD].GetText(),
|
||||
err.Problem() ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,21 +746,8 @@ void SIM_MODEL::AddParam( const PARAM::INFO& aInfo )
|
|||
|
||||
void SIM_MODEL::SetBaseModel( const SIM_MODEL& aBaseModel )
|
||||
{
|
||||
auto describe =
|
||||
[]( const SIM_MODEL* aModel )
|
||||
{
|
||||
return fmt::format( "{} ({})",
|
||||
aModel->GetDeviceInfo().fieldValue,
|
||||
aModel->GetTypeInfo().description );
|
||||
};
|
||||
|
||||
if( GetType() != aBaseModel.GetType() )
|
||||
{
|
||||
THROW_IO_ERROR( wxString::Format( _( "Simulation model type must be the same as of its "
|
||||
"base class: '%s', but is '%s'" ),
|
||||
describe( &aBaseModel ),
|
||||
describe( this ) ) );
|
||||
}
|
||||
wxASSERT_MSG( GetType() == aBaseModel.GetType(),
|
||||
wxS( "Simulation model type must be the same as its base class!" ) );
|
||||
|
||||
m_baseModel = &aBaseModel;
|
||||
}
|
||||
|
|
|
@ -384,7 +384,7 @@ public:
|
|||
|
||||
|
||||
template <typename T>
|
||||
static TYPE ReadTypeFromFields( const std::vector<T>& aFields );
|
||||
static TYPE ReadTypeFromFields( const std::vector<T>& aFields, REPORTER* aReporter );
|
||||
|
||||
template <typename T>
|
||||
static TYPE InferTypeFromLegacyFields( const std::vector<T>& aFields );
|
||||
|
|
|
@ -55,7 +55,6 @@ std::vector<std::string> SPICE_GENERATOR_NGSPICE::CurrentNames( const SPICE_ITEM
|
|||
return SPICE_GENERATOR::CurrentNames( aItem );
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "Unhandled model device type in SIM_MODEL_NGSPICE" );
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,10 @@ std::string SPICE_GENERATOR::ModelLine( const SPICE_ITEM& aItem ) const
|
|||
value ) );
|
||||
}
|
||||
|
||||
// Don't send SPICE empty models.
|
||||
if( result.length() == indentLength + 1 /* line ending */ )
|
||||
result.clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <kiway.h>
|
||||
#include <confirm.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
#include <widgets/wx_html_report_box.h>
|
||||
#include <project/project_file.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <sim/simulator_frame.h>
|
||||
|
@ -350,45 +351,74 @@ public:
|
|||
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL ) );
|
||||
}
|
||||
|
||||
NETLIST_VIEW_DIALOG( wxWindow* parent, const wxString& source) :
|
||||
NETLIST_VIEW_DIALOG( wxWindow* parent ) :
|
||||
DIALOG_SHIM( parent, wxID_ANY, _( "SPICE Netlist" ), wxDefaultPosition,
|
||||
wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
|
||||
wxSize( 800, 800 ), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
|
||||
m_textCtrl( nullptr ),
|
||||
m_reporter( nullptr )
|
||||
{
|
||||
wxStyledTextCtrl* textCtrl = new wxStyledTextCtrl( this, wxID_ANY );
|
||||
textCtrl->SetMinSize( wxSize( 600, 400 ) );
|
||||
m_splitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||
wxSP_LIVE_UPDATE | wxSP_NOBORDER | wxSP_3DSASH );
|
||||
|
||||
textCtrl->SetMarginWidth( MARGIN_LINE_NUMBERS, 50 );
|
||||
textCtrl->StyleSetForeground( wxSTC_STYLE_LINENUMBER, wxColour( 75, 75, 75 ) );
|
||||
textCtrl->StyleSetBackground( wxSTC_STYLE_LINENUMBER, wxColour( 220, 220, 220 ) );
|
||||
textCtrl->SetMarginType( MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER );
|
||||
//Avoid the splitter window being assigned as the Parent to additional windows
|
||||
m_splitter->SetExtraStyle( wxWS_EX_TRANSIENT );
|
||||
|
||||
m_textCtrl = new wxStyledTextCtrl( m_splitter, wxID_ANY );
|
||||
|
||||
m_textCtrl->SetMarginWidth( MARGIN_LINE_NUMBERS, 50 );
|
||||
m_textCtrl->StyleSetForeground( wxSTC_STYLE_LINENUMBER, wxColour( 75, 75, 75 ) );
|
||||
m_textCtrl->StyleSetBackground( wxSTC_STYLE_LINENUMBER, wxColour( 220, 220, 220 ) );
|
||||
m_textCtrl->SetMarginType( MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER );
|
||||
|
||||
wxFont fixedFont = KIUI::GetMonospacedUIFont();
|
||||
|
||||
for( int i = 0; i < wxSTC_STYLE_MAX; ++i )
|
||||
textCtrl->StyleSetFont( i, fixedFont );
|
||||
m_textCtrl->StyleSetFont( i, fixedFont );
|
||||
|
||||
textCtrl->StyleClearAll(); // Addresses a bug in wx3.0 where styles are not correctly set
|
||||
m_textCtrl->StyleClearAll(); // Addresses a bug in wx3.0 where styles are not correctly set
|
||||
|
||||
textCtrl->SetWrapMode( wxSTC_WRAP_WORD );
|
||||
m_textCtrl->SetWrapMode( wxSTC_WRAP_WORD );
|
||||
m_textCtrl->SetLexer( wxSTC_LEX_SPICE );
|
||||
m_textCtrl->SetMinSize( wxSize( 40, 40 ) );
|
||||
m_textCtrl->SetSize( wxSize( 40, 40 ) );
|
||||
|
||||
textCtrl->SetText( source );
|
||||
m_reporter = new WX_HTML_REPORT_BOX( m_splitter, wxID_ANY );
|
||||
m_reporter->SetMinSize( wxSize( 40, 40 ) );
|
||||
m_reporter->SetSize( wxSize( 40, 40 ) );
|
||||
|
||||
textCtrl->SetLexer( wxSTC_LEX_SPICE );
|
||||
|
||||
textCtrl->SetEditable( false );
|
||||
m_splitter->SetMinimumPaneSize( 40 );
|
||||
m_splitter->SetSashPosition( 760 );
|
||||
m_splitter->SetSashGravity( 0.9 );
|
||||
m_splitter->SplitHorizontally( m_textCtrl, m_reporter );
|
||||
|
||||
wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
|
||||
sizer->Add( textCtrl, 1, wxEXPAND | wxALL, 5 );
|
||||
sizer->Add( m_splitter, 1, wxEXPAND | wxALL, 5 );
|
||||
SetSizer( sizer );
|
||||
Layout();
|
||||
|
||||
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( NETLIST_VIEW_DIALOG::onClose ),
|
||||
nullptr, this );
|
||||
|
||||
m_scintillaTricks = std::make_unique<SCINTILLA_TRICKS>( textCtrl, wxT( "{}" ), false );
|
||||
m_scintillaTricks = std::make_unique<SCINTILLA_TRICKS>( m_textCtrl, wxT( "{}" ), false );
|
||||
|
||||
finishDialogSettings();
|
||||
}
|
||||
|
||||
void SetNetlist( const wxString& aSource )
|
||||
{
|
||||
m_textCtrl->SetText( aSource );
|
||||
m_textCtrl->SetEditable( false );
|
||||
|
||||
m_reporter->Flush();
|
||||
}
|
||||
|
||||
REPORTER* GetReporter() { return m_reporter; }
|
||||
|
||||
private:
|
||||
wxSplitterWindow* m_splitter;
|
||||
wxStyledTextCtrl* m_textCtrl;
|
||||
WX_HTML_REPORT_BOX* m_reporter;
|
||||
|
||||
std::unique_ptr<SCINTILLA_TRICKS> m_scintillaTricks;
|
||||
};
|
||||
|
||||
|
@ -411,14 +441,13 @@ int SIMULATOR_CONTROL::ShowNetlist( const TOOL_EVENT& aEvent )
|
|||
if( m_schematicFrame == nullptr || m_simulator == nullptr )
|
||||
return -1;
|
||||
|
||||
wxString errors;
|
||||
WX_STRING_REPORTER reporter( &errors );
|
||||
STRING_FORMATTER formatter;
|
||||
STRING_FORMATTER formatter;
|
||||
NETLIST_VIEW_DIALOG dlg( m_simulatorFrame );
|
||||
|
||||
m_circuitModel->SetSimOptions( m_simulatorFrame->GetCurrentOptions() );
|
||||
m_circuitModel->GetNetlist( &formatter, reporter );
|
||||
m_circuitModel->GetNetlist( &formatter, *dlg.GetReporter() );
|
||||
|
||||
NETLIST_VIEW_DIALOG dlg( m_simulatorFrame, errors.IsEmpty() ? wxString( formatter.GetString() ) : errors );
|
||||
dlg.SetNetlist( wxString( formatter.GetString() ) );
|
||||
dlg.ShowModal();
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue