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