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