Correctly handle deleting multiple selections in some grids.

Fixes https://gitlab.com/kicad/code/kicad/issues/9952
This commit is contained in:
Jeff Young 2021-12-12 17:27:40 +00:00
parent 0f728e4d67
commit 88fc6d25a7
9 changed files with 214 additions and 101 deletions

View File

@ -440,7 +440,9 @@ void DIALOG_CONFIGURE_PATHS::OnRemoveEnvVar( wxCommandEvent& event )
int curRow = m_EnvVars->GetGridCursorRow();
if( curRow < 0 || m_EnvVars->GetNumberRows() <= curRow )
{
return;
}
else if( ENV_VAR::IsEnvVarImmutable( m_EnvVars->GetCellValue( curRow, TV_NAME_COL ) ) )
{
wxBell();
@ -457,20 +459,31 @@ void DIALOG_CONFIGURE_PATHS::OnRemoveEnvVar( wxCommandEvent& event )
void DIALOG_CONFIGURE_PATHS::OnDeleteSearchPath( wxCommandEvent& event )
{
int curRow = m_SearchPaths->GetGridCursorRow();
wxArrayInt selectedRows = m_SearchPaths->GetSelectedRows();
if( curRow < 0 || m_SearchPaths->GetNumberRows() <= curRow )
if( selectedRows.empty() && m_SearchPaths->GetGridCursorRow() >= 0 )
selectedRows.push_back( m_SearchPaths->GetGridCursorRow() );
if( selectedRows.empty() )
return;
m_SearchPaths->CommitPendingChanges( true /* silent mode; we don't care if it's valid */ );
m_SearchPaths->DeleteRows( curRow, 1 );
// if there are still rows in grid, make previous row visible
if( m_SearchPaths->GetNumberRows() )
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
for( int row : selectedRows )
{
m_SearchPaths->MakeCellVisible( std::max( 0, curRow-1 ),
m_SearchPaths->GetGridCursorCol() );
m_SearchPaths->SetGridCursor( std::max( 0, curRow-1 ), m_SearchPaths->GetGridCursorCol() );
m_SearchPaths->DeleteRows( row, 1 );
// if there are still rows in grid, make previous row visible
if( m_SearchPaths->GetNumberRows() )
{
m_SearchPaths->MakeCellVisible( std::max( 0, row-1 ),
m_SearchPaths->GetGridCursorCol() );
m_SearchPaths->SetGridCursor( std::max( 0, row-1 ),
m_SearchPaths->GetGridCursorCol() );
}
}
}

View File

@ -631,6 +631,8 @@ void DIALOG_LIB_EDIT_PIN_TABLE::OnAddRow( wxCommandEvent& event )
void DIALOG_LIB_EDIT_PIN_TABLE::OnDeleteRow( wxCommandEvent& event )
{
// TODO: handle delete of multiple rows....
if( !m_grid->CommitPendingChanges() )
return;
@ -652,7 +654,6 @@ void DIALOG_LIB_EDIT_PIN_TABLE::OnDeleteRow( wxCommandEvent& event )
m_grid->SetGridCursor( curRow, m_grid->GetGridCursorCol() );
m_grid->SelectRow( curRow );
updateSummary();
}

View File

@ -65,6 +65,7 @@ DIALOG_LIB_SYMBOL_PROPERTIES::DIALOG_LIB_SYMBOL_PROPERTIES( SYMBOL_EDIT_FRAME* a
m_fields = new FIELDS_GRID_TABLE<LIB_FIELD>( this, aParent, m_grid, m_libEntry );
m_grid->SetTable( m_fields );
m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this ) );
m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
// Show/hide columns according to the user's preference
SYMBOL_EDITOR_SETTINGS* cfg = m_Parent->GetSettings();
@ -494,31 +495,42 @@ void DIALOG_LIB_SYMBOL_PROPERTIES::OnAddField( wxCommandEvent& event )
void DIALOG_LIB_SYMBOL_PROPERTIES::OnDeleteField( wxCommandEvent& event )
{
int curRow = m_grid->GetGridCursorRow();
wxArrayInt selectedRows = m_grid->GetSelectedRows();
if( curRow < 0 )
{
if( selectedRows.empty() && m_grid->GetGridCursorRow() >= 0 )
selectedRows.push_back( m_grid->GetGridCursorRow() );
if( selectedRows.empty() )
return;
}
else if( curRow < MANDATORY_FIELDS )
for( int row : selectedRows )
{
DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
MANDATORY_FIELDS ) );
return;
if( row < MANDATORY_FIELDS )
{
DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
MANDATORY_FIELDS ) );
return;
}
}
m_grid->CommitPendingChanges( true /* quiet mode */ );
m_fields->erase( m_fields->begin() + curRow );
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
// notify the grid
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, curRow, 1 );
m_grid->ProcessTableMessage( msg );
if( m_grid->GetNumberRows() > 0 )
for( int row : selectedRows )
{
m_grid->MakeCellVisible( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
m_grid->SetGridCursor( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
m_fields->erase( m_fields->begin() + row );
// notify the grid
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
m_grid->ProcessTableMessage( msg );
if( m_grid->GetNumberRows() > 0 )
{
m_grid->MakeCellVisible( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
m_grid->SetGridCursor( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
}
}
OnModify();

View File

@ -60,6 +60,7 @@ DIALOG_SHEET_PROPERTIES::DIALOG_SHEET_PROPERTIES( SCH_EDIT_FRAME* aParent, SCH_S
m_grid->SetTable( m_fields );
m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this ) );
m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
// Show/hide columns according to user's preference
auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
@ -715,29 +716,42 @@ void DIALOG_SHEET_PROPERTIES::OnAddField( wxCommandEvent& event )
void DIALOG_SHEET_PROPERTIES::OnDeleteField( wxCommandEvent& event )
{
int curRow = m_grid->GetGridCursorRow();
wxArrayInt selectedRows = m_grid->GetSelectedRows();
if( curRow < 0 )
if( selectedRows.empty() && m_grid->GetGridCursorRow() >= 0 )
selectedRows.push_back( m_grid->GetGridCursorRow() );
if( selectedRows.empty() )
return;
else if( curRow < SHEET_MANDATORY_FIELDS )
for( int row : selectedRows )
{
DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
SHEET_MANDATORY_FIELDS ) );
return;
if( row < SHEET_MANDATORY_FIELDS )
{
DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
SHEET_MANDATORY_FIELDS ) );
return;
}
}
m_grid->CommitPendingChanges( true /* quiet mode */ );
m_fields->erase( m_fields->begin() + curRow );
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
// notify the grid
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, curRow, 1 );
m_grid->ProcessTableMessage( msg );
if( m_grid->GetNumberRows() > 0 )
for( int row : selectedRows )
{
m_grid->MakeCellVisible( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
m_grid->SetGridCursor( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
m_fields->erase( m_fields->begin() + row );
// notify the grid
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
m_grid->ProcessTableMessage( msg );
if( m_grid->GetNumberRows() > 0 )
{
m_grid->MakeCellVisible( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
m_grid->SetGridCursor( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
}
}
}

View File

@ -315,6 +315,7 @@ DIALOG_SYMBOL_PROPERTIES::DIALOG_SYMBOL_PROPERTIES( SCH_EDIT_FRAME* aParent,
m_fieldsGrid->SetTable( m_fields );
m_fieldsGrid->PushEventHandler( new FIELDS_GRID_TRICKS( m_fieldsGrid, this ) );
m_fieldsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
// Show/hide columns according to user's preference
EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
@ -349,6 +350,7 @@ DIALOG_SYMBOL_PROPERTIES::DIALOG_SYMBOL_PROPERTIES( SCH_EDIT_FRAME* aParent,
}
m_pinGrid->PushEventHandler( new GRID_TRICKS( m_pinGrid ) );
m_pinGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
wxToolTip::Enable( true );
m_stdDialogButtonSizerOK->SetDefault();
@ -834,31 +836,42 @@ void DIALOG_SYMBOL_PROPERTIES::OnAddField( wxCommandEvent& event )
void DIALOG_SYMBOL_PROPERTIES::OnDeleteField( wxCommandEvent& event )
{
int curRow = m_fieldsGrid->GetGridCursorRow();
wxArrayInt selectedRows = m_fieldsGrid->GetSelectedRows();
if( curRow < 0 )
{
if( selectedRows.empty() && m_fieldsGrid->GetGridCursorRow() >= 0 )
selectedRows.push_back( m_fieldsGrid->GetGridCursorRow() );
if( selectedRows.empty() )
return;
}
else if( curRow < MANDATORY_FIELDS )
for( int row : selectedRows )
{
DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
MANDATORY_FIELDS ) );
return;
if( row < MANDATORY_FIELDS )
{
DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
MANDATORY_FIELDS ) );
return;
}
}
m_fieldsGrid->CommitPendingChanges( true /* quiet mode */ );
m_fields->erase( m_fields->begin() + curRow );
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
// notify the grid
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, curRow, 1 );
m_fieldsGrid->ProcessTableMessage( msg );
if( m_fieldsGrid->GetNumberRows() > 0 )
for( int row : selectedRows )
{
m_fieldsGrid->MakeCellVisible( std::max( 0, curRow-1 ), m_fieldsGrid->GetGridCursorCol() );
m_fieldsGrid->SetGridCursor( std::max( 0, curRow-1 ), m_fieldsGrid->GetGridCursorCol() );
m_fields->erase( m_fields->begin() + row );
// notify the grid
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
m_fieldsGrid->ProcessTableMessage( msg );
if( m_fieldsGrid->GetNumberRows() > 0 )
{
m_fieldsGrid->MakeCellVisible( std::max( 0, row-1 ), m_fieldsGrid->GetGridCursorCol() );
m_fieldsGrid->SetGridCursor( std::max( 0, row-1 ), m_fieldsGrid->GetGridCursorCol() );
}
}
OnModify();

