001package jmri.jmrit.logixng.util.swing;
002
003import java.util.List;
004import java.util.function.Predicate;
005
006import javax.annotation.CheckForNull;
007import javax.annotation.Nonnull;
008import javax.swing.*;
009
010import jmri.*;
011import jmri.jmrit.logixng.*;
012import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
013import jmri.jmrit.logixng.util.LogixNG_SelectNamedBean;
014import jmri.jmrit.logixng.util.parser.ParserException;
015import jmri.util.swing.BeanSelectPanel;
016
017/**
018 * Swing class for jmri.jmrit.logixng.util.LogixNG_SelectNamedBean.
019 *
020 * @param <E> the type of the named bean
021 *
022 * @author Daniel Bergqvist (C) 2022
023 */
024public class LogixNG_SelectNamedBeanSwing<E extends NamedBean> {
025
026    private final @Nonnull Manager<E> _manager;
027    private final JDialog _dialog;
028    private final LogixNG_SelectTableSwing _selectTableSwing;
029
030    private boolean onlyDirectAddressing = false;
031
032    private JTabbedPane _tabbedPane;
033    private BeanSelectPanel<E> _namedBeanPanel;
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 JTextField _localVariableTextField;
043    private JTextField _formulaTextField;
044
045
046    public LogixNG_SelectNamedBeanSwing(
047            @Nonnull Manager<E> manager,
048            @Nonnull JDialog dialog,
049            @Nonnull SwingConfiguratorInterface swi) {
050        _manager = manager;
051        _dialog = dialog;
052        _selectTableSwing = new LogixNG_SelectTableSwing(_dialog, swi);
053    }
054
055    public JPanel createPanel(
056            @CheckForNull LogixNG_SelectNamedBean<E> selectNamedBean) {
057        return createPanel(selectNamedBean, null);
058    }
059
060    public JPanel createPanel(
061            @CheckForNull LogixNG_SelectNamedBean<E> selectNamedBean,
062            @CheckForNull Predicate<E> filter) {
063
064        onlyDirectAddressing = selectNamedBean != null
065                && selectNamedBean.getOnlyDirectAddressingAllowed();
066
067        JPanel panel = new JPanel();
068
069        _tabbedPane = new JTabbedPane();
070        _panelDirect = new javax.swing.JPanel();
071        _panelReference = new javax.swing.JPanel();
072        _panelMemory = new JPanel();
073        _panelLocalVariable = new javax.swing.JPanel();
074        _panelFormula = new javax.swing.JPanel();
075        if (selectNamedBean != null) {
076            _panelTable = _selectTableSwing.createPanel(selectNamedBean.getSelectTable());
077        } else {
078            _panelTable = _selectTableSwing.createPanel(null);
079        }
080
081        _memoryPanel = new BeanSelectPanel<>(InstanceManager.getDefault(MemoryManager.class), null);
082
083        _panelMemory.setLayout(new BoxLayout(_panelMemory, BoxLayout.Y_AXIS));
084        _panelMemory.add(_memoryPanel);
085
086        _tabbedPane.addTab(NamedBeanAddressing.Direct.toString(), _panelDirect);
087        _tabbedPane.addTab(NamedBeanAddressing.Reference.toString(), _panelReference);
088        _tabbedPane.addTab(NamedBeanAddressing.Memory.toString(), _panelMemory);
089        _tabbedPane.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelLocalVariable);
090        _tabbedPane.addTab(NamedBeanAddressing.Formula.toString(), _panelFormula);
091        _tabbedPane.addTab(NamedBeanAddressing.Table.toString(), _panelTable);
092
093        _namedBeanPanel = new BeanSelectPanel<>(_manager, null, NamedBean.DisplayOptions.DISPLAYNAME, true, filter);
094        _panelDirect.add(_namedBeanPanel);
095
096        _referenceTextField = new JTextField();
097        _referenceTextField.setColumns(30);
098        _panelReference.add(_referenceTextField);
099
100        _localVariableTextField = new JTextField();
101        _localVariableTextField.setColumns(30);
102        _panelLocalVariable.add(_localVariableTextField);
103
104        _formulaTextField = new JTextField();
105        _formulaTextField.setColumns(30);
106        _panelFormula.add(_formulaTextField);
107
108
109        if (selectNamedBean != null) {
110            switch (selectNamedBean.getAddressing()) {
111                case Direct: _tabbedPane.setSelectedComponent(_panelDirect); break;
112                case Reference: _tabbedPane.setSelectedComponent(_panelReference); break;
113                case Memory: _tabbedPane.setSelectedComponent(_panelMemory); break;
114                case LocalVariable: _tabbedPane.setSelectedComponent(_panelLocalVariable); break;
115                case Formula: _tabbedPane.setSelectedComponent(_panelFormula); break;
116                case Table: _tabbedPane.setSelectedComponent(_panelTable); break;
117                default: throw new IllegalArgumentException("invalid _addressing state: " + selectNamedBean.getAddressing().name());
118            }
119            if (selectNamedBean.getNamedBean() != null) {
120                _namedBeanPanel.setDefaultNamedBean(selectNamedBean.getNamedBean().getBean());
121            }
122            _referenceTextField.setText(selectNamedBean.getReference());
123            _memoryPanel.setDefaultNamedBean(selectNamedBean.getMemory());
124            _localVariableTextField.setText(selectNamedBean.getLocalVariable());
125            _formulaTextField.setText(selectNamedBean.getFormula());
126        }
127
128        if (!onlyDirectAddressing) {
129            panel.add(_tabbedPane);
130        } else {
131            panel.add(_panelDirect);
132        }
133        return panel;
134    }
135
136    public boolean validate(
137            @Nonnull LogixNG_SelectNamedBean<E> selectNamedBean,
138            @Nonnull List<String> errorMessages) {
139        try {
140            if (_tabbedPane.getSelectedComponent() == _panelReference) {
141                selectNamedBean.setReference(_referenceTextField.getText());
142            }
143        } catch (IllegalArgumentException e) {
144            errorMessages.add(e.getMessage());
145            return false;
146        }
147
148        try {
149            selectNamedBean.setFormula(_formulaTextField.getText());
150            selectNamedBean.setAddressing(getAddressing());
151        } catch (ParserException e) {
152            errorMessages.add("Cannot parse formula: " + e.getMessage());
153            return false;
154        }
155
156        _selectTableSwing.validate(selectNamedBean.getSelectTable(), errorMessages);
157
158        return errorMessages.isEmpty();
159    }
160
161    public void updateObject(@Nonnull LogixNG_SelectNamedBean<E> selectNamedBean) {
162
163        if (onlyDirectAddressing || _tabbedPane.getSelectedComponent() == _panelDirect) {
164            E namedBean = _namedBeanPanel.getNamedBean();
165            if (namedBean != null) {
166                NamedBeanHandle<E> handle
167                        = InstanceManager.getDefault(NamedBeanHandleManager.class)
168                                .getNamedBeanHandle(namedBean.getDisplayName(), namedBean);
169                selectNamedBean.setNamedBean(handle);
170            } else {
171                selectNamedBean.removeNamedBean();
172            }
173        } else {
174            selectNamedBean.removeNamedBean();
175        }
176
177        try {
178            NamedBeanAddressing addressing = getAddressing();
179            selectNamedBean.setAddressing(addressing);
180
181            switch (addressing) {
182                case Direct:
183                    // Do nothing
184                    break;
185                case Reference:
186                    selectNamedBean.setReference(_referenceTextField.getText());
187                    break;
188                case Memory:
189                    if (_memoryPanel.getNamedBean() != null) {
190                        selectNamedBean.setMemory(_memoryPanel.getNamedBean());
191                    }
192                    break;
193                case LocalVariable:
194                    selectNamedBean.setLocalVariable(_localVariableTextField.getText());
195                    break;
196                case Formula:
197                    selectNamedBean.setFormula(_formulaTextField.getText());
198                    break;
199                case Table:
200                    // Do nothing
201                    break;
202                default:
203                    throw new IllegalArgumentException("unknown addressing: "+addressing.name());
204            }
205        } catch (ParserException e) {
206            throw new RuntimeException("ParserException: "+e.getMessage(), e);
207        }
208
209        _selectTableSwing.updateObject(selectNamedBean.getSelectTable());
210    }
211
212    public BeanSelectPanel<E> getBeanSelectPanel() {
213        return _namedBeanPanel;
214    }
215
216    public NamedBeanAddressing getAddressing() {
217        if (onlyDirectAddressing) {
218            return NamedBeanAddressing.Direct;
219        }
220
221        if (_tabbedPane.getSelectedComponent() == _panelDirect) {
222            return NamedBeanAddressing.Direct;
223        } else if (_tabbedPane.getSelectedComponent() == _panelReference) {
224            return NamedBeanAddressing.Reference;
225        } else if (_tabbedPane.getSelectedComponent() == _panelMemory) {
226            return NamedBeanAddressing.Memory;
227        } else if (_tabbedPane.getSelectedComponent() == _panelLocalVariable) {
228            return NamedBeanAddressing.LocalVariable;
229        } else if (_tabbedPane.getSelectedComponent() == _panelFormula) {
230            return NamedBeanAddressing.Formula;
231        } else if (_tabbedPane.getSelectedComponent() == _panelTable) {
232            return NamedBeanAddressing.Table;
233        } else {
234            throw new IllegalArgumentException("_tabbedPane has unknown selection");
235        }
236    }
237
238    public void addAddressingListener(javax.swing.event.ChangeListener l) {
239        _tabbedPane.addChangeListener(l);
240    }
241
242    public void removeAddressingListener(javax.swing.event.ChangeListener l) {
243        _tabbedPane.removeChangeListener(l);
244    }
245
246    public E getBean() {
247        if (getAddressing() == NamedBeanAddressing.Direct) {
248            return _namedBeanPanel.getNamedBean();
249        } else {
250            throw new IllegalArgumentException("Addressing is not Direct");
251        }
252    }
253
254    public void dispose() {
255        if (_namedBeanPanel != null) {
256            _namedBeanPanel.dispose();
257        }
258        _selectTableSwing.dispose();
259    }
260
261}