001package jmri.jmrit.logixng.actions.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.actions.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 AbstractDigitalActionSwing {
025
026    private JCheckBox _logToLogCheckBox;
027    private JCheckBox _logToScriptOutputCheckBox;
028    private JComboBox<LogData.FormatType> _formatType;
029    private JTextField _format;
030    private JTable _logDataTable;
031    private LogDataTableModel _logDataTableModel;
032
033    @Override
034    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
035        if ((object != null) && (! (object instanceof LogData))) {
036            throw new IllegalArgumentException("object is not a LogData: " + object.getClass().getName());
037        }
038        LogData logData = (LogData)object;
039
040        panel = new JPanel();
041
042        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
043
044
045        _logToLogCheckBox = new JCheckBox(Bundle.getMessage("LogData_LogToLog"));
046        panel.add(_logToLogCheckBox);
047
048        _logToScriptOutputCheckBox = new JCheckBox(Bundle.getMessage("LogData_LogToScriptOutput"));
049        panel.add(_logToScriptOutputCheckBox);
050
051
052        JPanel formatTypePanel = new JPanel();
053        _formatType = new JComboBox<>();
054        for (LogData.FormatType formatType : LogData.FormatType.values()) {
055            _formatType.addItem(formatType);
056        }
057        formatTypePanel.add(new JLabel(Bundle.getMessage("LogData_FormatType")));
058        formatTypePanel.add(_formatType);
059        panel.add(formatTypePanel);
060
061        JPanel formatPanel = new JPanel();
062        _format = new JTextField(20);
063        formatPanel.add(new JLabel(Bundle.getMessage("LogData_Format")));
064        formatPanel.add(_format);
065        panel.add(formatPanel);
066
067
068        if (logData != null) {
069            _logToLogCheckBox.setSelected(logData.getLogToLog());
070            _logToScriptOutputCheckBox.setSelected(logData.getLogToScriptOutput());
071            _formatType.setSelectedItem(logData.getFormatType());
072            _format.setText(logData.getFormat());
073        }
074
075
076        _logDataTable = new JTable();
077
078        if (logData != null) {
079            List<LogData.Data> dataList
080                    = new ArrayList<>(logData.getDataList());
081
082            _logDataTableModel = new LogDataTableModel(dataList);
083        } else {
084            _logDataTableModel = new LogDataTableModel(null);
085        }
086
087        _logDataTable.setModel(_logDataTableModel);
088        _logDataTable.setDefaultRenderer(LogData.DataType.class,
089                new LogDataTableModel.CellRenderer());
090        _logDataTable.setDefaultEditor(LogData.DataType.class,
091                new LogDataTableModel.DataTypeCellEditor());
092        _logDataTableModel.setColumnsForComboBoxes(_logDataTable);
093        _logDataTable.setDefaultRenderer(JButton.class, new ButtonRenderer());
094        _logDataTable.setDefaultEditor(JButton.class, new ButtonEditor(new JButton()));
095
096        JButton testButton = new JButton("XXXXXX");  // NOI18N
097        _logDataTable.setRowHeight(testButton.getPreferredSize().height);
098        TableColumn deleteColumn = _logDataTable.getColumnModel()
099                .getColumn(LogDataTableModel.COLUMN_DUMMY);
100        deleteColumn.setMinWidth(testButton.getPreferredSize().width);
101        deleteColumn.setMaxWidth(testButton.getPreferredSize().width);
102        deleteColumn.setResizable(false);
103
104        // The dummy column is used to be able to force update of the
105        // other columns when the panel is closed.
106        TableColumn dummyColumn = _logDataTable.getColumnModel()
107                .getColumn(LogDataTableModel.COLUMN_DUMMY);
108        dummyColumn.setMinWidth(0);
109        dummyColumn.setPreferredWidth(0);
110        dummyColumn.setMaxWidth(0);
111
112        JScrollPane scrollpane = new JScrollPane(_logDataTable);
113        scrollpane.setPreferredSize(new Dimension(400, 200));
114        panel.add(scrollpane);
115
116        // Add parameter
117        JButton add = new JButton(Bundle.getMessage("LogData_TableAdd"));
118        buttonPanel.add(add);
119        add.addActionListener((ActionEvent e) -> {
120            _logDataTableModel.add();
121        });
122    }
123
124    /** {@inheritDoc} */
125    @Override
126    public boolean validate(@Nonnull List<String> errorMessages) {
127        boolean result = true;
128        for (LogData.Data data : _logDataTableModel.getDataList()) {
129            if (data.getDataType() == LogData.DataType.Formula) {
130                try {
131                    Map<String, Variable> variables = new HashMap<>();
132                    RecursiveDescentParser parser = new RecursiveDescentParser(variables);
133                    parser.parseExpression(data.getData());
134                } catch (ParserException e) {
135                    errorMessages.add(e.getLocalizedMessage());
136                    result = false;
137                }
138            }
139        }
140        return result;
141    }
142
143    /** {@inheritDoc} */
144    @Override
145    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
146        LogData action = new LogData(systemName, userName);
147        updateObject(action);
148        return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action);
149    }
150
151    /** {@inheritDoc} */
152    @Override
153    public void updateObject(@Nonnull Base object) {
154        if (! (object instanceof LogData)) {
155            throw new IllegalArgumentException("object is not a LogData: " + object.getClass().getName());
156        }
157        LogData logData = (LogData)object;
158
159
160        logData.setLogToLog(_logToLogCheckBox.isSelected());
161        logData.setLogToScriptOutput(_logToScriptOutputCheckBox.isSelected());
162
163        logData.setFormatType(_formatType.getItemAt(_formatType.getSelectedIndex()));
164        logData.setFormat(_format.getText());
165
166
167        // Do this to force update of the table
168        _logDataTable.editCellAt(0, 2);
169
170        logData.getDataList().clear();
171
172        for (LogData.Data data : _logDataTableModel.getDataList()) {
173            logData.getDataList().add(data);
174        }
175    }
176
177    /** {@inheritDoc} */
178    @Override
179    public String toString() {
180        return Bundle.getMessage("LogData_Short");
181    }
182
183    @Override
184    public void dispose() {
185    }
186
187}