001package jmri.jmrit.logixng.util.swing;
002
003import java.awt.Component;
004import java.awt.event.ActionListener;
005import java.util.List;
006
007import javax.annotation.Nonnull;
008import javax.swing.*;
009import javax.swing.event.ChangeListener;
010
011import jmri.*;
012import jmri.jmrit.logixng.*;
013import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
014import jmri.jmrit.logixng.util.LogixNG_SelectComboBox;
015import jmri.jmrit.logixng.util.parser.ParserException;
016import jmri.util.swing.BeanSelectPanel;
017import jmri.util.swing.JComboBoxUtil;
018
019/**
020 * Swing class for jmri.jmrit.logixng.util.LogixNG_SelectComboBox.
021 *
022 * @author Daniel Bergqvist (C) 2024
023 */
024public class LogixNG_SelectComboBoxSwing {
025
026    private final JDialog _dialog;
027    private final LogixNG_SelectTableSwing _selectTableSwing;
028
029    private JTabbedPane _tabbedPane;
030    private JComboBox<String> _valuesComboBox;
031    private JPanel _panelDirect;
032    private JPanel _panelReference;
033    private JPanel _panelMemory;
034    private JPanel _panelLocalVariable;
035    private JPanel _panelFormula;
036    private JPanel _panelTable;
037    private JTextField _referenceTextField;
038    private BeanSelectPanel<Memory> _memoryPanel;
039    private JCheckBox _listenToMemoryCheckBox;
040    private JTextField _localVariableTextField;
041    private JTextField _formulaTextField;
042
043
044    public LogixNG_SelectComboBoxSwing(
045            @Nonnull JDialog dialog,
046            @Nonnull SwingConfiguratorInterface swi) {
047        _dialog = dialog;
048        _selectTableSwing = new LogixNG_SelectTableSwing(_dialog, swi);
049    }
050
051    public JPanel createPanel(
052            @Nonnull LogixNG_SelectComboBox selectComboBox) {
053        return createPanel(selectComboBox, null);
054    }
055
056    public JPanel createPanel(
057            @Nonnull LogixNG_SelectComboBox selectComboBox, String defaultValue) {
058
059        JPanel panel = new JPanel();
060
061        _tabbedPane = new JTabbedPane();
062        _panelDirect = new javax.swing.JPanel();
063        _panelReference = new javax.swing.JPanel();
064        _panelMemory = new JPanel();
065        _panelLocalVariable = new javax.swing.JPanel();
066        _panelFormula = new javax.swing.JPanel();
067        _panelTable = _selectTableSwing.createPanel(selectComboBox.getSelectTable());
068
069        _memoryPanel = new BeanSelectPanel<>(InstanceManager.getDefault(MemoryManager.class), null);
070        _listenToMemoryCheckBox = new JCheckBox(Bundle.getMessage("ListenToMemory"));
071
072        _panelMemory.setLayout(new BoxLayout(_panelMemory, BoxLayout.Y_AXIS));
073        _panelMemory.add(_memoryPanel);
074        _panelMemory.add(_listenToMemoryCheckBox);
075
076        _tabbedPane.addTab(NamedBeanAddressing.Direct.toString(), _panelDirect);
077        _tabbedPane.addTab(NamedBeanAddressing.Reference.toString(), _panelReference);
078        _tabbedPane.addTab(NamedBeanAddressing.Memory.toString(), _panelMemory);
079        _tabbedPane.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelLocalVariable);
080        _tabbedPane.addTab(NamedBeanAddressing.Formula.toString(), _panelFormula);
081        _tabbedPane.addTab(NamedBeanAddressing.Table.toString(), _panelTable);
082
083        _valuesComboBox = new JComboBox<>();
084        for (String value : selectComboBox.getValues()) {
085            _valuesComboBox.addItem(value);
086        }
087        JComboBoxUtil.setupComboBoxMaxRows(_valuesComboBox);
088        _valuesComboBox.setRenderer(new ComboBoxRenderer<>(_valuesComboBox.getRenderer()));
089        _panelDirect.add(_valuesComboBox);
090
091        _referenceTextField = new JTextField();
092        _referenceTextField.setColumns(30);
093        _panelReference.add(_referenceTextField);
094
095        _localVariableTextField = new JTextField();
096        _localVariableTextField.setColumns(30);
097        _panelLocalVariable.add(_localVariableTextField);
098
099        _formulaTextField = new JTextField();
100        _formulaTextField.setColumns(30);
101        _panelFormula.add(_formulaTextField);
102
103
104        if (defaultValue != null) {
105            _valuesComboBox.setSelectedItem(defaultValue);
106        }
107
108        switch (selectComboBox.getAddressing()) {
109            case Direct: _tabbedPane.setSelectedComponent(_panelDirect); break;
110            case Reference: _tabbedPane.setSelectedComponent(_panelReference); break;
111            case Memory: _tabbedPane.setSelectedComponent(_panelMemory); break;
112            case LocalVariable: _tabbedPane.setSelectedComponent(_panelLocalVariable); break;
113            case Formula: _tabbedPane.setSelectedComponent(_panelFormula); break;
114            case Table: _tabbedPane.setSelectedComponent(_panelTable); break;
115            default: throw new IllegalArgumentException("invalid _addressing state: " + selectComboBox.getAddressing().name());
116        }
117        if (selectComboBox.getValue() != null) {
118            _valuesComboBox.setSelectedItem(selectComboBox.getValue());
119        }
120        _referenceTextField.setText(selectComboBox.getReference());
121        _memoryPanel.setDefaultNamedBean(selectComboBox.getMemory());
122        _listenToMemoryCheckBox.setSelected(selectComboBox.getListenToMemory());
123        _localVariableTextField.setText(selectComboBox.getLocalVariable());
124        _formulaTextField.setText(selectComboBox.getFormula());
125
126        panel.add(_tabbedPane);
127        return panel;
128    }
129
130    public void addAddressingListener(ChangeListener listener) {
131        _tabbedPane.addChangeListener(listener);
132    }
133
134    public void addEnumListener(ActionListener listener) {
135        _valuesComboBox.addActionListener(listener);
136    }
137
138    public boolean validate(
139            @Nonnull LogixNG_SelectComboBox selectComboBox,
140            @Nonnull List<String> errorMessages) {
141        try {
142            if (_tabbedPane.getSelectedComponent() == _panelReference) {
143                selectComboBox.setReference(_referenceTextField.getText());
144            }
145        } catch (IllegalArgumentException e) {
146            errorMessages.add(e.getMessage());
147            return false;
148        }
149
150        try {
151            selectComboBox.setFormula(_formulaTextField.getText());
152            selectComboBox.setAddressing(getAddressing());
153        } catch (ParserException e) {
154            errorMessages.add("Cannot parse formula: " + e.getMessage());
155            return false;
156        }
157
158        _selectTableSwing.validate(selectComboBox.getSelectTable(), errorMessages);
159
160        return errorMessages.isEmpty();
161    }
162
163    public void updateObject(@Nonnull LogixNG_SelectComboBox selectComboBox) {
164
165        if (_tabbedPane.getSelectedComponent() == _panelDirect) {
166            selectComboBox.setValue(_valuesComboBox.getItemAt(_valuesComboBox.getSelectedIndex()));
167        }
168
169        try {
170            if (_tabbedPane.getSelectedComponent() == _panelDirect) {
171                selectComboBox.setAddressing(NamedBeanAddressing.Direct);
172            } else if (_tabbedPane.getSelectedComponent() == _panelReference) {
173                selectComboBox.setAddressing(NamedBeanAddressing.Reference);
174                selectComboBox.setReference(_referenceTextField.getText());
175            } else if (_tabbedPane.getSelectedComponent() == _panelMemory) {
176                selectComboBox.setAddressing(NamedBeanAddressing.Memory);
177                selectComboBox.setMemory(_memoryPanel.getNamedBean());
178                selectComboBox.setListenToMemory(_listenToMemoryCheckBox.isSelected());
179            } else if (_tabbedPane.getSelectedComponent() == _panelLocalVariable) {
180                selectComboBox.setAddressing(NamedBeanAddressing.LocalVariable);
181                selectComboBox.setLocalVariable(_localVariableTextField.getText());
182            } else if (_tabbedPane.getSelectedComponent() == _panelFormula) {
183                selectComboBox.setAddressing(NamedBeanAddressing.Formula);
184                selectComboBox.setFormula(_formulaTextField.getText());
185            } else if (_tabbedPane.getSelectedComponent() == _panelTable) {
186                selectComboBox.setAddressing(NamedBeanAddressing.Table);
187            } else {
188                throw new IllegalArgumentException("_tabbedPaneEnum has unknown selection");
189            }
190        } catch (ParserException e) {
191            throw new RuntimeException("ParserException: "+e.getMessage(), e);
192        }
193
194        _selectTableSwing.updateObject(selectComboBox.getSelectTable());
195    }
196
197    public boolean isValueSelected(String value) {
198        if (_tabbedPane.getSelectedComponent() == _panelDirect) {
199            return _valuesComboBox.getItemAt(_valuesComboBox.getSelectedIndex()).equals(value);
200        } else {
201            return false;
202        }
203    }
204
205    public boolean isValueSelectedOrIndirectAddressing(String value) {
206        if (_tabbedPane.getSelectedComponent() == _panelDirect) {
207            return _valuesComboBox.getItemAt(_valuesComboBox.getSelectedIndex()).equals(value);
208        } else {
209            return true;
210        }
211    }
212
213    public NamedBeanAddressing getAddressing() {
214        if (_tabbedPane.getSelectedComponent() == _panelDirect) {
215            return NamedBeanAddressing.Direct;
216        } else if (_tabbedPane.getSelectedComponent() == _panelReference) {
217            return NamedBeanAddressing.Reference;
218        } else if (_tabbedPane.getSelectedComponent() == _panelMemory) {
219            return NamedBeanAddressing.Memory;
220        } else if (_tabbedPane.getSelectedComponent() == _panelLocalVariable) {
221            return NamedBeanAddressing.LocalVariable;
222        } else if (_tabbedPane.getSelectedComponent() == _panelFormula) {
223            return NamedBeanAddressing.Formula;
224        } else if (_tabbedPane.getSelectedComponent() == _panelTable) {
225            return NamedBeanAddressing.Table;
226        } else {
227            throw new IllegalArgumentException("_tabbedPane has unknown selection");
228        }
229    }
230
231    public String getValue() {
232        return _valuesComboBox.getItemAt(_valuesComboBox.getSelectedIndex());
233    }
234
235    public void setValue(String value) {
236        _valuesComboBox.setSelectedItem(value);
237    }
238
239    public void setValues(String[] valuesArray) {
240        String selectedValue = _valuesComboBox.getItemAt(_valuesComboBox.getSelectedIndex());
241
242        _valuesComboBox.removeAllItems();
243        for (String value : valuesArray) {
244            _valuesComboBox.addItem(value);
245        }
246
247        _valuesComboBox.setSelectedItem(selectedValue);
248    }
249
250    public void dispose() {
251        _selectTableSwing.dispose();
252    }
253
254
255    private static class ComboBoxRenderer<E> extends JLabel implements ListCellRenderer<E> {
256
257        private final JSeparator _separator = new JSeparator(JSeparator.HORIZONTAL);
258        private final ListCellRenderer<E> _old;
259
260        private ComboBoxRenderer(ListCellRenderer<E> old) {
261            this._old = old;
262        }
263
264        @Override
265        public Component getListCellRendererComponent(JList<? extends E> list,
266                E value, int index, boolean isSelected, boolean cellHasFocus) {
267            if (Base.SEPARATOR.equals(value)) {
268                return _separator;
269            } else {
270                return _old.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
271            }
272        }
273    }
274
275}