001package jmri.jmrit.logixng.expressions.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.expressions.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                LogData.DataType oldType = ref.getDataType();
098                ref.setDataType((LogData.DataType) value);
099                if (oldType != ref.getDataType()) ref.setData("");
100                break;
101            case COLUMN_DATA:
102                ref.setData((String) value);
103                break;
104            case COLUMN_DELETE:
105                delete(rowIndex);
106                break;
107            case COLUMN_DUMMY:
108                break;
109            default:
110                throw new IllegalArgumentException("Invalid column");
111        }      
112    }
113    
114    /** {@inheritDoc} */
115    @Override
116    public Object getValueAt(int rowIndex, int columnIndex) {
117        if (rowIndex >= _dataList.size()) throw new IllegalArgumentException("Invalid row");
118        
119        switch (columnIndex) {
120            case COLUMN_TYPE:
121                return _dataList.get(rowIndex).getDataType();
122            case COLUMN_DATA:
123                return _dataList.get(rowIndex).getData();
124            case COLUMN_DELETE:
125                return Bundle.getMessage("ButtonDelete");  // NOI18N
126            case COLUMN_DUMMY:
127                return "";
128            default:
129                throw new IllegalArgumentException("Invalid column");
130        }
131    }
132    
133    public void setColumnsForComboBoxes(JTable table) {
134        JComboBox<LogData.DataType> beanTypeComboBox = new JComboBox<>();
135        table.setRowHeight(beanTypeComboBox.getPreferredSize().height);
136        table.getColumnModel().getColumn(COLUMN_TYPE)
137                .setPreferredWidth((beanTypeComboBox.getPreferredSize().width) + 4);
138    }
139    
140    public void add() {
141        int row = _dataList.size();
142        try {
143            _dataList.add(new LogData.Data(LogData.DataType.LocalVariable, ""));
144        } catch (ParserException e) {
145            throw new RuntimeException(e);  // This should never happen
146        }
147        fireTableRowsInserted(row, row);
148    }
149    
150    private void delete(int row) {
151        _dataList.remove(row);
152        fireTableRowsDeleted(row, row);
153    }
154    
155    public List<LogData.Data> getDataList() {
156        return _dataList;
157    }
158    
159    
160    public static class CellRenderer extends DefaultTableCellRenderer {
161
162        @Override
163        public Component getTableCellRendererComponent(JTable table, Object value,
164                boolean isSelected, boolean hasFocus, int row, int column) {
165            
166            if (column == COLUMN_TYPE) {
167                if (value == null) value = LogData.DataType.LocalVariable;
168                
169                if (! (value instanceof LogData.DataType)) {
170                    throw new IllegalArgumentException("value is not an LogData.DataType: " + value.getClass().getName());
171                }
172                setText(((LogData.DataType) value).toString());
173            } else {
174                throw new RuntimeException("Unknown column: "+Integer.toString(column));
175            }
176            return this;
177        }
178    }
179    
180    
181    public static class DataTypeCellEditor extends AbstractCellEditor
182            implements TableCellEditor, ActionListener {
183        
184        private LogData.DataType _beanType;
185        
186        @Override
187        public Object getCellEditorValue() {
188            return this._beanType;
189        }
190        
191        @Override
192        public Component getTableCellEditorComponent(JTable table, Object value,
193                boolean isSelected, int row, int column) {
194            
195            if (value == null) value = LogData.DataType.LocalVariable;
196            
197            if (! (value instanceof LogData.DataType)) {
198                throw new IllegalArgumentException("value is not an LogData.DataType: " + value.getClass().getName());
199            }
200            
201            JComboBox<LogData.DataType> returnValueTypeComboBox = new JComboBox<>();
202            
203            for (LogData.DataType type : LogData.DataType.values()) {
204                returnValueTypeComboBox.addItem(type);
205            }
206            JComboBoxUtil.setupComboBoxMaxRows(returnValueTypeComboBox);
207            
208            returnValueTypeComboBox.setSelectedItem(value);
209            returnValueTypeComboBox.addActionListener(this);
210            
211            return returnValueTypeComboBox;
212        }
213        
214        @Override
215        @SuppressWarnings("unchecked")  // Not possible to check that event.getSource() is instanceof JComboBox<LogData.DataType>
216        public void actionPerformed(ActionEvent event) {
217            if (! (event.getSource() instanceof JComboBox)) {
218                throw new IllegalArgumentException("value is not an JComboBox: " + event.getSource().getClass().getName());
219            }
220            JComboBox<LogData.DataType> returnValueTypeComboBox =
221                    (JComboBox<LogData.DataType>) event.getSource();
222            _beanType = returnValueTypeComboBox.getItemAt(returnValueTypeComboBox.getSelectedIndex());
223            
224        }
225        
226    }
227    
228/*    
229    public NamedBeanCellEditor getNamedBeanCellEditor() {
230        return new NamedBeanCellEditor();
231    }
232    
233    
234    public class NamedBeanCellEditor extends AbstractCellEditor
235            implements TableCellEditor, ActionListener {
236        
237        private String _namedBean;
238        
239        @Override
240        public Object getCellEditorValue() {
241            return this._namedBean;
242        }
243        
244        @Override
245        public Component getTableCellEditorComponent(JTable table, Object value,
246                boolean isSelected, int row, int column) {
247            
248            if ((value != null) && (! (value instanceof String))) {
249                throw new IllegalArgumentException("value is not a String: " + value.getClass().getName());
250            }
251            
252            JComboBox<String> namedBeanComboBox = new JComboBox<>();
253            SortedSet<? extends NamedBean> set =
254                    _dataList.get(row).getDataType().getManager().getNamedBeanSet();
255            
256            String name = _dataList.get(row).getData();
257            
258            if (!set.isEmpty()) {
259                for (NamedBean bean : set) {
260                    namedBeanComboBox.addItem(bean.getDisplayName());
261                    
262                    if (name != null) {
263                        if (name.equals(bean.getUserName()) || name.equals(bean.getSystemName())) {
264                            namedBeanComboBox.setSelectedItem(bean.getDisplayName());
265                        }
266                    }
267                }
268                JComboBoxUtil.setupComboBoxMaxRows(namedBeanComboBox);
269            } else {
270                namedBeanComboBox.addItem("");
271            }
272            
273//            namedBeanComboBox.setSelectedItem(value);
274            namedBeanComboBox.addActionListener(this);
275            
276            return namedBeanComboBox;
277        }
278        
279        @Override
280        @SuppressWarnings("unchecked")  // Not possible to check that event.getSource() is instanceof JComboBox<LogData.DataType>
281        public void actionPerformed(ActionEvent event) {
282            if (! (event.getSource() instanceof JComboBox)) {
283                throw new IllegalArgumentException("value is not an JComboBox: " + event.getSource().getClass().getName());
284            }
285            JComboBox<String> namedBeanComboBox = (JComboBox<String>) event.getSource();
286            int index = namedBeanComboBox.getSelectedIndex();
287            _namedBean = (index != -1) ? namedBeanComboBox.getItemAt(index) : null;
288        }
289        
290    }
291*/    
292}