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}