View File

@ -47,6 +47,7 @@ PANEL_EESCHEMA_TEMPLATE_FIELDNAMES::PANEL_EESCHEMA_TEMPLATE_FIELDNAMES( SCH_EDIT
m_checkboxColWidth = m_grid->GetColSize( 1 );
m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
}
@ -90,16 +91,25 @@ void PANEL_EESCHEMA_TEMPLATE_FIELDNAMES::OnDeleteButtonClick( wxCommandEvent& ev
if( !m_grid->CommitPendingChanges() )
return;
int curRow = m_grid->GetGridCursorRow();
wxArrayInt selectedRows = m_grid->GetSelectedRows();
if( curRow >= 0 && curRow < (int)m_fields.size() )
if( selectedRows.empty() && m_grid->GetGridCursorRow() >= 0 )
selectedRows.push_back( m_grid->GetGridCursorRow() );
if( selectedRows.empty() )
return;
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
for( int row : selectedRows )
{
m_fields.erase( m_fields.begin() + curRow );
m_grid->DeleteRows( curRow );
}
m_fields.erase( m_fields.begin() + row );
m_grid->DeleteRows( row );
m_grid->MakeCellVisible( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
m_grid->SetGridCursor( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
m_grid->MakeCellVisible( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
m_grid->SetGridCursor( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
}
}

View File

@ -558,28 +558,42 @@ void DIALOG_FOOTPRINT_PROPERTIES::OnAddField( wxCommandEvent& )
void DIALOG_FOOTPRINT_PROPERTIES::OnDeleteField( wxCommandEvent& )
{
m_itemsGrid->CommitPendingChanges( true /* quiet mode */ );
int curRow = m_itemsGrid->GetGridCursorRow();
if( curRow < 0 )
if( !m_itemsGrid->CommitPendingChanges() )
return;
else if( curRow < 2 )
wxArrayInt selectedRows = m_itemsGrid->GetSelectedRows();
if( selectedRows.empty() && m_itemsGrid->GetGridCursorRow() >= 0 )
selectedRows.push_back( m_itemsGrid->GetGridCursorRow() );
if( selectedRows.empty() )
return;
for( int row : selectedRows )
{
DisplayError( nullptr, _( "Reference and value are mandatory." ) );
return;
if( row < 2 )
{
DisplayError( nullptr, _( "Reference and value are mandatory." ) );
return;
}
}
m_texts->erase( m_texts->begin() + curRow );
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
// notify the grid
wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_DELETED, curRow, 1 );
m_itemsGrid->ProcessTableMessage( msg );
if( m_itemsGrid->GetNumberRows() > 0 )
for( int row : selectedRows )
{
m_itemsGrid->MakeCellVisible( std::max( 0, curRow-1 ), m_itemsGrid->GetGridCursorCol() );
m_itemsGrid->SetGridCursor( std::max( 0, curRow-1 ), m_itemsGrid->GetGridCursorCol() );
m_texts->erase( m_texts->begin() + row );
// notify the grid
wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
m_itemsGrid->ProcessTableMessage( msg );
if( m_itemsGrid->GetNumberRows() > 0 )
{
m_itemsGrid->MakeCellVisible( std::max( 0, row-1 ), m_itemsGrid->GetGridCursorCol() );
m_itemsGrid->SetGridCursor( std::max( 0, row-1 ), m_itemsGrid->GetGridCursorCol() );
}
}
}

View File

@ -93,6 +93,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR(
m_itemsGrid->SetTable( m_texts );
m_itemsGrid->PushEventHandler( new GRID_TRICKS( m_itemsGrid ) );
m_itemsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
// Show/hide columns according to the user's preference
m_itemsGrid->ShowHideColumns( m_frame->GetSettings()->m_FootprintTextShownColumns );
@ -511,28 +512,39 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnDeleteField( wxCommandEvent& event
if( !m_itemsGrid->CommitPendingChanges() )
return;
int curRow = m_itemsGrid->GetGridCursorRow();
wxArrayInt selectedRows = m_itemsGrid->GetSelectedRows();
if( curRow < 0 )
{
if( selectedRows.empty() && m_itemsGrid->GetGridCursorRow() >= 0 )
selectedRows.push_back( m_itemsGrid->GetGridCursorRow() );
if( selectedRows.empty() )
return;
}
else if( curRow < 2 )
for( int row : selectedRows )
{
DisplayError( nullptr, _( "Reference and value are mandatory." ) );
return;
if( row < 2 )
{
DisplayError( nullptr, _( "Reference and value are mandatory." ) );
return;
}
}
m_texts->erase( m_texts->begin() + curRow );
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
// notify the grid
wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_DELETED, curRow, 1 );
m_itemsGrid->ProcessTableMessage( msg );
if( m_itemsGrid->GetNumberRows() > 0 )
for( int row : selectedRows )
{
m_itemsGrid->MakeCellVisible( std::max( 0, curRow-1 ), m_itemsGrid->GetGridCursorCol() );
m_itemsGrid->SetGridCursor( std::max( 0, curRow-1 ), m_itemsGrid->GetGridCursorCol() );
m_texts->erase( m_texts->begin() + row );
// notify the grid
wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
m_itemsGrid->ProcessTableMessage( msg );
if( m_itemsGrid->GetNumberRows() > 0 )
{
m_itemsGrid->MakeCellVisible( std::max( 0, row-1 ), m_itemsGrid->GetGridCursorCol() );
m_itemsGrid->SetGridCursor( std::max( 0, row-1 ), m_itemsGrid->GetGridCursorCol() );
}
}
}

View File

@ -32,6 +32,7 @@
#include <bitmaps.h>
#include <wx/treebook.h>
#include <confirm.h>
class TEXT_ITEMS_GRID_TABLE : public wxGridTableBase
{
@ -181,6 +182,7 @@ PANEL_FP_EDITOR_DEFAULTS::PANEL_FP_EDITOR_DEFAULTS( FOOTPRINT_EDIT_FRAME* aFrame
m_textItemsGrid->SetTable( new TEXT_ITEMS_GRID_TABLE(), true );
m_textItemsGrid->PushEventHandler( new GRID_TRICKS( m_textItemsGrid ) );
m_textItemsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
wxGridCellAttr* attr = new wxGridCellAttr;
attr->SetRenderer( new wxGridCellBoolRenderer() );
@ -397,19 +399,41 @@ void PANEL_FP_EDITOR_DEFAULTS::OnAddTextItem( wxCommandEvent& event )
void PANEL_FP_EDITOR_DEFAULTS::OnDeleteTextItem( wxCommandEvent& event )
{
wxArrayInt selectedRows = m_textItemsGrid->GetSelectedRows();
if( selectedRows.empty() && m_textItemsGrid->GetGridCursorRow() >= 0 )
selectedRows.push_back( m_textItemsGrid->GetGridCursorRow() );
if( selectedRows.empty() )
return;
for( int row : selectedRows )
{
if( row < 2 )
{
DisplayError( nullptr, _( "Reference and value are mandatory." ) );
return;
}
}
if( !m_textItemsGrid->CommitPendingChanges() || !m_graphicsGrid->CommitPendingChanges() )
return;
int curRow = m_textItemsGrid->GetGridCursorRow();
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
if( curRow < 2 ) // First two rows are required
return;
for( int row : selectedRows )
{
m_textItemsGrid->GetTable()->DeleteRows( row, 1 );
m_textItemsGrid->GetTable()->DeleteRows( curRow, 1 );
curRow = std::max( 0, curRow - 1 );
m_textItemsGrid->MakeCellVisible( curRow, m_textItemsGrid->GetGridCursorCol() );
m_textItemsGrid->SetGridCursor( curRow, m_textItemsGrid->GetGridCursorCol() );
if( m_textItemsGrid->GetNumberRows() > 0 )
{
m_textItemsGrid->MakeCellVisible( std::max( 0, row-1 ),
m_textItemsGrid->GetGridCursorCol() );
m_textItemsGrid->SetGridCursor( std::max( 0, row-1 ),
m_textItemsGrid->GetGridCursorCol() );
}
}
}