001package jmri.jmrit.logixng.actions.swing; 002 003import java.awt.Component; 004import java.awt.event.ActionEvent; 005import java.awt.event.ActionListener; 006import java.util.*; 007 008import javax.swing.*; 009import javax.swing.table.AbstractTableModel; 010import javax.swing.table.DefaultTableCellRenderer; 011import javax.swing.table.TableCellEditor; 012 013import jmri.jmrit.logixng.actions.LogData; 014import jmri.jmrit.logixng.util.parser.ParserException; 015import jmri.util.swing.JComboBoxUtil; 016 017/** 018 * Table model for LogData 019 * 020 * @author Daniel Bergqvist Copyright 2021 021 */ 022public class LogDataTableModel extends AbstractTableModel { 023 024 // COLUMN_DUMMY is "hidden" but used when the panel is closed to 025 // ensure that the last edited cell is saved. 026 public static final int COLUMN_TYPE = 0; 027 public static final int COLUMN_DATA = 1; 028 public static final int COLUMN_DELETE = 2; 029 public static final int COLUMN_DUMMY = 3; 030 031 private final List<LogData.Data> _dataList = new ArrayList<>(); 032 033 034 public LogDataTableModel(Collection<LogData.Data> namedBeanReference) { 035 if (namedBeanReference != null) _dataList.addAll(namedBeanReference); 036 } 037 038 /** {@inheritDoc} */ 039 @Override 040 public int getRowCount() { 041 return _dataList.size(); 042 } 043 044 /** {@inheritDoc} */ 045 @Override 046 public int getColumnCount() { 047 return COLUMN_DUMMY+1; 048 } 049 050 /** {@inheritDoc} */ 051 @Override 052 public String getColumnName(int col) { 053 switch (col) { 054 case COLUMN_TYPE: 055 return Bundle.getMessage("LogData_ColumnType"); 056 case COLUMN_DATA: 057 return Bundle.getMessage("LogData_ColumnData"); 058 case COLUMN_DELETE: 059 return ""; // no label 060 case COLUMN_DUMMY: 061 return ""; // no label 062 default: 063 throw new IllegalArgumentException("Invalid column"); 064 } 065 } 066 067 /** {@inheritDoc} */ 068 @Override 069 public Class<?> getColumnClass(int col) { 070 switch (col) { 071 case COLUMN_TYPE: 072 return LogData.DataType.class; 073 case COLUMN_DATA: 074 return String.class; 075 case COLUMN_DELETE: 076 return JButton.class; 077 case COLUMN_DUMMY: 078 return String.class; 079 default: 080 throw new IllegalArgumentException("Invalid column"); 081 } 082 } 083 084 /** {@inheritDoc} */ 085 @Override 086 public boolean isCellEditable(int row, int col) { 087 return true; 088 } 089 090 /** {@inheritDoc} */ 091 @Override 092 public void setValueAt(Object value, int rowIndex, int columnIndex) { 093 LogData.Data ref = _dataList.get(rowIndex); 094 095 switch (columnIndex) { 096 case COLUMN_TYPE: 097 if (value != null) { 098 LogData.DataType oldType = ref.getDataType(); 099 ref.setDataType((LogData.DataType) value); 100 if (oldType != ref.getDataType()) ref.setData(""); 101 } else { 102 // This happens if the combo box is open when the user clicks on another cell. 103 log.debug("Cannot set data type to null"); 104 } 105 break; 106 case COLUMN_DATA: 107 ref.setData((String) value); 108 break; 109 case COLUMN_DELETE: 110 delete(rowIndex); 111 break; 112 case COLUMN_DUMMY: 113 break; 114 default: 115 throw new IllegalArgumentException("Invalid column"); 116 } 117 } 118 119 /** {@inheritDoc} */ 120 @Override 121 public Object getValueAt(int rowIndex, int columnIndex) { 122 if (rowIndex >= _dataList.size()) throw new IllegalArgumentException("Invalid row"); 123 124 switch (columnIndex) { 125 case COLUMN_TYPE: 126 return _dataList.get(rowIndex).getDataType(); 127 case COLUMN_DATA: 128 return _dataList.get(rowIndex).getData(); 129 case COLUMN_DELETE: 130 return Bundle.getMessage("ButtonDelete"); // NOI18N 131 case COLUMN_DUMMY: 132 return ""; 133 default: 134 throw new IllegalArgumentException("Invalid column"); 135 } 136 } 137 138 public void setColumnsForComboBoxes(JTable table) { 139 JComboBox<LogData.DataType> beanTypeComboBox = new JComboBox<>(); 140 table.setRowHeight(beanTypeComboBox.getPreferredSize().height); 141 table.getColumnModel().getColumn(COLUMN_TYPE) 142 .setPreferredWidth((beanTypeComboBox.getPreferredSize().width) + 4); 143 } 144 145 public void add() { 146 int row = _dataList.size(); 147 try { 148 _dataList.add(new LogData.Data(LogData.DataType.LocalVariable, "")); 149 } catch (ParserException e) { 150 throw new RuntimeException(e); // This should never happen 151 } 152 fireTableRowsInserted(row, row); 153 } 154 155 private void delete(int row) { 156 _dataList.remove(row); 157 fireTableRowsDeleted(row, row); 158 } 159 160 public List<LogData.Data> getDataList() { 161 return _dataList; 162 } 163 164 165 public static class CellRenderer extends DefaultTableCellRenderer { 166 167 @Override 168 public Component getTableCellRendererComponent(JTable table, Object value, 169 boolean isSelected, boolean hasFocus, int row, int column) { 170 171 if (column == COLUMN_TYPE) { 172 if (value == null) value = LogData.DataType.LocalVariable; 173 174 if (! (value instanceof LogData.DataType)) { 175 throw new IllegalArgumentException("value is not an LogData.DataType: " + value.getClass().getName()); 176 } 177 setText(((LogData.DataType) value).toString()); 178 } else { 179 throw new RuntimeException("Unknown column: "+Integer.toString(column)); 180 } 181 return this; 182 } 183 } 184 185 186 public static class DataTypeCellEditor extends AbstractCellEditor 187 implements TableCellEditor, ActionListener { 188 189 private LogData.DataType _beanType; 190 191 @Override 192 public Object getCellEditorValue() { 193 return this._beanType; 194 } 195 196 @Override 197 public Component getTableCellEditorComponent(JTable table, Object value, 198 boolean isSelected, int row, int column) { 199 200 if (value == null) value = LogData.DataType.LocalVariable; 201 202 if (! (value instanceof LogData.DataType)) { 203 throw new IllegalArgumentException("value is not an LogData.DataType: " + value.getClass().getName()); 204 } 205 206 JComboBox<LogData.DataType> returnValueTypeComboBox = new JComboBox<>(); 207 208 for (LogData.DataType type : LogData.DataType.values()) { 209 returnValueTypeComboBox.addItem(type); 210 } 211 JComboBoxUtil.setupComboBoxMaxRows(returnValueTypeComboBox); 212 213 returnValueTypeComboBox.setSelectedItem(value); 214 returnValueTypeComboBox.addActionListener(this); 215 216 return returnValueTypeComboBox; 217 } 218 219 @Override 220 @SuppressWarnings("unchecked") // Not possible to check that event.getSource() is instanceof JComboBox<LogData.DataType> 221 public void actionPerformed(ActionEvent event) { 222 if (! (event.getSource() instanceof JComboBox)) { 223 throw new IllegalArgumentException("value is not an JComboBox: " + event.getSource().getClass().getName()); 224 } 225 JComboBox<LogData.DataType> returnValueTypeComboBox = 226 (JComboBox<LogData.DataType>) event.getSource(); 227 _beanType = returnValueTypeComboBox.getItemAt(returnValueTypeComboBox.getSelectedIndex()); 228 229 } 230 231 } 232 233 234 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogDataTableModel.class); 235 236}