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 if (value != null) { 105 variable._initialValueType = (InitialValueType) value; 106 } else { 107 variable._initialValueType = InitialValueType.None; 108 } 109 break; 110 case COLUMN_DATA: 111 variable._initialValueData = (String) value; 112 break; 113 case COLUMN_MENU: 114 // Do nothing 115 break; 116 default: 117 throw new IllegalArgumentException("Invalid column"); 118 } 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 public Object getValueAt(int rowIndex, int columnIndex) { 124 if (rowIndex >= _variables.size()) throw new IllegalArgumentException("Invalid row"); 125 126 switch (columnIndex) { 127 case COLUMN_NAME: 128 return _variables.get(rowIndex).getName(); 129 case COLUMN_TYPE: 130 return _variables.get(rowIndex).getInitialValueType(); 131 case COLUMN_DATA: 132 return _variables.get(rowIndex).getInitialValueData(); 133 case COLUMN_MENU: 134 return Menu.Select; 135 default: 136 throw new IllegalArgumentException("Invalid column"); 137 } 138 } 139 140 public void setColumnForMenu(JTable table) { 141 JComboBox<Menu> comboBox = new JComboBox<>(); 142 table.setRowHeight(comboBox.getPreferredSize().height); 143 table.getColumnModel().getColumn(COLUMN_MENU) 144 .setPreferredWidth((comboBox.getPreferredSize().width) + 4); 145 } 146 147 public void add() { 148 int row = _variables.size(); 149 _variables.add(new VariableData("", InitialValueType.None, "")); 150 fireTableRowsInserted(row, row); 151 } 152 153 public List<VariableData> getVariables() { 154 return _variables; 155 } 156 157 158 public static enum Menu { 159 Select(Bundle.getMessage("TableMenuSelect")), 160 Delete(Bundle.getMessage("TableMenuDelete")), 161 MoveUp(Bundle.getMessage("TableMenuMoveUp")), 162 MoveDown(Bundle.getMessage("TableMenuMoveDown")); 163 164 private final String _descr; 165 166 private Menu(String descr) { 167 _descr = descr; 168 } 169 170 @Override 171 public String toString() { 172 return _descr; 173 } 174 } 175 176 177 public static class TypeCellRenderer extends DefaultTableCellRenderer { 178 179 @Override 180 public Component getTableCellRendererComponent(JTable table, Object value, 181 boolean isSelected, boolean hasFocus, int row, int column) { 182 183 if (value == null) value = InitialValueType.None; 184 185 if (! (value instanceof InitialValueType)) { 186 throw new IllegalArgumentException("value is not an InitialValueType: " + value.getClass().getName()); 187 } 188 setText(((InitialValueType) value).toString()); 189 return this; 190 } 191 } 192 193 194 public static class MenuCellRenderer extends DefaultTableCellRenderer { 195 196 @Override 197 public Component getTableCellRendererComponent(JTable table, Object value, 198 boolean isSelected, boolean hasFocus, int row, int column) { 199 200 if (value == null) value = Menu.Select; 201 202 if (! (value instanceof Menu)) { 203 throw new IllegalArgumentException("value is not an Menu: " + value.getClass().getName()); 204 } 205 setText(((Menu) value).toString()); 206 return this; 207 } 208 } 209 210 211 public static class TypeCellEditor extends AbstractCellEditor 212 implements TableCellEditor, ActionListener { 213 214 private InitialValueType _type; 215 216 @Override 217 public Object getCellEditorValue() { 218 return this._type; 219 } 220 221 @Override 222 public Component getTableCellEditorComponent(JTable table, Object value, 223 boolean isSelected, int row, int column) { 224 225 if (value == null) value = InitialValueType.None; 226 227 if (! (value instanceof InitialValueType)) { 228 throw new IllegalArgumentException("value is not an InitialValueType: " + value.getClass().getName()); 229 } 230 231 JComboBox<InitialValueType> typeComboBox = new JComboBox<>(); 232 233 for (InitialValueType type : InitialValueType.values()) { 234 typeComboBox.addItem(type); 235 } 236 JComboBoxUtil.setupComboBoxMaxRows(typeComboBox); 237 238 typeComboBox.setSelectedItem(value); 239 typeComboBox.addActionListener(this); 240 241 return typeComboBox; 242 } 243 244 @Override 245 @SuppressWarnings("unchecked") // Not possible to check that event.getSource() is instanceof JComboBox<InitialValueType> 246 public void actionPerformed(ActionEvent event) { 247 if (! (event.getSource() instanceof JComboBox)) { 248 throw new IllegalArgumentException("value is not an InitialValueType: " + event.getSource().getClass().getName()); 249 } 250 JComboBox<InitialValueType> typeComboBox = 251 (JComboBox<InitialValueType>) event.getSource(); 252 _type = typeComboBox.getItemAt(typeComboBox.getSelectedIndex()); 253 } 254 255 } 256 257 258 public static class MenuCellEditor extends AbstractCellEditor 259 implements TableCellEditor, ActionListener { 260 261 JTable _table; 262 LocalVariableTableModel _tableModel; 263 264 public MenuCellEditor(JTable table, LocalVariableTableModel tableModel) { 265 _table = table; 266 _tableModel = tableModel; 267 } 268 269 @Override 270 public Object getCellEditorValue() { 271 return Menu.Select; 272 } 273 274 @Override 275 public Component getTableCellEditorComponent(JTable table, Object value, 276 boolean isSelected, int row, int column) { 277 278 if (value == null) value = Menu.Select; 279 280 if (! (value instanceof Menu)) { 281 throw new IllegalArgumentException("value is not an Menu: " + value.getClass().getName()); 282 } 283 284 JComboBox<Menu> menuComboBox = new JComboBox<>(); 285 286 for (Menu menu : Menu.values()) { 287 if ((menu == Menu.MoveUp) && (row == 0)) continue; 288 if ((menu == Menu.MoveDown) && (row+1 == _tableModel._variables.size())) continue; 289 menuComboBox.addItem(menu); 290 } 291 JComboBoxUtil.setupComboBoxMaxRows(menuComboBox); 292 293 menuComboBox.setSelectedItem(value); 294 menuComboBox.addActionListener(this); 295 296 return menuComboBox; 297 } 298 299 @Override 300 @SuppressWarnings("unchecked") // Not possible to check that event.getSource() is instanceof JComboBox<Menu> 301 public void actionPerformed(ActionEvent event) { 302 if (! (event.getSource() instanceof JComboBox)) { 303 throw new IllegalArgumentException("value is not an InitialValueType: " + event.getSource().getClass().getName()); 304 } 305 JComboBox<Menu> menuComboBox = 306 (JComboBox<Menu>) event.getSource(); 307 int row = _table.getSelectedRow(); 308 Menu menu = menuComboBox.getItemAt(menuComboBox.getSelectedIndex()); 309 310 switch (menu) { 311 case Delete: 312 delete(row); 313 break; 314 case MoveUp: 315 if ((row) > 0) moveUp(row); 316 break; 317 case MoveDown: 318 if ((row+1) < _tableModel._variables.size()) moveUp(row+1); 319 break; 320 default: 321 // Do nothing 322 } 323 // Remove focus from combo box 324 if (_tableModel._variables.size() > 0) _table.editCellAt(row, COLUMN_NAME); 325 } 326 327 private void delete(int row) { 328 _tableModel._variables.remove(row); 329 _tableModel.fireTableRowsDeleted(row, row); 330 } 331 332 private void moveUp(int row) { 333 VariableData temp = _tableModel._variables.get(row-1); 334 _tableModel._variables.set(row-1, _tableModel._variables.get(row)); 335 _tableModel._variables.set(row, temp); 336 _tableModel.fireTableRowsUpdated(row-1, row); 337 } 338 339 } 340 341}