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