001package jmri.jmrit.logixng.actions.swing;
002
003import java.util.List;
004
005import javax.annotation.CheckForNull;
006import javax.annotation.Nonnull;
007import javax.swing.*;
008
009import jmri.*;
010import jmri.jmrit.logixng.*;
011import jmri.jmrit.logixng.actions.TableForEach;
012import jmri.jmrit.logixng.TableRowOrColumn;
013import jmri.jmrit.logixng.util.parser.ParserException;
014import jmri.jmrit.logixng.util.swing.LogixNG_SelectNamedBeanSwing;
015import jmri.util.swing.JComboBoxUtil;
016
017/**
018 * Configures an TableForEach object with a Swing JPanel.
019 *
020 * @author Daniel Bergqvist Copyright 2021
021 */
022public class TableForEachSwing extends AbstractDigitalActionSwing {
023
024    private LogixNG_SelectNamedBeanSwing<NamedTable> _selectNamedBeanSwing;
025
026    private JComboBox<TableRowOrColumn> _tableRowOrColumnComboBox;
027
028    private JLabel _panelRowOrColumnLabel;
029    private JTabbedPane _tabbedRowOrColumnPane;
030    private JPanel _panelRowOrColumnName;
031    private JPanel _panelRowOrColumnReference;
032    private JPanel _panelRowOrColumnLocalVariable;
033    private JPanel _panelRowOrColumnFormula;
034    private JComboBox<String> _rowOrColumnNameComboBox;
035    private JTextField _rowOrColumnNameTextField;
036
037    private JTextField _referenceRowOrColumnTextField;
038    private JTextField _localRowOrColumnVariableTextField;
039    private JTextField _formulaRowOrColumnTextField;
040
041    private JTextField _localVariable;
042
043    @Override
044    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
045        if ((object != null) && !(object instanceof TableForEach)) {
046            throw new IllegalArgumentException("object must be an TableForEach but is a: "+object.getClass().getName());
047        }
048
049        TableForEach action = (TableForEach)object;
050
051        panel = new JPanel();
052        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
053
054        _selectNamedBeanSwing = new LogixNG_SelectNamedBeanSwing<>(
055                InstanceManager.getDefault(NamedTableManager.class), getJDialog(), this);
056
057        _panelRowOrColumnLabel = new JLabel(Bundle.getMessage("TableForEachSwing_RowName"));
058
059        _tableRowOrColumnComboBox = new JComboBox<>();
060        for (TableRowOrColumn item : TableRowOrColumn.values()) {
061            _tableRowOrColumnComboBox.addItem(item);
062        }
063        JComboBoxUtil.setupComboBoxMaxRows(_tableRowOrColumnComboBox);
064        _tableRowOrColumnComboBox.addActionListener((evt) -> {
065            setupRowOrColumnNameComboBox(action != null ? action.getRowOrColumnName() : null);
066
067            if (_tableRowOrColumnComboBox.getItemAt(_tableRowOrColumnComboBox.getSelectedIndex()) == TableRowOrColumn.Row) {
068                _panelRowOrColumnLabel.setText(Bundle.getMessage("TableForEachSwing_RowName"));
069            } else {
070                _panelRowOrColumnLabel.setText(Bundle.getMessage("TableForEachSwing_ColumnName"));
071            }
072        });
073
074        JPanel tableRowOrColumnPanel = new JPanel();
075        tableRowOrColumnPanel.add(new JLabel(Bundle.getMessage("TableForEachSwing_RowOrColumn")));
076        tableRowOrColumnPanel.add(_tableRowOrColumnComboBox);
077        panel.add(tableRowOrColumnPanel);
078
079        JPanel tabbedPanesPanel = new JPanel();
080        tabbedPanesPanel.setLayout(new BoxLayout(tabbedPanesPanel, BoxLayout.X_AXIS));
081
082        JPanel tabbedTablePane;
083
084        if (action != null) {
085            tabbedTablePane = _selectNamedBeanSwing.createPanel(action.getSelectNamedBean());
086        } else {
087            tabbedTablePane = _selectNamedBeanSwing.createPanel(null);
088        }
089
090        _selectNamedBeanSwing.addAddressingListener((evt) -> {
091            boolean isDirectAddressing = (_selectNamedBeanSwing.getAddressing() == NamedBeanAddressing.Direct);
092            _rowOrColumnNameComboBox.setVisible(isDirectAddressing);
093            _rowOrColumnNameTextField.setVisible(!isDirectAddressing);
094        });
095
096        _selectNamedBeanSwing.getBeanSelectPanel().getBeanCombo().addActionListener((evt) -> {
097            setupRowOrColumnNameComboBox(action != null ? action.getRowOrColumnName() : null);
098        });
099
100        tabbedPanesPanel.add(new JLabel(Bundle.getMessage("TableForEachSwing_Table")));
101
102        tabbedPanesPanel.add(tabbedTablePane);
103
104        _tabbedRowOrColumnPane = new JTabbedPane();
105        _panelRowOrColumnName = new javax.swing.JPanel();
106        _panelRowOrColumnReference = new javax.swing.JPanel();
107        _panelRowOrColumnLocalVariable = new javax.swing.JPanel();
108        _panelRowOrColumnFormula = new javax.swing.JPanel();
109
110        _tabbedRowOrColumnPane.addTab(NamedBeanAddressing.Direct.toString(), _panelRowOrColumnName);
111        _tabbedRowOrColumnPane.addTab(NamedBeanAddressing.Reference.toString(), _panelRowOrColumnReference);
112        _tabbedRowOrColumnPane.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelRowOrColumnLocalVariable);
113        _tabbedRowOrColumnPane.addTab(NamedBeanAddressing.Formula.toString(), _panelRowOrColumnFormula);
114
115        _rowOrColumnNameComboBox = new JComboBox<>();
116        _panelRowOrColumnName.add(_rowOrColumnNameComboBox);
117        _rowOrColumnNameTextField = new JTextField(20);
118        _rowOrColumnNameTextField.setVisible(false);
119        _panelRowOrColumnName.add(_rowOrColumnNameTextField);
120        JComboBoxUtil.setupComboBoxMaxRows(_rowOrColumnNameComboBox);
121
122        _referenceRowOrColumnTextField = new JTextField();
123        _referenceRowOrColumnTextField.setColumns(20);
124        _panelRowOrColumnReference.add(_referenceRowOrColumnTextField);
125
126        _localRowOrColumnVariableTextField = new JTextField();
127        _localRowOrColumnVariableTextField.setColumns(20);
128        _panelRowOrColumnLocalVariable.add(_localRowOrColumnVariableTextField);
129
130        _formulaRowOrColumnTextField = new JTextField();
131        _formulaRowOrColumnTextField.setColumns(20);
132        _panelRowOrColumnFormula.add(_formulaRowOrColumnTextField);
133
134        tabbedPanesPanel.add(_panelRowOrColumnLabel);
135
136        tabbedPanesPanel.add(_tabbedRowOrColumnPane);
137
138        panel.add(tabbedPanesPanel);
139
140        JPanel localVariablePanel = new JPanel();
141        localVariablePanel.add(new JLabel(Bundle.getMessage("TableForEachSwing_LocalVariable")));
142        _localVariable = new JTextField(20);
143        localVariablePanel.add(_localVariable);
144        panel.add(localVariablePanel);
145
146        JPanel infoPanel = new JPanel();
147        infoPanel.add(new JLabel(Bundle.getMessage("TableForEachSwing_Info")));
148        panel.add(infoPanel);
149
150        if (action != null) {
151            _tableRowOrColumnComboBox.setSelectedItem(action.getRowOrColumn());
152
153            switch (action.getRowOrColumnAddressing()) {
154                case Direct: _tabbedRowOrColumnPane.setSelectedComponent(_panelRowOrColumnName); break;
155                case Reference: _tabbedRowOrColumnPane.setSelectedComponent(_panelRowOrColumnReference); break;
156                case LocalVariable: _tabbedRowOrColumnPane.setSelectedComponent(_panelRowOrColumnLocalVariable); break;
157                case Formula: _tabbedRowOrColumnPane.setSelectedComponent(_panelRowOrColumnFormula); break;
158                default: throw new IllegalArgumentException("invalid _rowOrColumnAddressing state: " + action.getRowOrColumnAddressing().name());
159            }
160
161            _rowOrColumnNameTextField.setText(action.getRowOrColumnName());
162            _referenceRowOrColumnTextField.setText(action.getRowOrColumnReference());
163            _localRowOrColumnVariableTextField.setText(action.getRowOrColumnLocalVariable());
164            _formulaRowOrColumnTextField.setText(action.getRowOrColumnFormula());
165
166            _localVariable.setText(action.getLocalVariableName());
167        }
168    }
169
170    private void setupRowOrColumnNameComboBox(String rowOrColumnName) {
171        if (_selectNamedBeanSwing.getAddressing() == NamedBeanAddressing.Direct) {
172            _rowOrColumnNameComboBox.removeAllItems();
173            NamedTable table = _selectNamedBeanSwing.getBean();
174            if (table != null) {
175                _rowOrColumnNameComboBox.addItem(Bundle.getMessage("TableForEach_Header"));
176
177                if (_tableRowOrColumnComboBox.getItemAt(_tableRowOrColumnComboBox.getSelectedIndex()) == TableRowOrColumn.Column) {
178                    for (int column=0; column <= table.numColumns(); column++) {
179                        // If the header is null or empty, treat the row as a comment
180                        Object header = table.getCell(0, column);
181                        if ((header != null) && (!header.toString().isEmpty())) {
182                            _rowOrColumnNameComboBox.addItem(header.toString());
183                        }
184                    }
185                } else {
186                    for (int row=0; row <= table.numRows(); row++) {
187                        // If the header is null or empty, treat the row as a comment
188                        Object header = table.getCell(row, 0);
189                        if ((header != null) && (!header.toString().isEmpty())) {
190                            _rowOrColumnNameComboBox.addItem(header.toString());
191                        }
192                    }
193                }
194                if (rowOrColumnName == null || rowOrColumnName.isEmpty()) {    // Header row or column
195                    _rowOrColumnNameComboBox.setSelectedIndex(0);
196                } else {
197                    _rowOrColumnNameComboBox.setSelectedItem(rowOrColumnName);
198                }
199            }
200        }
201    }
202
203    /** {@inheritDoc} */
204    @Override
205    public boolean validate(@Nonnull List<String> errorMessages) {
206        // Create a temporary action to test formula
207        TableForEach action = new TableForEach("IQDA1", null);
208
209        _selectNamedBeanSwing.validate(action.getSelectNamedBean(), errorMessages);
210
211        try {
212            if (_tabbedRowOrColumnPane.getSelectedComponent() == _panelRowOrColumnName) {
213                action.setRowOrColumnAddressing(NamedBeanAddressing.Direct);
214            } else if (_tabbedRowOrColumnPane.getSelectedComponent() == _panelRowOrColumnReference) {
215                action.setRowOrColumnAddressing(NamedBeanAddressing.Reference);
216            } else if (_tabbedRowOrColumnPane.getSelectedComponent() == _panelRowOrColumnLocalVariable) {
217                action.setRowOrColumnAddressing(NamedBeanAddressing.LocalVariable);
218            } else if (_tabbedRowOrColumnPane.getSelectedComponent() == _panelRowOrColumnFormula) {
219                action.setRowOrColumnFormula(_formulaRowOrColumnTextField.getText());
220                action.setRowOrColumnAddressing(NamedBeanAddressing.Formula);
221            } else {
222                throw new IllegalArgumentException("_tabbedRowOrColumnPane has unknown selection");
223            }
224        } catch (ParserException e) {
225            errorMessages.add("Cannot parse formula: " + e.getMessage());
226            return false;
227        }
228        return true;
229    }
230
231    /** {@inheritDoc} */
232    @Override
233    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
234        TableForEach action = new TableForEach(systemName, userName);
235        updateObject(action);
236        return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action);
237    }
238
239    /** {@inheritDoc} */
240    @Override
241    public void updateObject(@Nonnull Base object) {
242        if (!(object instanceof TableForEach)) {
243            throw new IllegalArgumentException("object must be an TableForEach but is a: "+object.getClass().getName());
244        }
245
246
247        TableForEach action = (TableForEach)object;
248        action.setRowOrColumn(_tableRowOrColumnComboBox.getItemAt(_tableRowOrColumnComboBox.getSelectedIndex()));
249        _selectNamedBeanSwing.updateObject(action.getSelectNamedBean());
250
251        try {
252            if (_tabbedRowOrColumnPane.getSelectedComponent() == _panelRowOrColumnName) {
253                action.setRowOrColumnAddressing(NamedBeanAddressing.Direct);
254                if (_selectNamedBeanSwing.getAddressing() == NamedBeanAddressing.Direct) {
255                    if (_rowOrColumnNameComboBox.getSelectedIndex() > 0) {
256                        action.setRowOrColumnName(_rowOrColumnNameComboBox.getItemAt(_rowOrColumnNameComboBox.getSelectedIndex()));
257                    } else {
258                        action.setRowOrColumnName("");  // Header row or column
259                    }
260                } else {
261                    action.setRowOrColumnName(_rowOrColumnNameTextField.getText());
262                }
263            } else if (_tabbedRowOrColumnPane.getSelectedComponent() == _panelRowOrColumnReference) {
264                action.setRowOrColumnAddressing(NamedBeanAddressing.Reference);
265                action.setRowOrColumnReference(_referenceRowOrColumnTextField.getText());
266            } else if (_tabbedRowOrColumnPane.getSelectedComponent() == _panelRowOrColumnLocalVariable) {
267                action.setRowOrColumnAddressing(NamedBeanAddressing.LocalVariable);
268                action.setRowOrColumnLocalVariable(_localRowOrColumnVariableTextField.getText());
269            } else if (_tabbedRowOrColumnPane.getSelectedComponent() == _panelRowOrColumnFormula) {
270                action.setRowOrColumnAddressing(NamedBeanAddressing.Formula);
271                action.setRowOrColumnFormula(_formulaRowOrColumnTextField.getText());
272            } else {
273                throw new IllegalArgumentException("_tabbedPaneTurnoutState has unknown selection");
274            }
275
276            action.setLocalVariableName(_localVariable.getText());
277        } catch (ParserException e) {
278            throw new RuntimeException("ParserException: "+e.getMessage(), e);
279        }
280    }
281
282    /** {@inheritDoc} */
283    @Override
284    public String toString() {
285        return Bundle.getMessage("TableForEach_Short");
286    }
287
288    @Override
289    public void dispose() {
290    }
291
292
293//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TableForEachSwing.class);
294
295}