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