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