001package jmri.jmrit.logixng.expressions.swing;
002
003import java.awt.Dimension;
004import java.awt.event.ActionEvent;
005import java.util.*;
006
007import javax.annotation.CheckForNull;
008import javax.annotation.Nonnull;
009import javax.swing.*;
010import javax.swing.table.TableColumn;
011
012import jmri.InstanceManager;
013import jmri.jmrit.logixng.*;
014import jmri.jmrit.logixng.expressions.LogData;
015import jmri.jmrit.logixng.util.parser.*;
016import jmri.util.table.ButtonEditor;
017import jmri.util.table.ButtonRenderer;
018
019/**
020 * Configures an LogData object with a Swing JPanel.
021 *
022 * @author Daniel Bergqvist Copyright 2021
023 */
024public class LogDataSwing extends AbstractDigitalExpressionSwing {
025
026    private JComboBox<ResultType> _resultType;
027    private JCheckBox _logToLogCheckBox;
028    private JCheckBox _logToScriptOutputCheckBox;
029    private JComboBox<LogData.FormatType> _formatType;
030    private JTextField _format;
031    private JTable _logDataTable;
032    private LogDataTableModel _logDataTableModel;
033
034    @Override
035    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
036        if ((object != null) && (! (object instanceof LogData))) {
037            throw new IllegalArgumentException("object is not a LogData: " + object.getClass().getName());
038        }
039        LogData logData = (LogData)object;
040
041        panel = new JPanel();
042
043        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
044
045
046        JPanel resultTypePanel = new JPanel();
047        _resultType = new JComboBox<>();
048        for (ResultType formatType : ResultType.values()) {
049            _resultType.addItem(formatType);
050        }
051        resultTypePanel.add(new JLabel(Bundle.getMessage("LogData_ResultType")));
052        resultTypePanel.add(_resultType);
053        panel.add(resultTypePanel);
054
055
056        _logToLogCheckBox = new JCheckBox(Bundle.getMessage("LogData_LogToLog"));
057        _logToLogCheckBox.setSelected(true);    // Selected as default
058        panel.add(_logToLogCheckBox);
059
060        _logToScriptOutputCheckBox = new JCheckBox(Bundle.getMessage("LogData_LogToScriptOutput"));
061        panel.add(_logToScriptOutputCheckBox);
062
063
064        JPanel formatTypePanel = new JPanel();
065        _formatType = new JComboBox<>();
066        for (LogData.FormatType formatType : LogData.FormatType.values()) {
067            _formatType.addItem(formatType);
068        }
069        formatTypePanel.add(new JLabel(Bundle.getMessage("LogData_FormatType")));
070        formatTypePanel.add(_formatType);
071        panel.add(formatTypePanel);
072
073        JPanel formatPanel = new JPanel();
074        _format = new JTextField(20);
075        formatPanel.add(new JLabel(Bundle.getMessage("LogData_Format")));
076        formatPanel.add(_format);
077        panel.add(formatPanel);
078
079
080        if (logData != null) {
081            _resultType.setSelectedItem(ResultType.parseResult(logData.getResult()));
082            _logToLogCheckBox.setSelected(logData.getLogToLog());
083            _logToScriptOutputCheckBox.setSelected(logData.getLogToScriptOutput());
084            _formatType.setSelectedItem(logData.getFormatType());
085            _format.setText(logData.getFormat());
086        }
087
088
089        _logDataTable = new JTable();
090
091        if (logData != null) {
092            List<LogData.Data> dataList
093                    = new ArrayList<>(logData.getDataList());
094
095            _logDataTableModel = new LogDataTableModel(dataList);
096        } else {
097            _logDataTableModel = new LogDataTableModel(null);
098        }
099
100        _logDataTable.setModel(_logDataTableModel);
101        _logDataTable.setDefaultRenderer(LogData.DataType.class,
102                new LogDataTableModel.CellRenderer());
103        _logDataTable.setDefaultEditor(LogData.DataType.class,
104                new LogDataTableModel.DataTypeCellEditor());
105        _logDataTableModel.setColumnsForComboBoxes(_logDataTable);
106        _logDataTable.setDefaultRenderer(JButton.class, new ButtonRenderer());
107        _logDataTable.setDefaultEditor(JButton.class, new ButtonEditor(new JButton()));
108
109        JButton testButton = new JButton("XXXXXX");  // NOI18N
110        _logDataTable.setRowHeight(testButton.getPreferredSize().height);
111        TableColumn deleteColumn = _logDataTable.getColumnModel()
112                .getColumn(LogDataTableModel.COLUMN_DUMMY);
113        deleteColumn.setMinWidth(testButton.getPreferredSize().width);
114        deleteColumn.setMaxWidth(testButton.getPreferredSize().width);
115        deleteColumn.setResizable(false);
116
117        // The dummy column is used to be able to force update of the
118        // other columns when the panel is closed.
119        TableColumn dummyColumn = _logDataTable.getColumnModel()
120                .getColumn(LogDataTableModel.COLUMN_DUMMY);
121        dummyColumn.setMinWidth(0);
122        dummyColumn.setPreferredWidth(0);
123        dummyColumn.setMaxWidth(0);
124
125        JScrollPane scrollpane = new JScrollPane(_logDataTable);
126        scrollpane.setPreferredSize(new Dimension(400, 200));
127        panel.add(scrollpane);
128
129        // Add parameter
130        JButton add = new JButton(Bundle.getMessage("LogData_TableAdd"));
131        buttonPanel.add(add);
132        add.addActionListener((ActionEvent e) -> {
133            _logDataTableModel.add();
134        });
135    }
136
137    /** {@inheritDoc} */
138    @Override
139    public boolean validate(@Nonnull List<String> errorMessages) {
140        for (LogData.Data data : _logDataTableModel.getDataList()) {
141            if (data.getDataType() == LogData.DataType.Formula) {
142                try {
143                    Map<String, Variable> variables = new HashMap<>();
144                    RecursiveDescentParser parser = new RecursiveDescentParser(variables);
145                    parser.parseExpression(data.getData());
146                } catch (ParserException e) {
147                    errorMessages.add(e.getLocalizedMessage());
148                }
149            }
150        }
151        return true;
152    }
153
154    /** {@inheritDoc} */
155    @Override
156    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
157        LogData expression = new LogData(systemName, userName);
158        updateObject(expression);
159        return InstanceManager.getDefault(DigitalExpressionManager.class).registerExpression(expression);
160    }
161
162    /** {@inheritDoc} */
163    @Override
164    public void updateObject(@Nonnull Base object) {
165        if (! (object instanceof LogData)) {
166            throw new IllegalArgumentException("object is not a LogData: " + object.getClass().getName());
167        }
168        LogData logData = (LogData)object;
169
170
171        logData.setResult(_resultType.getItemAt(_resultType.getSelectedIndex()).getResult());
172
173        logData.setLogToLog(_logToLogCheckBox.isSelected());
174        logData.setLogToScriptOutput(_logToScriptOutputCheckBox.isSelected());
175
176        logData.setFormatType(_formatType.getItemAt(_formatType.getSelectedIndex()));
177        logData.setFormat(_format.getText());
178
179
180        // Do this to force update of the table
181        _logDataTable.editCellAt(0, 2);
182
183        logData.getDataList().clear();
184
185        for (LogData.Data data : _logDataTableModel.getDataList()) {
186            logData.getDataList().add(data);
187        }
188    }
189
190    /** {@inheritDoc} */
191    @Override
192    public String toString() {
193        return Bundle.getMessage("LogData_Short");
194    }
195
196    @Override
197    public void dispose() {
198    }
199
200
201    public enum ResultType {
202        True(Bundle.getMessage("LogData_ReturnType_True"), true),
203        False(Bundle.getMessage("LogData_ReturnType_False"), false);
204
205        private final String _text;
206        private boolean _result;
207
208        private ResultType(String text, boolean result) {
209            this._text = text;
210            this._result = result;
211        }
212
213        @Override
214        public String toString() {
215            return _text;
216        }
217
218        public boolean getResult() {
219            return _result;
220        }
221
222        public static ResultType parseResult(boolean result) {
223            return result ? ResultType.True : ResultType.False;
224        }
225
226    }
227
228}