Merge pull request #2340 from SiboVG/fix-preset-column

Fix component preset table column popup menu
This commit is contained in:
Sibo Van Gool 2023-09-22 18:38:43 +02:00 committed by GitHub
commit d9a86021f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 175 additions and 85 deletions

View File

@ -22,8 +22,12 @@ import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.RowFilter; import javax.swing.RowFilter;
import javax.swing.event.ChangeEvent;
import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
@ -247,9 +251,51 @@ public class ComponentPresetChooserDialog extends JDialog {
showLegacyCheckBox.addItemListener(new ItemListener() { showLegacyCheckBox.addItemListener(new ItemListener() {
@Override @Override
public void itemStateChanged(ItemEvent e) { public void itemStateChanged(ItemEvent e) {
updateFilters(); boolean selected = e != null && e.getStateChange() == ItemEvent.SELECTED;
tm.setColumnVisible(legacyColumn, showLegacyCheckBox.isSelected()); if (tm.isColumnVisible(legacyColumn) == selected) {
// No change
return;
} }
updateFilters();
tm.setColumnVisible(legacyColumn, selected);
if (selected) {
// Let's say the optimal width is 100 (you can adjust this as needed)
int optimalWidth = 50;
legacyColumn.setPreferredWidth(optimalWidth);
}
}
});
// When the legacy column changes visibility (by right-clicking on the column header and toggling the legacy header checkbox),
// update the main legacy checkbox
tm.addColumnModelListener(new TableColumnModelListener() {
@Override
public void columnAdded(TableColumnModelEvent e) {
TableColumn column = tm.getColumn(e.getToIndex());
if (column == legacyColumn) {
showLegacyCheckBox.setSelected(true);
}
}
@Override
public void columnRemoved(TableColumnModelEvent e) {
// Use 'getFromIndex' since the column has been removed
if (e.getFromIndex() == legacyColumnIndex) {
showLegacyCheckBox.setSelected(false);
}
}
@Override
public void columnMoved(TableColumnModelEvent e) {}
@Override
public void columnMarginChanged(ChangeEvent e) {}
@Override
public void columnSelectionChanged(ListSelectionEvent e) {}
}); });
if(component instanceof SymmetricComponent) { if(component instanceof SymmetricComponent) {

View File

@ -1,5 +1,7 @@
package net.sf.openrocket.gui.dialogs.preset; package net.sf.openrocket.gui.dialogs.preset;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent; import java.awt.event.ItemEvent;
import java.awt.event.ItemListener; import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
@ -10,9 +12,11 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem; import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JPopupMenu; import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.RowFilter; import javax.swing.RowFilter;
@ -45,17 +49,19 @@ public class ComponentPresetTable extends JTable {
private final AbstractTableModel tableModel; private final AbstractTableModel tableModel;
private final XTableColumnModel tableColumnModel; private final XTableColumnModel tableColumnModel;
private final ComponentPresetTableColumn[] columns; private final ComponentPresetTableColumn[] columns;
private final List<TableColumn> hiddenColumns;
public ComponentPresetTable(final ComponentPreset.Type presetType, List<ComponentPreset> presets, List<TypedKey<?>> visibleColumnKeys) { public ComponentPresetTable(final ComponentPreset.Type presetType, List<ComponentPreset> presets, List<TypedKey<?>> visibleColumnKeys) {
super(); super();
this.presets = presets; this.presets = presets;
this.presetType = presetType; this.presetType = presetType;
this.favorites = Application.getPreferences().getComponentFavorites(presetType); this.favorites = Application.getPreferences().getComponentFavorites(presetType);
this.columns = new ComponentPresetTableColumn[ComponentPreset.ORDERED_KEY_LIST.size()+1]; this.columns = new ComponentPresetTableColumn[ComponentPreset.ORDERED_KEY_LIST.size() + 1];
tableModel = new AbstractTableModel() { this.tableModel = new AbstractTableModel() {
final ComponentPresetTableColumn[] myColumns = columns; final ComponentPresetTableColumn[] myColumns = columns;
@Override @Override
public int getRowCount() { public int getRowCount() {
return ComponentPresetTable.this.presets.size(); return ComponentPresetTable.this.presets.size();
@ -68,7 +74,7 @@ public class ComponentPresetTable extends JTable {
@Override @Override
public Object getValueAt(int rowIndex, int columnIndex) { public Object getValueAt(int rowIndex, int columnIndex) {
return myColumns[columnIndex].getValueFromPreset(favorites,ComponentPresetTable.this.presets.get(rowIndex)); return myColumns[columnIndex].getValueFromPreset(favorites, ComponentPresetTable.this.presets.get(rowIndex));
} }
@Override @Override
@ -96,29 +102,28 @@ public class ComponentPresetTable extends JTable {
}; };
sorter = new TableRowSorter<TableModel>(tableModel); this.sorter = new TableRowSorter<TableModel>(tableModel);
this.tableColumnModel = new XTableColumnModel();
tableColumnModel = new XTableColumnModel();
/* /*
* Set up the Column Table model, and customize the sorting. * Set up the Column Table model, and customize the sorting.
*/ */
columns[0] = new ComponentPresetTableColumn.Favorite(0); this.columns[0] = new ComponentPresetTableColumn.Favorite(0);
tableColumnModel.addColumn(columns[0]); this.tableColumnModel.addColumn(columns[0]);
List<TableColumn> hiddenColumns = new ArrayList<TableColumn>(); this.hiddenColumns = new ArrayList<>();
{ {
int index = 1; int index = 1;
for (final TypedKey<?> key: ComponentPreset.ORDERED_KEY_LIST ) { for (final TypedKey<?> key : ComponentPreset.ORDERED_KEY_LIST) {
if ( key.getType() == Double.class && key.getUnitGroup() != null ) { if (key.getType() == Double.class && key.getUnitGroup() != null) {
columns[index] = new ComponentPresetTableColumn.DoubleWithUnit((TypedKey<Double>)key,index); columns[index] = new ComponentPresetTableColumn.DoubleWithUnit((TypedKey<Double>) key, index);
} else { } else {
columns[index] = new ComponentPresetTableColumn.Parameter(key,index); columns[index] = new ComponentPresetTableColumn.Parameter(key, index);
} }
tableColumnModel.addColumn(columns[index]); tableColumnModel.addColumn(columns[index]);
if ( key == ComponentPreset.PARTNO ) { if (key == ComponentPreset.PARTNO) {
sorter.setComparator(index, new AlphanumComparator()); sorter.setComparator(index, new AlphanumComparator());
} else if ( key.getType() == Double.class ) { } else if (key.getType() == Double.class) {
sorter.setComparator(index, new Comparator<Value>() { sorter.setComparator(index, new Comparator<Value>() {
@Override @Override
@ -127,7 +132,7 @@ public class ComponentPresetTable extends JTable {
} }
}); });
} else if ( key.getType() == Boolean.class ) { } else if (key.getType() == Boolean.class) {
sorter.setComparator(index, new Comparator<Boolean>() { sorter.setComparator(index, new Comparator<Boolean>() {
@Override @Override
@ -143,39 +148,40 @@ public class ComponentPresetTable extends JTable {
}); });
} }
if ( visibleColumnKeys.indexOf(key) < 0 ) { if (!visibleColumnKeys.contains(key)) {
hiddenColumns.add(columns[index]); hiddenColumns.add(columns[index]);
} }
index ++; index++;
} }
} }
this.setAutoCreateColumnsFromModel(false); this.setAutoCreateColumnsFromModel(false);
this.setColumnModel( tableColumnModel ); this.setColumnModel(tableColumnModel);
this.setModel(tableModel); this.setModel(tableModel);
this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
this.setRowSorter(sorter); this.setRowSorter(sorter);
sorter.toggleSortOrder(2); // Sort by the first column (manufacturer) by default this.sorter.toggleSortOrder(2); // Sort by the first column (manufacturer) by default
for ( TableColumn hiddenColumn : hiddenColumns ) { for (TableColumn hiddenColumn : this.hiddenColumns) {
tableColumnModel.setColumnVisible(hiddenColumn, false); this.tableColumnModel.setColumnVisible(hiddenColumn, false);
} }
JTableHeader header = this.getTableHeader(); JTableHeader header = this.getTableHeader();
header.setReorderingAllowed(true); header.setReorderingAllowed(true);
header.addMouseListener( new MouseAdapter() { header.addMouseListener(new MouseAdapter() {
@Override @Override
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
if ( e.isPopupTrigger() ) { if (e.isPopupTrigger()) {
doPopup(e); doPopup(e);
} }
} }
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
if ( e.isPopupTrigger() ) { if (e.isPopupTrigger()) {
doPopup(e); doPopup(e);
} }
} }
@ -183,14 +189,14 @@ public class ComponentPresetTable extends JTable {
} }
public XTableColumnModel getXColumnModel() { public XTableColumnModel getXColumnModel() {
return tableColumnModel; return this.tableColumnModel;
} }
public void setRowFilter( RowFilter<? super TableModel ,? super Integer> filter ) { public void setRowFilter(RowFilter<? super TableModel, ? super Integer> filter) {
sorter.setRowFilter( filter ); sorter.setRowFilter(filter);
} }
public void updateData( List<ComponentPreset> myPresets ) { public void updateData(List<ComponentPreset> myPresets) {
this.presets = myPresets; this.presets = myPresets;
this.favorites = Application.getPreferences().getComponentFavorites(presetType); this.favorites = Application.getPreferences().getComponentFavorites(presetType);
this.tableModel.fireTableDataChanged(); this.tableModel.fireTableDataChanged();
@ -201,34 +207,37 @@ public class ComponentPresetTable extends JTable {
this.tableModel.fireTableDataChanged(); this.tableModel.fireTableDataChanged();
} }
private void doPopup(MouseEvent evt ) { private void doPopup(MouseEvent evt) {
// Figure out what column header was clicked on. // Figure out what column header was clicked on.
int colIndex = tableColumnModel.getColumnIndexAtX( evt.getX() ); int colIndex = tableColumnModel.getColumnIndexAtX(evt.getX());
ComponentPresetTableColumn colClicked = null; ComponentPresetTableColumn colClicked = null;
if ( colIndex >=0 ) { if (colIndex >= 0) {
colClicked = (ComponentPresetTableColumn) tableColumnModel.getColumn(colIndex); colClicked = (ComponentPresetTableColumn) tableColumnModel.getColumn(colIndex);
} }
JPopupMenu columnMenu = new ColumnPopupMenu(colClicked, colIndex); JPopupMenu columnMenu = new ColumnPopupMenu(colClicked, colIndex);
columnMenu.show(evt.getComponent(),evt.getX(),evt.getY()); columnMenu.show(evt.getComponent(), evt.getX(), evt.getY());
} }
private class ColumnPopupMenu extends JPopupMenu { private class ColumnPopupMenu extends JPopupMenu {
ColumnPopupMenu(ComponentPresetTableColumn colClicked, int colClickedIndex) { ColumnPopupMenu(ComponentPresetTableColumn colClicked, int colClickedIndex) {
if ( colClickedIndex >= 0 ) { if (colClickedIndex >= 0) {
JCheckBoxMenuItem item = new SortAscColumnMenuItem(colClickedIndex); JCheckBoxMenuItem item = new SortAscColumnMenuItem(colClickedIndex);
this.add(item); this.add(item);
item = new SortDescColumnMenuItem(colClickedIndex); item = new SortDescColumnMenuItem(colClickedIndex);
this.add(item); this.add(item);
this.addSeparator(); this.addSeparator();
if ( colClicked instanceof ComponentPresetTableColumn.DoubleWithUnit ) { if (colClicked instanceof ComponentPresetTableColumn.DoubleWithUnit) {
this.add( new UnitSelectorMenuItem( (ComponentPresetTableColumn.DoubleWithUnit) colClicked )); this.add(new UnitSelectorMenuItem((ComponentPresetTableColumn.DoubleWithUnit) colClicked));
this.addSeparator(); this.addSeparator();
} }
} }
for( TableColumn c: columns ) { for (TableColumn c : columns) {
if (hiddenColumns.contains(c)) {
continue;
}
JCheckBoxMenuItem item = new ToggleColumnMenuItem(c); JCheckBoxMenuItem item = new ToggleColumnMenuItem(c);
this.add(item); this.add(item);
} }
@ -237,69 +246,81 @@ public class ComponentPresetTable extends JTable {
private class SortAscColumnMenuItem extends JCheckBoxMenuItem implements ItemListener { private class SortAscColumnMenuItem extends JCheckBoxMenuItem implements ItemListener {
private int columnClicked; private int columnClicked;
SortAscColumnMenuItem(int columnClicked) { SortAscColumnMenuItem(int columnClicked) {
super( trans.get("ComponentPresetChooserDialog.menu.sortAsc") ); super(trans.get("ComponentPresetChooserDialog.menu.sortAsc"));
this.addItemListener(this); this.addItemListener(this);
this.columnClicked = columnClicked; this.columnClicked = columnClicked;
} }
@Override @Override
public void itemStateChanged(ItemEvent e) { public void itemStateChanged(ItemEvent e) {
sorter.setSortKeys( Collections.singletonList( new SortKey(columnClicked, SortOrder.ASCENDING))); sorter.setSortKeys(Collections.singletonList(new SortKey(columnClicked, SortOrder.ASCENDING)));
} }
} }
private class SortDescColumnMenuItem extends JCheckBoxMenuItem implements ItemListener { private class SortDescColumnMenuItem extends JCheckBoxMenuItem implements ItemListener {
private int columnClicked; private int columnClicked;
SortDescColumnMenuItem(int columnClicked) { SortDescColumnMenuItem(int columnClicked) {
super( trans.get("ComponentPresetChooserDialog.menu.sortDesc") ); super(trans.get("ComponentPresetChooserDialog.menu.sortDesc"));
this.addItemListener(this); this.addItemListener(this);
this.columnClicked = columnClicked; this.columnClicked = columnClicked;
} }
@Override @Override
public void itemStateChanged(ItemEvent e) { public void itemStateChanged(ItemEvent e) {
sorter.setSortKeys( Collections.singletonList( new SortKey(columnClicked, SortOrder.DESCENDING))); sorter.setSortKeys(Collections.singletonList(new SortKey(columnClicked, SortOrder.DESCENDING)));
} }
} }
private class ToggleColumnMenuItem extends JCheckBoxMenuItem implements ItemListener { private class ToggleColumnMenuItem extends JCheckBoxMenuItem implements ItemListener {
TableColumn col; TableColumn col;
ToggleColumnMenuItem( TableColumn col ) {
super( String.valueOf(col.getHeaderValue()), tableColumnModel.isColumnVisible(col)); ToggleColumnMenuItem(TableColumn col) {
super(String.valueOf(col.getHeaderValue()), tableColumnModel.isColumnVisible(col));
this.addItemListener(this); this.addItemListener(this);
this.col = col; this.col = col;
} }
@Override @Override
public void itemStateChanged(ItemEvent e) { public void itemStateChanged(ItemEvent e) {
tableColumnModel.setColumnVisible(col, !tableColumnModel.isColumnVisible(col)); tableColumnModel.setColumnVisible(col, !tableColumnModel.isColumnVisible(col));
} }
} }
private class UnitSelectorMenuItem extends JMenu implements ItemListener { private class UnitSelectorMenuItem extends JMenu {
ComponentPresetTableColumn.DoubleWithUnit col; ComponentPresetTableColumn.DoubleWithUnit col;
UnitSelectorMenuItem( ComponentPresetTableColumn.DoubleWithUnit col ) { ButtonGroup buttonGroup; // To group the radio buttons
UnitSelectorMenuItem(ComponentPresetTableColumn.DoubleWithUnit col) {
super(trans.get("ComponentPresetChooserDialog.menu.units")); super(trans.get("ComponentPresetChooserDialog.menu.units"));
this.col = col; this.col = col;
buttonGroup = new ButtonGroup(); // Create a new ButtonGroup to hold the radio buttons
UnitGroup group = col.unitGroup; UnitGroup group = col.unitGroup;
Unit selectedUnit = col.selectedUnit; Unit selectedUnit = col.selectedUnit;
for( Unit u : group.getUnits() ) {
JCheckBoxMenuItem item = new JCheckBoxMenuItem( u.toString() ); for (Unit u : group.getUnits()) {
if ( u == selectedUnit ) { JRadioButtonMenuItem item = new JRadioButtonMenuItem(u.toString());
if (u == selectedUnit) {
item.setSelected(true); item.setSelected(true);
} }
item.addItemListener(this);
this.add(item);
}
} item.addActionListener(new ActionListener() {
@Override @Override
public void itemStateChanged(ItemEvent e) { public void actionPerformed(ActionEvent e) {
JCheckBoxMenuItem item = (JCheckBoxMenuItem) e.getItem(); col.selectedUnit = u;
String val = item.getText();
col.selectedUnit = col.unitGroup.findApproximate(val);
ComponentPresetTable.this.tableModel.fireTableDataChanged(); ComponentPresetTable.this.tableModel.fireTableDataChanged();
return;
} }
});
buttonGroup.add(item); // Add the radio button to the button group
this.add(item); // Add the radio button to the menu
}
}
} }
} }
} }

View File

@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -56,6 +57,7 @@ import javax.swing.event.ChangeListener;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel; import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
@ -404,23 +406,26 @@ public class GUIUtil {
public static void rememberTableColumnWidths(final JTable table, String keyName) { public static void rememberTableColumnWidths(final JTable table, String keyName) {
final String key = keyName == null ? table.getClass().getName() : keyName; final String key = keyName == null ? table.getClass().getName() : keyName;
for (int i = 0; i < table.getColumnCount(); i++) { Enumeration<TableColumn> columns = table.getColumnModel().getColumns();
final int column = i; while (columns.hasMoreElements()) {
table.getColumnModel().getColumn(i).addPropertyChangeListener(new PropertyChangeListener() { TableColumn column = columns.nextElement();
column.addPropertyChangeListener(new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("width")) { if (evt.getPropertyName().equals("width")) {
log.debug("Storing width of " + table.getName() + "-" + table.getColumnName(column) + ": " + table.getColumnModel().getColumn(column).getWidth()); log.debug("Storing width of " + table.getName() + "-" + column + ": " + column.getWidth());
((SwingPreferences) Application.getPreferences()).setTableColumnWidth( ((SwingPreferences) Application.getPreferences()).setTableColumnWidth(
key, column, table.getColumnModel().getColumn(column).getWidth()); key, column.getModelIndex(), column.getWidth());
} }
} }
}); });
final Integer width = ((SwingPreferences) Application.getPreferences()).getTableColumnWidth( final Integer width = ((SwingPreferences) Application.getPreferences()).getTableColumnWidth(
key, column); key, column.getModelIndex());
if (width != null) { if (width != null) {
table.getColumnModel().getColumn(column).setPreferredWidth(width); column.setPreferredWidth(width);
} else {
column.setPreferredWidth(getOptimalColumnWidth(table, column.getModelIndex()));
} }
} }
} }
@ -429,6 +434,24 @@ public class GUIUtil {
rememberTableColumnWidths(table, null); rememberTableColumnWidths(table, null);
} }
public static int getOptimalColumnWidth(JTable table, int columnIndex) {
TableColumn column = table.getColumnModel().getColumn(columnIndex);
Component headerRenderer = table.getTableHeader().getDefaultRenderer()
.getTableCellRendererComponent(table, column.getHeaderValue(), false, false, 0, columnIndex);
int maxWidth = headerRenderer.getPreferredSize().width;
for (int row = 0; row < table.getRowCount(); row++) {
Component renderer = table.getCellRenderer(row, columnIndex)
.getTableCellRendererComponent(table, table.getValueAt(row, columnIndex), false, false, row, columnIndex);
maxWidth = Math.max(maxWidth, renderer.getPreferredSize().width);
}
// Optional: Add some padding
int padding = 5; // adjust this value as needed
return maxWidth + padding;
}
/** /**
* Automatically remember the position of a window. The position is stored in the user preferences * Automatically remember the position of a window. The position is stored in the user preferences