Fix crash when grid tries to access deleted field.

This commit is contained in:
Jeff Young 2022-12-11 22:59:27 +00:00
parent 419fe236ad
commit e890986e01
5 changed files with 110 additions and 31 deletions

View File

@ -606,24 +606,67 @@ void DIALOG_LIB_SYMBOL_PROPERTIES::OnMoveDown( wxCommandEvent& event )
void DIALOG_LIB_SYMBOL_PROPERTIES::OnEditSpiceModel( wxCommandEvent& event ) void DIALOG_LIB_SYMBOL_PROPERTIES::OnEditSpiceModel( wxCommandEvent& event )
{ {
#ifdef KICAD_SPICE #ifdef KICAD_SPICE
int diff = m_fields->size(); if( !m_grid->CommitPendingChanges() )
return;
DIALOG_SIM_MODEL dialog( this, *m_libEntry, *m_fields ); std::vector<LIB_FIELD> fields;
for( const LIB_FIELD& field : *m_fields )
fields.emplace_back( field );
DIALOG_SIM_MODEL dialog( this, *m_libEntry, fields );
if( dialog.ShowModal() != wxID_OK ) if( dialog.ShowModal() != wxID_OK )
return; return;
diff = (int) m_fields->size() - diff; // Add in any new fields
for( const LIB_FIELD& editedField : fields )
{
bool found = false;
if( diff > 0 ) for( LIB_FIELD& existingField : *m_fields )
{ {
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, diff ); if( existingField.GetName() == editedField.GetName() )
m_grid->ProcessTableMessage( msg ); {
found = true;
existingField.SetText( editedField.GetText() );
break;
}
}
if( !found )
{
m_fields->emplace_back( editedField );
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
m_grid->ProcessTableMessage( msg );
}
} }
else if( diff < 0 )
// Remove any deleted fields
for( int ii = (int) m_fields->size() - 1; ii >= 0; /* advance in loop */ )
{ {
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, -diff ); LIB_FIELD& existingField = m_fields->at( ii );
m_grid->ProcessTableMessage( msg ); bool found = false;
for( LIB_FIELD& editedField : fields )
{
if( editedField.GetName() == existingField.GetName() )
{
found = true;
break;
}
}
if( found )
{
ii--;
}
else
{
m_fields->erase( m_fields->begin() + ii );
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, ii, 1 );
m_grid->ProcessTableMessage( msg );
}
} }
OnModify(); OnModify();

View File

@ -362,22 +362,22 @@ int DIALOG_SIM_COMMAND::ShowModal()
{ m_noiseRef, m_noiseRef->GetStringSelection() } { m_noiseRef, m_noiseRef->GetStringSelection() }
}; };
for( auto& c : cmbNet ) for( const std::pair<wxComboBox* const, wxString>& c : cmbNet )
c.first->Clear(); c.first->Clear();
for( const auto& net : m_circuitModel->GetNets() ) for( const std::string& net : m_circuitModel->GetNets() )
{ {
for( auto& c : cmbNet ) for( const std::pair<wxComboBox* const, wxString>& c : cmbNet )
c.first->Append( net ); c.first->Append( net );
} }
// Try to restore the previous selection, if possible // Try to restore the previous selection, if possible
for( auto& c : cmbNet ) for( const std::pair<wxComboBox* const, wxString>& c : cmbNet )
{ {
int idx = c.first->FindString( c.second ); int idx = c.first->FindString( c.second );
if( idx != wxNOT_FOUND ) if( idx != wxNOT_FOUND )
c.first->SetSelection( idx ); c.first->SetSelection( idx );
} }
return DIALOG_SIM_COMMAND_BASE::ShowModal(); return DIALOG_SIM_COMMAND_BASE::ShowModal();

View File

@ -50,7 +50,6 @@ DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symb
: DIALOG_SIM_MODEL_BASE( aParent ), : DIALOG_SIM_MODEL_BASE( aParent ),
m_symbol( aSymbol ), m_symbol( aSymbol ),
m_fields( aFields ), m_fields( aFields ),
m_fieldsOrigin( aFields ),
m_libraryModelsMgr( Prj() ), m_libraryModelsMgr( Prj() ),
m_builtinModelsMgr( Prj() ), m_builtinModelsMgr( Prj() ),
m_prevModel( nullptr ), m_prevModel( nullptr ),
@ -314,8 +313,6 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataFromWindow()
curModel().WriteFields( m_fields ); curModel().WriteFields( m_fields );
m_fieldsOrigin = m_fields;
return true; return true;
} }

View File

@ -82,7 +82,7 @@ public:
MODEL MODEL
}; };
DIALOG_SIM_MODEL( wxWindow* aParent, T_symbol& aSymbol, std::vector<T_field>& aSchFields ); DIALOG_SIM_MODEL( wxWindow* aParent, T_symbol& aSymbol, std::vector<T_field>& aFields );
~DIALOG_SIM_MODEL(); ~DIALOG_SIM_MODEL();
@ -143,8 +143,7 @@ private:
private: private:
T_symbol& m_symbol; T_symbol& m_symbol;
std::vector<T_field> m_fields; // Local copy of the fields std::vector<T_field>& m_fields;
std::vector<T_field>& m_fieldsOrigin; // Pointer back to the source copy of the fields
SIM_LIB_MGR m_libraryModelsMgr; SIM_LIB_MGR m_libraryModelsMgr;
SIM_LIB_MGR m_builtinModelsMgr; SIM_LIB_MGR m_builtinModelsMgr;

View File

@ -544,24 +544,64 @@ void DIALOG_SYMBOL_PROPERTIES::OnEditSpiceModel( wxCommandEvent& event )
if( !m_fieldsGrid->CommitPendingChanges() ) if( !m_fieldsGrid->CommitPendingChanges() )
return; return;
int diff = m_fields->size(); std::vector<SCH_FIELD> fields;
DIALOG_SIM_MODEL dialog( this, *m_symbol, *m_fields ); for( const SCH_FIELD& field : *m_fields )
fields.emplace_back( field );
DIALOG_SIM_MODEL dialog( this, *m_symbol, fields );
if( dialog.ShowModal() != wxID_OK ) if( dialog.ShowModal() != wxID_OK )
return; return;
diff = (int) m_fields->size() - diff; // Add in any new fields
for( const SCH_FIELD& editedField : fields )
{
bool found = false;
if( diff > 0 ) for( SCH_FIELD& existingField : *m_fields )
{ {
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, diff ); if( existingField.GetName() == editedField.GetName() )
m_fieldsGrid->ProcessTableMessage( msg ); {
found = true;
existingField.SetText( editedField.GetText() );
break;
}
}
if( !found )
{
m_fields->emplace_back( editedField );
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
m_fieldsGrid->ProcessTableMessage( msg );
}
} }
else if( diff < 0 )
// Remove any deleted fields
for( int ii = (int) m_fields->size() - 1; ii >= 0; /* advance in loop */ )
{ {
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, -diff ); SCH_FIELD& existingField = m_fields->at( ii );
m_fieldsGrid->ProcessTableMessage( msg ); bool found = false;
for( SCH_FIELD& editedField : fields )
{
if( editedField.GetName() == existingField.GetName() )
{
found = true;
break;
}
}
if( found )
{
ii--;
}
else
{
m_fields->erase( m_fields->begin() + ii );
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, ii, 1 );
m_fieldsGrid->ProcessTableMessage( msg );
}
} }
OnModify(); OnModify();