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                variable._initialValueType = (InitialValueType) value;
118                break;
119            case COLUMN_INPUT_DATA:
120                variable._initialValueData = (String) value;
121                break;
122            case COLUMN_OUTPUT_TYPE:
123                variable._returnValueType = (ReturnValueType) value;
124                break;
125            case COLUMN_OUTPUT_DATA:
126                variable._returnValueData = (String) value;
127                break;
128            default:
129                throw new IllegalArgumentException("Invalid column");
130        }      
131    }
132    
133    /** {@inheritDoc} */
134    @Override
135    public Object getValueAt(int rowIndex, int columnIndex) {
136        if (rowIndex >= _parameterData.size()) throw new IllegalArgumentException("Invalid row");
137        
138        switch (columnIndex) {
139            case COLUMN_NAME:
140                return _parameterData.get(rowIndex).getName();
141            case COLUMN_INPUT_TYPE:
142                return _parameterData.get(rowIndex).getInitialValueType();
143            case COLUMN_INPUT_DATA:
144                return _parameterData.get(rowIndex).getInitialValueData();
145            case COLUMN_OUTPUT_TYPE:
146                return _parameterData.get(rowIndex).getReturnValueType();
147            case COLUMN_OUTPUT_DATA:
148                return _parameterData.get(rowIndex).getReturnValueData();
149            default:
150                throw new IllegalArgumentException("Invalid column");
151        }
152    }
153    
154    public void setColumnsForComboBoxes(JTable table) {
155        JComboBox<InitialValueType> initValueComboBox = new JComboBox<>();
156        JComboBox<ReturnValueType> returnValueComboBox = new JComboBox<>();
157        table.setRowHeight(initValueComboBox.getPreferredSize().height);
158        table.getColumnModel().getColumn(COLUMN_INPUT_TYPE)
159                .setPreferredWidth((initValueComboBox.getPreferredSize().width) + 4);
160        table.getColumnModel().getColumn(COLUMN_OUTPUT_TYPE)
161                .setPreferredWidth((returnValueComboBox.getPreferredSize().width) + 4);
162    }
163    
164    public void add() {
165        int row = _parameterData.size();
166        _parameterData.add(new ParameterData("", InitialValueType.None, "", ReturnValueType.None, ""));
167        fireTableRowsInserted(row, row);
168    }
169    
170    public List<ParameterData> getParameters() {
171        return _parameterData;
172    }
173    
174    
175    public static class TypeCellRenderer extends DefaultTableCellRenderer {
176
177        @Override
178        public Component getTableCellRendererComponent(JTable table, Object value,
179                boolean isSelected, boolean hasFocus, int row, int column) {
180            
181            if (column == COLUMN_INPUT_TYPE) {
182                if (value == null) value = InitialValueType.None;
183
184                if (! (value instanceof InitialValueType)) {
185                    throw new IllegalArgumentException("value is not an InitialValueType: " + value.getClass().getName());
186                }
187                setText(((InitialValueType) value).toString());
188            }
189            else if (column == COLUMN_OUTPUT_TYPE) {
190                if (value == null) value = ReturnValueType.None;
191
192                if (! (value instanceof ReturnValueType)) {
193                    throw new IllegalArgumentException("value is not an ReturnValueType: " + value.getClass().getName());
194                }
195                setText(((ReturnValueType) value).getDescr());
196            } else {
197                throw new RuntimeException("Unknown column: "+Integer.toString(column));
198            }
199            return this;
200        }
201    }
202    
203    
204    public static class InitialValueCellEditor extends AbstractCellEditor
205            implements TableCellEditor, ActionListener {
206
207        private InitialValueType _initialValueType;
208        
209        @Override
210        public Object getCellEditorValue() {
211            return this._initialValueType;
212        }
213        
214        @Override
215        public Component getTableCellEditorComponent(JTable table, Object value,
216                boolean isSelected, int row, int column) {
217            
218            if (value == null) value = InitialValueType.None;
219            
220            if (! (value instanceof InitialValueType)) {
221                throw new IllegalArgumentException("value is not an InitialValueType: " + value.getClass().getName());
222            }
223            
224            JComboBox<InitialValueType> initialValueTypeComboBox = new JComboBox<>();
225            
226            for (InitialValueType type : InitialValueType.values()) {
227                if (type.isValidAsParameter()) initialValueTypeComboBox.addItem(type);
228            }
229            JComboBoxUtil.setupComboBoxMaxRows(initialValueTypeComboBox);
230            
231            initialValueTypeComboBox.setSelectedItem(value);
232            initialValueTypeComboBox.addActionListener(this);
233            
234            return initialValueTypeComboBox;
235        }
236        
237        @Override
238        @SuppressWarnings("unchecked")  // Not possible to check that event.getSource() is instanceof JComboBox<InitialValueType>
239        public void actionPerformed(ActionEvent event) {
240            if (! (event.getSource() instanceof JComboBox)) {
241                throw new IllegalArgumentException("value is not an JComboBox: " + event.getSource().getClass().getName());
242            }
243            JComboBox<InitialValueType> initialValueTypeComboBox =
244                    (JComboBox<InitialValueType>) event.getSource();
245            _initialValueType = initialValueTypeComboBox.getItemAt(initialValueTypeComboBox.getSelectedIndex());
246            
247        }
248        
249    }
250    
251    
252    public static class ReturnValueCellEditor extends AbstractCellEditor
253            implements TableCellEditor, ActionListener {
254        
255        private ReturnValueType _returnValueType;
256        
257        @Override
258        public Object getCellEditorValue() {
259            return this._returnValueType;
260        }
261        
262        @Override
263        public Component getTableCellEditorComponent(JTable table, Object value,
264                boolean isSelected, int row, int column) {
265            
266            if (value == null) value = ReturnValueType.None;
267            
268            if (! (value instanceof ReturnValueType)) {
269                throw new IllegalArgumentException("value is not an ReturnValueType: " + value.getClass().getName());
270            }
271            
272            JComboBox<ReturnValueType> returnValueTypeComboBox = new JComboBox<>();
273            
274            for (ReturnValueType type : ReturnValueType.values()) {
275                returnValueTypeComboBox.addItem(type);
276            }
277            JComboBoxUtil.setupComboBoxMaxRows(returnValueTypeComboBox);
278            
279            returnValueTypeComboBox.setSelectedItem(value);
280            returnValueTypeComboBox.addActionListener(this);
281            
282            return returnValueTypeComboBox;
283        }
284        
285        @Override
286        @SuppressWarnings("unchecked")  // Not possible to check that event.getSource() is instanceof JComboBox<ReturnValueType>
287        public void actionPerformed(ActionEvent event) {
288            if (! (event.getSource() instanceof JComboBox)) {
289                throw new IllegalArgumentException("value is not an JComboBox: " + event.getSource().getClass().getName());
290            }
291            JComboBox<ReturnValueType> returnValueTypeComboBox =
292                    (JComboBox<ReturnValueType>) event.getSource();
293            _returnValueType = returnValueTypeComboBox.getItemAt(returnValueTypeComboBox.getSelectedIndex());
294            
295        }
296        
297    }
298    
299}