package net.sf.openrocket.gui.dialogs.preset; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.RowFilter; import javax.swing.RowSorter.SortKey; import javax.swing.SortOrder; import javax.swing.table.AbstractTableModel; import javax.swing.table.JTableHeader; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; import javax.swing.table.TableRowSorter; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.preset.TypedKey; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.Unit; import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.unit.Value; import net.sf.openrocket.util.AlphanumComparator; public class ComponentPresetTable extends JTable { private static final Translator trans = Application.getTranslator(); private final TableRowSorter<TableModel> sorter; private List<ComponentPreset> presets; private final ComponentPreset.Type presetType; private Set<String> favorites; private final AbstractTableModel tableModel; private final XTableColumnModel tableColumnModel; private final ComponentPresetTableColumn[] columns; public ComponentPresetTable(final ComponentPreset.Type presetType, List<ComponentPreset> presets, List<TypedKey<?>> visibleColumnKeys) { super(); this.presets = presets; this.presetType = presetType; this.favorites = Application.getPreferences().getComponentFavorites(presetType); this.columns = new ComponentPresetTableColumn[ComponentPreset.ORDERED_KEY_LIST.size()+1]; tableModel = new AbstractTableModel() { final ComponentPresetTableColumn[] myColumns = columns; @Override public int getRowCount() { return ComponentPresetTable.this.presets.size(); } @Override public int getColumnCount() { return myColumns.length; } @Override public Object getValueAt(int rowIndex, int columnIndex) { return myColumns[columnIndex].getValueFromPreset(favorites,ComponentPresetTable.this.presets.get(rowIndex)); } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { // Only support favorite if ( columnIndex != 0 ) { return; } ComponentPreset preset = ComponentPresetTable.this.presets.get(rowIndex); Application.getComponentPresetDao().setFavorite(preset, presetType, (Boolean) aValue); ComponentPresetTable.this.updateFavorites(); } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return columnIndex == 0; } @Override public Class<?> getColumnClass(int columnIndex) { return columnIndex == 0 ? Boolean.class : Object.class; } }; sorter = new TableRowSorter<TableModel>(tableModel); tableColumnModel = new XTableColumnModel(); /* * Set up the Column Table model, and customize the sorting. */ columns[0] = new ComponentPresetTableColumn.Favorite(0); tableColumnModel.addColumn(columns[0]); List<TableColumn> hiddenColumns = new ArrayList<TableColumn>(); { int index = 1; for (final TypedKey<?> key: ComponentPreset.ORDERED_KEY_LIST ) { if ( key.getType() == Double.class && key.getUnitGroup() != null ) { columns[index] = new ComponentPresetTableColumn.DoubleWithUnit((TypedKey<Double>)key,index); } else { columns[index] = new ComponentPresetTableColumn.Parameter(key,index); } tableColumnModel.addColumn(columns[index]); if ( key == ComponentPreset.PARTNO ) { sorter.setComparator(index, new AlphanumComparator()); } else if ( key.getType() == Double.class ) { sorter.setComparator(index, new Comparator<Value>() { @Override public int compare(Value o1, Value o2) { return Double.compare(o1.getValue(), o2.getValue()); } }); } if ( visibleColumnKeys.indexOf(key) < 0 ) { hiddenColumns.add(columns[index]); } index ++; } } this.setAutoCreateColumnsFromModel(false); this.setColumnModel( tableColumnModel ); this.setModel(tableModel); this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); this.setRowSorter(sorter); for ( TableColumn hiddenColumn : hiddenColumns ) { tableColumnModel.setColumnVisible(hiddenColumn, false); } JTableHeader header = this.getTableHeader(); header.setReorderingAllowed(true); header.addMouseListener( new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if ( e.isPopupTrigger() ) { doPopup(e); } } @Override public void mouseReleased(MouseEvent e) { if ( e.isPopupTrigger() ) { doPopup(e); } } }); } public void setRowFilter( RowFilter<? super TableModel ,? super Integer> filter ) { sorter.setRowFilter( filter ); } public void updateData( List<ComponentPreset> myPresets ) { this.presets = myPresets; this.favorites = Application.getPreferences().getComponentFavorites(presetType); this.tableModel.fireTableDataChanged(); } public void updateFavorites() { this.favorites = Application.getPreferences().getComponentFavorites(presetType); this.tableModel.fireTableDataChanged(); } private void doPopup(MouseEvent evt ) { // Figure out what column header was clicked on. int colIndex = tableColumnModel.getColumnIndexAtX( evt.getX() ); ComponentPresetTableColumn colClicked = null; if ( colIndex >=0 ) { colClicked = (ComponentPresetTableColumn) tableColumnModel.getColumn(colIndex); } JPopupMenu columnMenu = new ColumnPopupMenu(colClicked, colIndex); columnMenu.show(evt.getComponent(),evt.getX(),evt.getY()); } private class ColumnPopupMenu extends JPopupMenu { ColumnPopupMenu(ComponentPresetTableColumn colClicked, int colClickedIndex) { if ( colClickedIndex >= 0 ) { JCheckBoxMenuItem item = new SortAscColumnMenuItem(colClickedIndex); this.add(item); item = new SortDescColumnMenuItem(colClickedIndex); this.add(item); this.addSeparator(); if ( colClicked instanceof ComponentPresetTableColumn.DoubleWithUnit ) { this.add( new UnitSelectorMenuItem( (ComponentPresetTableColumn.DoubleWithUnit) colClicked )); this.addSeparator(); } } for( TableColumn c: columns ) { JCheckBoxMenuItem item = new ToggleColumnMenuItem(c); this.add(item); } } private class SortAscColumnMenuItem extends JCheckBoxMenuItem implements ItemListener { private int columnClicked; SortAscColumnMenuItem(int columnClicked) { super( trans.get("ComponentPresetChooserDialog.menu.sortAsc") ); this.addItemListener(this); this.columnClicked = columnClicked; } @Override public void itemStateChanged(ItemEvent e) { sorter.setSortKeys( Collections.singletonList( new SortKey(columnClicked, SortOrder.ASCENDING))); } } private class SortDescColumnMenuItem extends JCheckBoxMenuItem implements ItemListener { private int columnClicked; SortDescColumnMenuItem(int columnClicked) { super( trans.get("ComponentPresetChooserDialog.menu.sortDesc") ); this.addItemListener(this); this.columnClicked = columnClicked; } @Override public void itemStateChanged(ItemEvent e) { sorter.setSortKeys( Collections.singletonList( new SortKey(columnClicked, SortOrder.DESCENDING))); } } private class ToggleColumnMenuItem extends JCheckBoxMenuItem implements ItemListener { TableColumn col; ToggleColumnMenuItem( TableColumn col ) { super( String.valueOf(col.getHeaderValue()), tableColumnModel.isColumnVisible(col)); this.addItemListener(this); this.col = col; } @Override public void itemStateChanged(ItemEvent e) { tableColumnModel.setColumnVisible(col, !tableColumnModel.isColumnVisible(col)); } } private class UnitSelectorMenuItem extends JMenu implements ItemListener { ComponentPresetTableColumn.DoubleWithUnit col; UnitSelectorMenuItem( ComponentPresetTableColumn.DoubleWithUnit col ) { super(trans.get("ComponentPresetChooserDialog.menu.units")); this.col = col; UnitGroup group = col.unitGroup; Unit selectedUnit = col.selectedUnit; for( Unit u : group.getUnits() ) { JCheckBoxMenuItem item = new JCheckBoxMenuItem( u.toString() ); if ( u == selectedUnit ) { item.setSelected(true); } item.addItemListener(this); this.add(item); } } @Override public void itemStateChanged(ItemEvent e) { JCheckBoxMenuItem item = (JCheckBoxMenuItem) e.getItem(); String val = item.getText(); col.selectedUnit = col.unitGroup.findApproximate(val); ComponentPresetTable.this.tableModel.fireTableDataChanged(); return; } } } }