001package jmri.jmrit.logixng.tools.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.Module;
014import jmri.jmrit.logixng.Module.Parameter;
015import jmri.jmrit.logixng.Module.ParameterData;
016import jmri.jmrit.logixng.Module.ReturnValueType;
017import jmri.jmrit.logixng.SymbolTable.InitialValueType;
018import jmri.util.swing.JComboBoxUtil;
019
020/**
021 * Table model for CallModule parameters
022 * @author Daniel Bergqvist Copyright 2020
023 */
024public class CallModuleParameterTableModel extends AbstractTableModel {
025
026    public static final int COLUMN_NAME = 0;
027    public static final int COLUMN_INPUT_TYPE = 1;
028    public static final int COLUMN_INPUT_DATA = 2;
029    public static final int COLUMN_OUTPUT_TYPE = 3;
030    public static final int COLUMN_OUTPUT_DATA = 4;
031
032    private final List<ParameterData> _parameterData = new ArrayList<>();
033
034
035    public CallModuleParameterTableModel(Module module, List<ParameterData> parameterData) {
036        if (module != null) {
037            Map<String, ParameterData> parameterDataMap = new HashMap<>();
038            for (ParameterData pd : parameterData) {
039                parameterDataMap.put(pd._name, new ParameterData(pd));
040            }
041            for (Parameter p : module.getParameters()) {
042                if (parameterDataMap.containsKey(p.getName())) {
043                    _parameterData.add(parameterDataMap.get(p.getName()));
044                } else {
045                    _parameterData.add(new ParameterData(
046                            p.getName(), InitialValueType.None, "",
047                            ReturnValueType.None, ""));
048                }
049            }
050        }
051    }
052
053    /** {@inheritDoc} */
054    @Override
055    public int getRowCount() {
056        return _parameterData.size();
057    }
058
059    /** {@inheritDoc} */
060    @Override
061    public int getColumnCount() {
062        return 5;
063    }
064
065    /** {@inheritDoc} */
066    @Override
067    public String getColumnName(int col) {
068        switch (col) {
069            case COLUMN_NAME:
070                return Bundle.getMessage("ColumnParameterName");
071            case COLUMN_INPUT_TYPE:
072                return Bundle.getMessage("ColumnInputParameterType");
073            case COLUMN_INPUT_DATA:
074                return Bundle.getMessage("ColumnInputParameterData");
075            case COLUMN_OUTPUT_TYPE:
076                return Bundle.getMessage("ColumnOutputParameterType");
077            case COLUMN_OUTPUT_DATA:
078                return Bundle.getMessage("ColumnOutputParameterData");
079            default:
080                throw new IllegalArgumentException("Invalid column");
081        }
082    }
083
084    /** {@inheritDoc} */
085    @Override
086    public Class<?> getColumnClass(int col) {
087        switch (col) {
088            case COLUMN_INPUT_TYPE:
089                return InitialValueType.class;
090            case COLUMN_OUTPUT_TYPE:
091                return ReturnValueType.class;
092            case COLUMN_NAME:
093            case COLUMN_INPUT_DATA:
094            case COLUMN_OUTPUT_DATA:
095                return String.class;
096            default:
097                throw new IllegalArgumentException("Invalid column");
098        }
099    }
100
101    /** {@inheritDoc} */
102    @Override
103    public boolean isCellEditable(int row, int col) {
104        return col != COLUMN_NAME;
105    }
106
107    /** {@inheritDoc} */
108    @Override
109    public void setValueAt(Object value, int rowIndex, int columnIndex) {
110        ParameterData variable = _parameterData.get(rowIndex);
111
112        switch (columnIndex) {
113            case COLUMN_NAME:
114                variable._name = (String) value;
115                break;
116            case COLUMN_INPUT_TYPE:
117                if (value != null) {
118                    variable._initialValueType = (InitialValueType) value;
119                } else {
120                    variable._initialValueType = InitialValueType.None;
121                }
122                break;
123            case COLUMN_INPUT_DATA:
124                variable._initialValueData = (String) value;
125                break;
126            case COLUMN_OUTPUT_TYPE:
127                variable._returnValueType = (ReturnValueType) value;
128                break;
129            case COLUMN_OUTPUT_DATA:
130                variable._returnValueData = (String) value;
131                break;
132            default:
133                throw new IllegalArgumentException("Invalid column");
134        }
135    }
136
137    /** {@inheritDoc} */
138    @Override
139    public Object getValueAt(int rowIndex, int columnIndex) {
140        if (rowIndex >= _parameterData.size()) throw new IllegalArgumentException("Invalid row");
141
142        switch (columnIndex) {
143            case COLUMN_NAME:
144                return _parameterData.get(rowIndex).getName();
145            case COLUMN_INPUT_TYPE:
146                return _parameterData.get(rowIndex).getInitialValueType();
147            case COLUMN_INPUT_DATA:
148                return _parameterData.get(rowIndex).getInitialValueData();
149            case COLUMN_OUTPUT_TYPE:
150                return _parameterData.get(rowIndex).getReturnValueType();
151            case COLUMN_OUTPUT_DATA:
152                return _parameterData.get(rowIndex).getReturnValueData();
153            default:
154                throw new IllegalArgumentException("Invalid column");
155        }
156    }
157
158    public void setColumnsForComboBoxes(JTable table) {
159        JComboBox<InitialValueType> initValueComboBox = new JComboBox<>();
160        JComboBox<ReturnValueType> returnValueComboBox = new JComboBox<>();
161        table.setRowHeight(initValueComboBox.getPreferredSize().height);
162        table.getColumnModel().getColumn(COLUMN_INPUT_TYPE)
163                .setPreferredWidth((initValueComboBox.getPreferredSize().width) + 4);
164        table.getColumnModel().getColumn(COLUMN_OUTPUT_TYPE)
165                .setPreferredWidth((returnValueComboBox.getPreferredSize().width) + 4);
166    }
167
168    public void add() {
169        int row = _parameterData.size();
170        _parameterData.add(new ParameterData("", InitialValueType.None, "", ReturnValueType.None, ""));
171        fireTableRowsInserted(row, row);
172    }
173
174    public List<ParameterData> getParameters() {
175        return _parameterData;
176    }
177
178
179    public static class TypeCellRenderer extends DefaultTableCellRenderer {
180
181        @Override
182        public Component getTableCellRendererComponent(JTable table, Object value,
183                boolean isSelected, boolean hasFocus, int row, int column) {
184
185            if (column == COLUMN_INPUT_TYPE) {
186                if (value == null) value = InitialValueType.None;
187
188                if (! (value instanceof InitialValueType)) {
189                    throw new IllegalArgumentException("value is not an InitialValueType: " + value.getClass().getName());
190                }
191                setText(((InitialValueType) value).toString());
192            }
193            else if (column == COLUMN_OUTPUT_TYPE) {
194                if (value == null) value = ReturnValueType.None;
195
196                if (! (value instanceof ReturnValueType)) {
197                    throw new IllegalArgumentException("value is not an ReturnValueType: " + value.getClass().getName());
198                }
199                setText(((ReturnValueType) value).getDescr());
200            } else {
201                throw new RuntimeException("Unknown column: "+Integer.toString(column));
202            }
203            return this;
204        }
205    }
206
207
208    public static class InitialValueCellEditor extends AbstractCellEditor
209            implements TableCellEditor, ActionListener {
210
211        private InitialValueType _initialValueType;
212
213        @Override
214        public Object getCellEditorValue() {
215            return this._initialValueType;
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> initialValueTypeComboBox = new JComboBox<>();
229
230            for (InitialValueType type : InitialValueType.values()) {
231                if (type.isValidAsParameter()) initialValueTypeComboBox.addItem(type);
232            }
233            JComboBoxUtil.setupComboBoxMaxRows(initialValueTypeComboBox);
234
235            initialValueTypeComboBox.setSelectedItem(value);
236            initialValueTypeComboBox.addActionListener(this);
237
238            return initialValueTypeComboBox;
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 JComboBox: " + event.getSource().getClass().getName());
246            }
247            JComboBox<InitialValueType> initialValueTypeComboBox =
248                    (JComboBox<InitialValueType>) event.getSource();
249            _initialValueType = initialValueTypeComboBox.getItemAt(initialValueTypeComboBox.getSelectedIndex());
250
251        }
252
253    }
254
255
256    public static class ReturnValueCellEditor extends AbstractCellEditor
257            implements TableCellEditor, ActionListener {
258
259        private ReturnValueType _returnValueType;
260
261        @Override
262        public Object getCellEditorValue() {
263            return this._returnValueType;
264        }
265
266        @Override
267        public Component getTableCellEditorComponent(JTable table, Object value,
268                boolean isSelected, int row, int column) {
269
270            if (value == null) value = ReturnValueType.None;
271
272            if (! (value instanceof ReturnValueType)) {
273                throw new IllegalArgumentException("value is not an ReturnValueType: " + value.getClass().getName());
274            }
275
276            JComboBox<ReturnValueType> returnValueTypeComboBox = new JComboBox<>();
277
278            for (ReturnValueType type : ReturnValueType.values()) {
279                returnValueTypeComboBox.addItem(type);
280            }
281            JComboBoxUtil.setupComboBoxMaxRows(returnValueTypeComboBox);
282
283            returnValueTypeComboBox.setSelectedItem(value);
284            returnValueTypeComboBox.addActionListener(this);
285
286            return returnValueTypeComboBox;
287        }
288
289        @Override
290        @SuppressWarnings("unchecked")  // Not possible to check that event.getSource() is instanceof JComboBox<ReturnValueType>
291        public void actionPerformed(ActionEvent event) {
292            if (! (event.getSource() instanceof JComboBox<?>)) {
293                throw new IllegalArgumentException("value is not an JComboBox: " + event.getSource().getClass().getName());
294            }
295            JComboBox<ReturnValueType> returnValueTypeComboBox =
296                    (JComboBox<ReturnValueType>) event.getSource();
297            _returnValueType = returnValueTypeComboBox.getItemAt(returnValueTypeComboBox.getSelectedIndex());
298
299        }
300
301    }
302
303}