Fix level delete action

This commit is contained in:
SiboVG 2024-09-22 07:13:18 +01:00
parent 3d583eda51
commit f7455bd385
2 changed files with 181 additions and 20 deletions

View File

@ -510,6 +510,8 @@ simedtdlg.col.StandardDeviation = Deviation
simedtdlg.col.Turbulence = Turbulence
simedtdlg.col.Intensity = Intensity
simedtdlg.col.Unit = Unit
simedtdlg.col.Delete = Delete
simedtdlg.popupmenu.Delete = Delete level
simedtdlg.lbl.Longitude = Longitude:
simedtdlg.lbl.ttip.Longitude = <html>Required for weather prediction and elevation models.
@ -565,7 +567,7 @@ simedtdlg.radio.AverageWind.ttip = Model the wind as pink noise from the average
simedtdlg.radio.MultiLevelWind = Multi-level
simedtdlg.radio.MultiLevelWind.ttip = Model the wind using speed and direction entries at various altitude levels.
simedtdlg.but.addWindLevel = Add level
simedtdlg.but.removeWindLevel = Remove level
simedtdlg.but.deleteWindLevel = Delete level
simedtdlg.but.visualizeWindLevels = Visualize levels
! WindLevelVisualizationDialog

View File

@ -9,6 +9,7 @@ import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
@ -16,6 +17,7 @@ import java.util.Comparator;
import java.util.EventObject;
import java.util.List;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultCellEditor;
@ -23,8 +25,10 @@ import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
@ -37,10 +41,13 @@ import javax.swing.SortOrder;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.RowSorterEvent;
import javax.swing.event.RowSorterListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
@ -501,15 +508,15 @@ public class SimulationConditionsPanel extends JPanel {
// Create the levels table
WindLevelTableModel tableModel = new WindLevelTableModel(model);
JTable windLevelTable = new JTable(tableModel);
windLevelTable.setRowSelectionAllowed(false);
windLevelTable.setRowSelectionAllowed(true);
windLevelTable.setColumnSelectionAllowed(false);
windLevelTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
windLevelTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); // Allow horizontal scrolling
// Set up value columns
SelectAllCellEditor selectAllEditor = new SelectAllCellEditor();
SelectAllCellEditor selectAllEditor = new SelectAllCellEditor(windLevelTable);
ValueCellRenderer valueCellRenderer = new ValueCellRenderer();
for (int i = 0; i < windLevelTable.getColumnCount(); i += 2) {
for (int i = 0; i < windLevelTable.getColumnCount() - 2; i += 2) {
windLevelTable.getColumnModel().getColumn(i).setCellRenderer(valueCellRenderer);
windLevelTable.getColumnModel().getColumn(i).setCellEditor(selectAllEditor);
}
@ -520,6 +527,11 @@ public class SimulationConditionsPanel extends JPanel {
windLevelTable.getColumnModel().getColumn(i).setCellEditor(new UnitSelectorEditor());
}
// Set up delete button column
TableColumn deleteColumn = windLevelTable.getColumnModel().getColumn(windLevelTable.getColumnCount() - 1);
deleteColumn.setCellRenderer(new DeleteButtonRenderer());
deleteColumn.setCellEditor(new DeleteButtonEditor(windLevelTable));
// Adjust column widths
adjustColumnWidths(windLevelTable);
@ -559,14 +571,15 @@ public class SimulationConditionsPanel extends JPanel {
});
buttonPanel.add(addButton);
// Remove level
JButton removeButton = new IconButton(trans.get("simedtdlg.but.removeWindLevel"), Icons.EDIT_DELETE);
removeButton.addActionListener(e -> {
// Delete level
JButton deleteButton = new IconButton(trans.get("simedtdlg.but.deleteWindLevel"), Icons.EDIT_DELETE);
deleteButton.addActionListener(e -> {
int selectedRow = windLevelTable.getSelectedRow();
tableModel.removeWindLevel(selectedRow);
tableModel.deleteWindLevel(selectedRow);
sorter.sort();
});
buttonPanel.add(removeButton, "gapright unrel");
deleteButton.setEnabled(false);
buttonPanel.add(deleteButton, "gapright unrel");
// Visualization levels
JButton visualizeButton = new IconButton(trans.get("simedtdlg.but.visualizeWindLevels"), Icons.SIM_PLOT);
@ -583,6 +596,7 @@ public class SimulationConditionsPanel extends JPanel {
visualizationDialog.setVisible(true);
}
});
visualizeButton.setEnabled(!tableModel.getLevels().isEmpty());
buttonPanel.add(visualizeButton);
panel.add(buttonPanel, "grow, wrap");
@ -593,6 +607,44 @@ public class SimulationConditionsPanel extends JPanel {
if (tableModel.getVisualizationDialog() != null) {
tableModel.getVisualizationDialog().repaint();
}
visualizeButton.setEnabled(!tableModel.getLevels().isEmpty());
});
// Add listener to update selected row when table data changes
windLevelTable.getSelectionModel().addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) {
int selectedRow = windLevelTable.getSelectedRow();
if (selectedRow != -1) {
windLevelTable.setRowSelectionInterval(selectedRow, selectedRow);
}
deleteButton.setEnabled(windLevelTable.getSelectedRow() != -1);
}
});
// Add context menu
JPopupMenu contextMenu = createContextMenu(windLevelTable, tableModel);
windLevelTable.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
showContextMenu(e);
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
showContextMenu(e);
}
}
private void showContextMenu(MouseEvent e) {
int row = windLevelTable.rowAtPoint(e.getPoint());
if (row >= 0 && row < windLevelTable.getRowCount()) {
windLevelTable.setRowSelectionInterval(row, row);
contextMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
}
@ -755,6 +807,37 @@ public class SimulationConditionsPanel extends JPanel {
}
}
private static JPopupMenu createContextMenu(JTable table, WindLevelTableModel model) {
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem deleteItem = new JMenuItem(trans.get("simedtdlg.popupmenu.Delete"));
deleteItem.setIcon(Icons.EDIT_DELETE);
deleteItem.addActionListener(e -> {
int selectedRow = table.getSelectedRow();
if (selectedRow != -1) {
int modelRow = table.convertRowIndexToModel(selectedRow);
model.deleteWindLevel(modelRow);
}
});
popupMenu.add(deleteItem);
// Disable the delete item if no row is selected
popupMenu.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
int selectedRow = table.getSelectedRow();
deleteItem.setEnabled(selectedRow != -1 && table.getRowCount() > 1);
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {}
});
return popupMenu;
}
private static class WindLevelTableModel extends AbstractTableModel {
private final MultiLevelPinkNoiseWindModel model;
private static final String[] columnNames = {
@ -769,6 +852,7 @@ public class SimulationConditionsPanel extends JPanel {
trans.get("simedtdlg.col.Turbulence"),
trans.get("simedtdlg.col.Unit"),
trans.get("simedtdlg.col.Intensity"),
trans.get("simedtdlg.col.Delete")
};
private static final UnitGroup[] unitGroups = {
UnitGroup.UNITS_DISTANCE, UnitGroup.UNITS_VELOCITY, UnitGroup.UNITS_ANGLE,
@ -786,6 +870,10 @@ public class SimulationConditionsPanel extends JPanel {
this.model = model;
}
public List<MultiLevelPinkNoiseWindModel.LevelWindModel> getLevels() {
return model.getLevels();
}
public void setVisualizationDialog(WindLevelVisualizationDialog visualizationDialog) {
this.visualizationDialog = visualizationDialog;
}
@ -812,9 +900,13 @@ public class SimulationConditionsPanel extends JPanel {
@Override
public Class<?> getColumnClass(int columnIndex) {
// Intensity column
if (columnIndex == getColumnCount()-1) {
if (columnIndex == getColumnCount() - 2) {
return String.class;
}
// Delete button column
if (columnIndex == getColumnCount() - 1) {
return JButton.class;
}
return (columnIndex % 2 == 0) ? Double.class : Unit.class;
}
@ -833,9 +925,12 @@ public class SimulationConditionsPanel extends JPanel {
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
// Intensity column
if (columnIndex == getColumnCount()-1) {
if (columnIndex == getColumnCount()-2) {
return getIntensityDescription(model.getLevels().get(rowIndex).getTurblenceIntensity());
}
if (columnIndex == getColumnCount()-1) {
return null;
}
if (columnIndex % 2 == 0) {
Object rawValue = getSIValueAt(rowIndex, columnIndex);
if (rawValue == null) {
@ -853,10 +948,13 @@ public class SimulationConditionsPanel extends JPanel {
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex >= getColumnCount() - 2) {
return;
}
MultiLevelPinkNoiseWindModel.LevelWindModel level = model.getLevels().get(rowIndex);
if (columnIndex % 2 == 0) {
// Value column
double value = Double.parseDouble((String) aValue);
double value = aValue instanceof Double ? (Double) aValue : Double.parseDouble(aValue.toString());
switch (columnIndex) {
case 0:
level.setAltitude(currentUnits[0].fromUnit(value));
@ -894,7 +992,7 @@ public class SimulationConditionsPanel extends JPanel {
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex != columnNames.length - 1; // Intensity column is not editable
return columnIndex != columnNames.length - 2; // Intensity & remove column is not editable
}
public void addWindLevel() {
@ -908,7 +1006,7 @@ public class SimulationConditionsPanel extends JPanel {
fireTableDataChanged();
}
public void removeWindLevel(int index) {
public void deleteWindLevel(int index) {
if (index >= 0 && index < model.getLevels().size()) {
model.removeWindLevelIdx(index);
fireTableDataChanged();
@ -964,14 +1062,26 @@ public class SimulationConditionsPanel extends JPanel {
}
private static class SelectAllCellEditor extends DefaultCellEditor {
private Object cellEditorValue;
private final JTable table;
private int editingRow;
private int editingColumn;
public SelectAllCellEditor() {
public SelectAllCellEditor(JTable table) {
super(new JTextField());
this.table = table;
setClickCountToStart(1);
JTextField textField = (JTextField) getComponent();
textField.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
editingRow = table.getEditingRow();
editingColumn = table.getEditingColumn();
if (editingRow != -1) {
table.setRowSelectionInterval(editingRow, editingRow);
}
}
@Override
public void focusLost(FocusEvent e) {
stopCellEditing();
@ -982,7 +1092,6 @@ public class SimulationConditionsPanel extends JPanel {
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
JTextField textField = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, column);
cellEditorValue = value;
SwingUtilities.invokeLater(textField::selectAll);
return textField;
}
@ -990,13 +1099,25 @@ public class SimulationConditionsPanel extends JPanel {
@Override
public boolean stopCellEditing() {
JTextField textField = (JTextField) getComponent();
cellEditorValue = textField.getText();
return super.stopCellEditing();
try {
// Attempt to parse the value as a double
double value = Double.parseDouble(textField.getText());
// If successful, update the cell value
table.getModel().setValueAt(value, editingRow, editingColumn);
} catch (NumberFormatException e) {
// If parsing fails, revert to the original value
return false;
}
boolean result = super.stopCellEditing();
if (result && editingRow != -1) {
SwingUtilities.invokeLater(() -> table.setRowSelectionInterval(editingRow, editingRow));
}
return result;
}
@Override
public Object getCellEditorValue() {
return cellEditorValue;
return ((JTextField) getComponent()).getText();
}
@Override
@ -1007,4 +1128,42 @@ public class SimulationConditionsPanel extends JPanel {
return super.isCellEditable(e);
}
}
private static class DeleteButtonRenderer extends JButton implements TableCellRenderer {
public DeleteButtonRenderer() {
setOpaque(true);
setIcon(Icons.EDIT_DELETE);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
return this;
}
}
private static class DeleteButtonEditor extends AbstractCellEditor implements TableCellEditor {
private final JButton button;
private int row;
public DeleteButtonEditor(JTable table) {
button = new JButton();
button.setIcon(Icons.EDIT_DELETE);
button.addActionListener(e -> {
WindLevelTableModel model = (WindLevelTableModel) table.getModel();
model.deleteWindLevel(row);
fireEditingStopped();
});
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
this.row = row;
return button;
}
@Override
public Object getCellEditorValue() {
return null;
}
}
}