001package jmri.jmrit.logixng.tools.swing.swing; 002 003import java.awt.Component; 004import java.awt.event.ActionEvent; 005import java.awt.event.ActionListener; 006import java.util.ArrayList; 007import java.util.List; 008 009import javax.annotation.Nonnull; 010import javax.swing.*; 011import javax.swing.table.AbstractTableModel; 012import javax.swing.table.DefaultTableCellRenderer; 013import javax.swing.table.TableCellEditor; 014 015import jmri.jmrit.logixng.Module; 016import jmri.jmrit.logixng.Module.Parameter; 017import jmri.jmrit.logixng.SymbolTable.InitialValueType; 018import jmri.jmrit.logixng.implementation.DefaultSymbolTable.DefaultParameter; 019import jmri.util.swing.JComboBoxUtil; 020 021/** 022 * Table model for local variables 023 * @author Daniel Bergqvist Copyright 2018 024 */ 025public class ModuleParametersTableModel extends AbstractTableModel { 026 027 public static final int COLUMN_NAME = 0; 028 public static final int COLUMN_IS_INPUT = 1; 029 public static final int COLUMN_IS_OUTPUT = 2; 030 public static final int COLUMN_MENU = 3; 031 032 private final List<DefaultParameter> _parameters = new ArrayList<>(); 033 034 035 public ModuleParametersTableModel(@Nonnull Module module) { 036 for (Parameter v : module.getParameters()) { 037 _parameters.add(new DefaultParameter(v)); 038 } 039 } 040 041 /** {@inheritDoc} */ 042 @Override 043 public int getRowCount() { 044 return _parameters.size(); 045 } 046 047 /** {@inheritDoc} */ 048 @Override 049 public int getColumnCount() { 050 return 4; 051 } 052 053 /** {@inheritDoc} */ 054 @Override 055 public String getColumnName(int col) { 056 switch (col) { 057 case COLUMN_NAME: 058 return Bundle.getMessage("ColumnParameterName"); 059 case COLUMN_IS_INPUT: 060 return Bundle.getMessage("ColumnParameterIsInput"); 061 case COLUMN_IS_OUTPUT: 062 return Bundle.getMessage("ColumnParameterIsOutput"); 063 case COLUMN_MENU: 064 return Bundle.getMessage("ColumnParameterMenu"); 065 default: 066 throw new IllegalArgumentException("Invalid column"); 067 } 068 } 069 070 /** {@inheritDoc} */ 071 @Override 072 public Class<?> getColumnClass(int col) { 073 switch (col) { 074 case COLUMN_NAME: 075 return String.class; 076 case COLUMN_IS_INPUT: 077 return Boolean.class; 078 case COLUMN_IS_OUTPUT: 079 return Boolean.class; 080 case COLUMN_MENU: 081 return Menu.class; 082 default: 083 throw new IllegalArgumentException("Invalid column"); 084 } 085 } 086 087 /** {@inheritDoc} */ 088 @Override 089 public boolean isCellEditable(int row, int col) { 090 return true; 091 } 092 093 /** {@inheritDoc} */ 094 @Override 095 public void setValueAt(Object value, int rowIndex, int columnIndex) { 096 if (rowIndex >= _parameters.size()) return; 097 098 DefaultParameter parameter = _parameters.get(rowIndex); 099 100 switch (columnIndex) { 101 case COLUMN_NAME: 102 parameter.setName((String) value); 103 break; 104 case COLUMN_IS_INPUT: 105 parameter.setIsInput((Boolean) value); 106 break; 107 case COLUMN_IS_OUTPUT: 108 parameter.setIsOutput((Boolean) value); 109 break; 110 case COLUMN_MENU: 111 // Do nothing 112 break; 113 default: 114 throw new IllegalArgumentException("Invalid column"); 115 } 116 } 117 118 /** {@inheritDoc} */ 119 @Override 120 public Object getValueAt(int rowIndex, int columnIndex) { 121 if (rowIndex >= _parameters.size()) throw new IllegalArgumentException("Invalid row"); 122 123 switch (columnIndex) { 124 case COLUMN_NAME: 125 return _parameters.get(rowIndex).getName(); 126 case COLUMN_IS_INPUT: 127 return _parameters.get(rowIndex).isInput(); 128 case COLUMN_IS_OUTPUT: 129 return _parameters.get(rowIndex).isOutput(); 130 case COLUMN_MENU: 131 return Menu.Select; 132 default: 133 throw new IllegalArgumentException("Invalid column"); 134 } 135 } 136 137 public void setColumnForMenu(JTable table) { 138 JComboBox<Menu> comboBox = new JComboBox<>(); 139 table.setRowHeight(comboBox.getPreferredSize().height); 140 table.getColumnModel().getColumn(COLUMN_MENU) 141 .setPreferredWidth((comboBox.getPreferredSize().width) + 4); 142 } 143 144 public void add() { 145 int row = _parameters.size(); 146 _parameters.add(new DefaultParameter("", false, false)); 147 fireTableRowsInserted(row, row); 148 } 149 150 public List<DefaultParameter> getParameters() { 151 return _parameters; 152 } 153 154 155 public static enum Menu { 156 Select(Bundle.getMessage("TableMenuSelect")), 157 Delete(Bundle.getMessage("TableMenuDelete")), 158 MoveUp(Bundle.getMessage("TableMenuMoveUp")), 159 MoveDown(Bundle.getMessage("TableMenuMoveDown")); 160 161 private final String _descr; 162 163 private Menu(String descr) { 164 _descr = descr; 165 } 166 167 @Override 168 public String toString() { 169 return _descr; 170 } 171 } 172 173 174 public static class TypeCellRenderer extends DefaultTableCellRenderer { 175 176 @Override 177 public Component getTableCellRendererComponent(JTable table, Object value, 178 boolean isSelected, boolean hasFocus, int row, int column) { 179 180 if (value == null) value = InitialValueType.None; 181 182 if (! (value instanceof InitialValueType)) { 183 throw new IllegalArgumentException("value is not an InitialValueType: " + value.getClass().getName()); 184 } 185 setText(((InitialValueType) value).toString()); 186 return this; 187 } 188 } 189 190 191 public static class MenuCellRenderer extends DefaultTableCellRenderer { 192 193 @Override 194 public Component getTableCellRendererComponent(JTable table, Object value, 195 boolean isSelected, boolean hasFocus, int row, int column) { 196 197 if (value == null) value = Menu.Select; 198 199 if (! (value instanceof Menu)) { 200 throw new IllegalArgumentException("value is not an Menu: " + value.getClass().getName()); 201 } 202 setText(((Menu) value).toString()); 203 return this; 204 } 205 } 206 207 208 public static class TypeCellEditor extends AbstractCellEditor 209 implements TableCellEditor, ActionListener { 210 211 private InitialValueType _type; 212 213 @Override 214 public Object getCellEditorValue() { 215 return this._type; 216 } 217 218 @Override 219 public Component getTableCellEditorComponent(JTable table, Object value, 220 boolean isSelected, int row, int column) { 221 222 if (value == null) value = InitialValueType.None; 223 224 if (! (value instanceof InitialValueType)) { 225 throw new IllegalArgumentException("value is not an InitialValueType: " + value.getClass().getName()); 226 } 227 228 JComboBox<InitialValueType> typeComboBox = new JComboBox<>(); 229 230 for (InitialValueType type : InitialValueType.values()) { 231 if (type.isValidAsParameter()) typeComboBox.addItem(type); 232 } 233 JComboBoxUtil.setupComboBoxMaxRows(typeComboBox); 234 235 typeComboBox.setSelectedItem(value); 236 typeComboBox.addActionListener(this); 237 238 return typeComboBox; 239 } 240 241 @Override 242 @SuppressWarnings("unchecked") // Not possible to check that event.getSource() is instanceof JComboBox<InitialValueType> 243 public void actionPerformed(ActionEvent event) { 244 if (! (event.getSource() instanceof JComboBox)) { 245 throw new IllegalArgumentException("value is not an InitialValueType: " + event.getSource().getClass().getName()); 246 } 247 JComboBox<InitialValueType> typeComboBox = 248 (JComboBox<InitialValueType>) event.getSource(); 249 _type = typeComboBox.getItemAt(typeComboBox.getSelectedIndex()); 250 } 251 252 } 253 254 255 public static class MenuCellEditor extends AbstractCellEditor 256 implements TableCellEditor, ActionListener { 257 258 JTable _table; 259 ModuleParametersTableModel _tableModel; 260 261 public MenuCellEditor(JTable table, ModuleParametersTableModel tableModel) { 262 _table = table; 263 _tableModel = tableModel; 264 } 265 266 @Override 267 public Object getCellEditorValue() { 268 return Menu.Select; 269 } 270 271 @Override 272 public Component getTableCellEditorComponent(JTable table, Object value, 273 boolean isSelected, int row, int column) { 274 275 if (value == null) value = Menu.Select; 276 277 if (! (value instanceof Menu)) { 278 throw new IllegalArgumentException("value is not an Menu: " + value.getClass().getName()); 279 } 280 281 JComboBox<Menu> menuComboBox = new JComboBox<>(); 282 283 for (Menu menu : Menu.values()) { 284 if ((menu == Menu.MoveUp) && (row == 0)) continue; 285 if ((menu == Menu.MoveDown) && (row+1 == _tableModel._parameters.size())) continue; 286 menuComboBox.addItem(menu); 287 } 288 JComboBoxUtil.setupComboBoxMaxRows(menuComboBox); 289 290 menuComboBox.setSelectedItem(value); 291 menuComboBox.addActionListener(this); 292 293 return menuComboBox; 294 } 295 296 @Override 297 @SuppressWarnings("unchecked") // Not possible to check that event.getSource() is instanceof JComboBox<Menu> 298 public void actionPerformed(ActionEvent event) { 299 if (! (event.getSource() instanceof JComboBox)) { 300 throw new IllegalArgumentException("value is not an InitialValueType: " + event.getSource().getClass().getName()); 301 } 302 JComboBox<Menu> menuComboBox = 303 (JComboBox<Menu>) event.getSource(); 304 int row = _table.getSelectedRow(); 305 Menu menu = menuComboBox.getItemAt(menuComboBox.getSelectedIndex()); 306 307 switch (menu) { 308 case Delete: 309 delete(row); 310 break; 311 case MoveUp: 312 if ((row) > 0) moveUp(row); 313 break; 314 case MoveDown: 315 if ((row+1) < _tableModel._parameters.size()) moveUp(row+1); 316 break; 317 default: 318 // Do nothing 319 } 320 // Remove focus from combo box 321 if (_tableModel._parameters.size() > 0) _table.editCellAt(row, COLUMN_NAME); 322 } 323 324 private void delete(int row) { 325 _tableModel._parameters.remove(row); 326 _tableModel.fireTableRowsDeleted(row, row); 327 } 328 329 private void moveUp(int row) { 330 DefaultParameter temp = _tableModel._parameters.get(row-1); 331 _tableModel._parameters.set(row-1, _tableModel._parameters.get(row)); 332 _tableModel._parameters.set(row, temp); 333 _tableModel.fireTableRowsUpdated(row-1, row); 334 } 335 336 } 337 338}