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