001package jmri.jmrit.logixng.expressions.swing;
002
003import java.awt.Color;
004import java.util.List;
005
006import javax.annotation.CheckForNull;
007import javax.annotation.Nonnull;
008import javax.swing.*;
009import javax.swing.event.ChangeEvent;
010
011import jmri.InstanceManager;
012import jmri.NamedBeanHandle;
013import jmri.NamedBeanHandleManager;
014import jmri.SignalMast;
015import jmri.SignalMastManager;
016import jmri.jmrit.logixng.*;
017import jmri.jmrit.logixng.expressions.ExpressionSignalMast;
018import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
019import jmri.jmrit.logixng.util.swing.LogixNG_SelectNamedBeanSwing;
020import jmri.jmrit.logixng.util.parser.ParserException;
021import jmri.util.swing.BeanSelectPanel;
022import jmri.util.swing.JComboBoxUtil;
023
024/**
025 * Configures an ExpressionSignalMast object with a Swing JPanel.
026 *
027 * @author Daniel Bergqvist Copyright 2021
028 */
029public class ExpressionSignalMastSwing extends AbstractDigitalExpressionSwing {
030
031    public static final int NUM_COLUMNS_TEXT_FIELDS = 20;
032
033    private LogixNG_SelectNamedBeanSwing<SignalMast> _selectNamedBeanSwing;
034
035    private JTabbedPane _tabbedPaneQueryType;
036    private JPanel _panelQueryTypeDirect;
037    private JPanel _panelQueryTypeReference;
038    private JPanel _panelQueryTypeLocalVariable;
039    private JPanel _panelQueryTypeFormula;
040
041    private JComboBox<ExpressionSignalMast.QueryType> _operationComboBox;
042    private JTextField _signalMastQueryReferenceTextField;
043    private JTextField _signalMastQueryLocalVariableTextField;
044    private JTextField _signalMastQueryFormulaTextField;
045
046    private JTabbedPane _tabbedPaneAspectType;
047    private JPanel _panelAspectTypeDirect;
048    private JPanel _panelAspectTypeReference;
049    private JPanel _panelAspectTypeLocalVariable;
050    private JPanel _panelAspectTypeFormula;
051
052    private JComboBox<String> _signalMastAspectComboBox;
053    private JTextField _signalMastAspectReferenceTextField;
054    private JTextField _signalMastAspectLocalVariableTextField;
055    private JTextField _signalMastAspectFormulaTextField;
056
057    private BeanSelectPanel<SignalMast> _exampleSignalMastBeanPanel;
058
059
060    public ExpressionSignalMastSwing() {
061    }
062
063    public ExpressionSignalMastSwing(JDialog dialog) {
064        super.setJDialog(dialog);
065    }
066
067    @Override
068    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
069        ExpressionSignalMast expression = (ExpressionSignalMast)object;
070
071        _selectNamedBeanSwing = new LogixNG_SelectNamedBeanSwing<>(
072                InstanceManager.getDefault(SignalMastManager.class), getJDialog(), this);
073
074        panel = new JPanel();
075        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
076
077        JPanel _tabbedPaneNamedBean;
078
079        if (expression != null) {
080            _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(expression.getSelectNamedBean());
081        } else {
082            _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(null);
083        }
084
085        JPanel examplePanel = new JPanel();
086        JPanel innerExamplePanel = new JPanel();
087        innerExamplePanel.setBorder(BorderFactory.createLineBorder(Color.black));
088        _exampleSignalMastBeanPanel = new BeanSelectPanel<>(InstanceManager.getDefault(SignalMastManager.class), null);
089        innerExamplePanel.add(_exampleSignalMastBeanPanel);
090
091        _exampleSignalMastBeanPanel.getBeanCombo().addActionListener((java.awt.event.ActionEvent e) -> {
092            setAspectComboBox(null);
093        });
094
095
096        JPanel expressionPanel = new JPanel();
097
098
099        _selectNamedBeanSwing.addAddressingListener((ChangeEvent e) -> {
100            setGuiEnabledStates();
101        });
102
103        _selectNamedBeanSwing.getBeanSelectPanel().getBeanCombo()
104                .addActionListener((java.awt.event.ActionEvent e) -> {
105            setAspectComboBox(null);
106        });
107
108        // Set up the tabbed pane for selecting the operation
109        _tabbedPaneQueryType = new JTabbedPane();
110        _panelQueryTypeDirect = new javax.swing.JPanel();
111        _panelQueryTypeDirect.setLayout(new BoxLayout(_panelQueryTypeDirect, BoxLayout.Y_AXIS));
112        _panelQueryTypeReference = new javax.swing.JPanel();
113        _panelQueryTypeReference.setLayout(new BoxLayout(_panelQueryTypeReference, BoxLayout.Y_AXIS));
114        _panelQueryTypeLocalVariable = new javax.swing.JPanel();
115        _panelQueryTypeLocalVariable.setLayout(new BoxLayout(_panelQueryTypeLocalVariable, BoxLayout.Y_AXIS));
116        _panelQueryTypeFormula = new javax.swing.JPanel();
117        _panelQueryTypeFormula.setLayout(new BoxLayout(_panelQueryTypeFormula, BoxLayout.Y_AXIS));
118
119        _tabbedPaneQueryType.addTab(NamedBeanAddressing.Direct.toString(), _panelQueryTypeDirect);
120        _tabbedPaneQueryType.addTab(NamedBeanAddressing.Reference.toString(), _panelQueryTypeReference);
121        _tabbedPaneQueryType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelQueryTypeLocalVariable);
122        _tabbedPaneQueryType.addTab(NamedBeanAddressing.Formula.toString(), _panelQueryTypeFormula);
123
124        _tabbedPaneQueryType.addChangeListener((ChangeEvent e) -> {
125            setGuiEnabledStates();
126        });
127
128        _operationComboBox = new JComboBox<>();
129        for (ExpressionSignalMast.QueryType e : ExpressionSignalMast.QueryType.values()) {
130            _operationComboBox.addItem(e);
131        }
132        JComboBoxUtil.setupComboBoxMaxRows(_operationComboBox);
133
134        _operationComboBox.addActionListener(e -> {
135            setGuiEnabledStates();
136        });
137
138        _panelQueryTypeDirect.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Query")));
139        _panelQueryTypeDirect.add(_operationComboBox);
140
141        _signalMastQueryReferenceTextField = new JTextField();
142        _signalMastQueryReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
143        _panelQueryTypeReference.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Query")));
144        _panelQueryTypeReference.add(_signalMastQueryReferenceTextField);
145
146        _signalMastQueryLocalVariableTextField = new JTextField();
147        _signalMastQueryLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
148        _panelQueryTypeLocalVariable.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Query")));
149        _panelQueryTypeLocalVariable.add(_signalMastQueryLocalVariableTextField);
150
151        _signalMastQueryFormulaTextField = new JTextField();
152        _signalMastQueryFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
153        _panelQueryTypeFormula.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Query")));
154        _panelQueryTypeFormula.add(_signalMastQueryFormulaTextField);
155
156
157        // Set up the tabbed pane for selecting the aspect
158        _tabbedPaneAspectType = new JTabbedPane();
159        _panelAspectTypeDirect = new javax.swing.JPanel();
160        _panelAspectTypeDirect.setLayout(new BoxLayout(_panelAspectTypeDirect, BoxLayout.Y_AXIS));
161        _panelAspectTypeReference = new javax.swing.JPanel();
162        _panelAspectTypeReference.setLayout(new BoxLayout(_panelAspectTypeReference, BoxLayout.Y_AXIS));
163        _panelAspectTypeLocalVariable = new javax.swing.JPanel();
164        _panelAspectTypeLocalVariable.setLayout(new BoxLayout(_panelAspectTypeLocalVariable, BoxLayout.Y_AXIS));
165        _panelAspectTypeFormula = new javax.swing.JPanel();
166        _panelAspectTypeFormula.setLayout(new BoxLayout(_panelAspectTypeFormula, BoxLayout.Y_AXIS));
167
168        _tabbedPaneAspectType.addTab(NamedBeanAddressing.Direct.toString(), _panelAspectTypeDirect);
169        _tabbedPaneAspectType.addTab(NamedBeanAddressing.Reference.toString(), _panelAspectTypeReference);
170        _tabbedPaneAspectType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelAspectTypeLocalVariable);
171        _tabbedPaneAspectType.addTab(NamedBeanAddressing.Formula.toString(), _panelAspectTypeFormula);
172
173        _tabbedPaneAspectType.addChangeListener((ChangeEvent e) -> {
174            setGuiEnabledStates();
175        });
176
177        _signalMastAspectComboBox = new JComboBox<>();
178        _panelAspectTypeDirect.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Aspect")));
179        _panelAspectTypeDirect.add(_signalMastAspectComboBox);
180
181        _signalMastAspectReferenceTextField = new JTextField();
182        _signalMastAspectReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
183        _panelAspectTypeReference.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Aspect")));
184        _panelAspectTypeReference.add(_signalMastAspectReferenceTextField);
185
186        _signalMastAspectLocalVariableTextField = new JTextField();
187        _signalMastAspectLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
188        _panelAspectTypeLocalVariable.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Aspect")));
189        _panelAspectTypeLocalVariable.add(_signalMastAspectLocalVariableTextField);
190
191        _signalMastAspectFormulaTextField = new JTextField();
192        _signalMastAspectFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
193        _panelAspectTypeFormula.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Aspect")));
194        _panelAspectTypeFormula.add(_signalMastAspectFormulaTextField);
195
196
197        JPanel notePanel = new JPanel();
198        notePanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.white));
199        examplePanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.white));
200
201        JLabel noteLabel = new JLabel(Bundle.getMessage("SignalExampleText",
202                Bundle.getMessage("SignalExampleMast"),
203                Bundle.getMessage("SignalExampleAspects")));
204        notePanel.add(noteLabel);
205
206
207        examplePanel.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_ExampleBean")));
208        examplePanel.add(innerExamplePanel);
209
210
211        if (expression != null) {
212            if (expression.getSelectExampleNamedBean().getNamedBean() != null) {
213                _exampleSignalMastBeanPanel.setDefaultNamedBean(expression.getSelectExampleNamedBean().getNamedBean().getBean());
214            }
215
216            switch (expression.getQueryAddressing()) {
217                case Direct: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeDirect); break;
218                case Reference: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeReference); break;
219                case LocalVariable: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeLocalVariable); break;
220                case Formula: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeFormula); break;
221                default: throw new IllegalArgumentException("invalid _addressing state: " + expression.getQueryAddressing().name());
222            }
223            _operationComboBox.setSelectedItem(expression.getQueryType());
224            _signalMastQueryReferenceTextField.setText(expression.getQueryReference());
225            _signalMastQueryLocalVariableTextField.setText(expression.getQueryLocalVariable());
226            _signalMastQueryFormulaTextField.setText(expression.getQueryFormula());
227
228
229
230            switch (expression.getAspectAddressing()) {
231                case Direct: _tabbedPaneAspectType.setSelectedComponent(_panelAspectTypeDirect); break;
232                case Reference: _tabbedPaneAspectType.setSelectedComponent(_panelAspectTypeReference); break;
233                case LocalVariable: _tabbedPaneAspectType.setSelectedComponent(_panelAspectTypeLocalVariable); break;
234                case Formula: _tabbedPaneAspectType.setSelectedComponent(_panelAspectTypeFormula); break;
235                default: throw new IllegalArgumentException("invalid _addressing state: " + expression.getAspectAddressing().name());
236            }
237            _signalMastAspectReferenceTextField.setText(expression.getAspectReference());
238            _signalMastAspectLocalVariableTextField.setText(expression.getAspectLocalVariable());
239            _signalMastAspectFormulaTextField.setText(expression.getAspectFormula());
240
241            jmri.util.ThreadingUtil.runOnGUIEventually(() -> { setAspectComboBox(expression); });
242        }
243
244        JComponent[] components = new JComponent[]{
245            _tabbedPaneNamedBean,
246            _tabbedPaneQueryType,
247            _tabbedPaneAspectType
248        };
249
250        List<JComponent> componentList = SwingConfiguratorInterface.parseMessage(
251                Bundle.getMessage("ExpressionSignalMast_Components"), components);
252
253        for (JComponent c : componentList) expressionPanel.add(c);
254
255        panel.add(expressionPanel);
256        panel.add(notePanel);
257        panel.add(examplePanel);
258
259        setGuiEnabledStates();
260    }
261
262
263    private void setGuiEnabledStates() {
264        _tabbedPaneAspectType.setEnabled(false);
265        _signalMastAspectComboBox.setEnabled(false);
266        _signalMastAspectReferenceTextField.setEnabled(false);
267        _signalMastAspectLocalVariableTextField.setEnabled(false);
268        _signalMastAspectFormulaTextField.setEnabled(false);
269        _exampleSignalMastBeanPanel.getBeanCombo().setEnabled(false);
270
271        if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeDirect &&
272                _operationComboBox.getSelectedItem() != ExpressionSignalMast.QueryType.Aspect &&
273                _operationComboBox.getSelectedItem() != ExpressionSignalMast.QueryType.NotAspect) {
274            return;
275        }
276
277        _tabbedPaneAspectType.setEnabled(true);
278
279        if (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct &&
280                _tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) {
281            _exampleSignalMastBeanPanel.getBeanCombo().setEnabled(true);
282        }
283
284        if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) {
285            _signalMastAspectComboBox.setEnabled(true);
286        }
287        if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeReference) {
288            _signalMastAspectReferenceTextField.setEnabled(true);
289        }
290        if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeLocalVariable) {
291            _signalMastAspectLocalVariableTextField.setEnabled(true);
292        }
293        if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeFormula) {
294            _signalMastAspectFormulaTextField.setEnabled(true);
295        }
296    }
297
298    private void setAspectComboBox(ExpressionSignalMast expression) {
299        SignalMast sm;
300        if (_selectNamedBeanSwing.getAddressing() == NamedBeanAddressing.Direct) {
301            sm = _selectNamedBeanSwing.getBean();
302        } else {
303            sm = _exampleSignalMastBeanPanel.getBeanCombo().getSelectedItem();
304        }
305
306        if (sm != null) {
307            _signalMastAspectComboBox.removeAllItems();
308            for (String aspect : sm.getValidAspects()) {
309                _signalMastAspectComboBox.addItem(aspect);
310                if (expression != null) {
311                    if (aspect.equals(expression.getAspect())) _signalMastAspectComboBox.setSelectedItem(aspect);
312                }
313            }
314            JComboBoxUtil.setupComboBoxMaxRows(_signalMastAspectComboBox);
315        }
316    }
317
318
319    /** {@inheritDoc} */
320    @Override
321    public boolean validate(@Nonnull List<String> errorMessages) {
322        // Create a temporary expression to test formula
323        ExpressionSignalMast expression = new ExpressionSignalMast("IQDE1", null);
324
325        _selectNamedBeanSwing.validate(expression.getSelectNamedBean(), errorMessages);
326
327        try {
328            if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeReference) {
329                expression.setQueryReference(_signalMastQueryReferenceTextField.getText());
330            }
331        } catch (IllegalArgumentException e) {
332            errorMessages.add(e.getMessage());
333            return false;
334        }
335
336        return errorMessages.isEmpty();
337    }
338
339    /** {@inheritDoc} */
340    @Override
341    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
342        ExpressionSignalMast expression = new ExpressionSignalMast(systemName, userName);
343        updateObject(expression);
344        return InstanceManager.getDefault(DigitalExpressionManager.class).registerExpression(expression);
345    }
346
347    /** {@inheritDoc} */
348    @Override
349    public void updateObject(@Nonnull Base object) {
350        if (! (object instanceof ExpressionSignalMast)) {
351            throw new IllegalArgumentException("object must be an ExpressionSignalMast but is a: "+object.getClass().getName());
352        }
353        ExpressionSignalMast expression = (ExpressionSignalMast)object;
354
355        _selectNamedBeanSwing.updateObject(expression.getSelectNamedBean());
356
357        if (!_exampleSignalMastBeanPanel.isEmpty()
358                && (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct)
359                && (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect)) {
360
361            SignalMast signalMast = _exampleSignalMastBeanPanel.getNamedBean();
362            if (signalMast != null) {
363                NamedBeanHandle<SignalMast> handle
364                        = InstanceManager.getDefault(NamedBeanHandleManager.class)
365                                .getNamedBeanHandle(signalMast.getDisplayName(), signalMast);
366                expression.getSelectExampleNamedBean().setNamedBean(handle);
367            }
368        } else {
369            expression.getSelectExampleNamedBean().removeNamedBean();
370        }
371
372        try {
373            if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeDirect) {
374                expression.setQueryAddressing(NamedBeanAddressing.Direct);
375                expression.setQueryType((ExpressionSignalMast.QueryType)_operationComboBox.getSelectedItem());
376            } else if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeReference) {
377                expression.setQueryAddressing(NamedBeanAddressing.Reference);
378                expression.setQueryReference(_signalMastQueryReferenceTextField.getText());
379            } else if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeLocalVariable) {
380                expression.setQueryAddressing(NamedBeanAddressing.LocalVariable);
381                expression.setQueryLocalVariable(_signalMastQueryLocalVariableTextField.getText());
382            } else if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeFormula) {
383                expression.setQueryAddressing(NamedBeanAddressing.Formula);
384                expression.setQueryFormula(_signalMastQueryFormulaTextField.getText());
385            } else {
386                throw new IllegalArgumentException("_tabbedPaneQueryType has unknown selection");
387            }
388
389            if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) {
390                expression.setAspectAddressing(NamedBeanAddressing.Direct);
391
392                if (_signalMastAspectComboBox.getItemCount() > 0) {
393                    expression.setAspect(_signalMastAspectComboBox
394                            .getItemAt(_signalMastAspectComboBox.getSelectedIndex()));
395                }
396            } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeReference) {
397                expression.setAspectAddressing(NamedBeanAddressing.Reference);
398                expression.setAspectReference(_signalMastAspectReferenceTextField.getText());
399            } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeLocalVariable) {
400                expression.setAspectAddressing(NamedBeanAddressing.LocalVariable);
401                expression.setAspectLocalVariable(_signalMastAspectLocalVariableTextField.getText());
402            } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeFormula) {
403                expression.setAspectAddressing(NamedBeanAddressing.Formula);
404                expression.setAspectFormula(_signalMastAspectFormulaTextField.getText());
405            } else {
406                throw new IllegalArgumentException("_tabbedPaneAspectType has unknown selection");
407            }
408        } catch (ParserException e) {
409            throw new RuntimeException("ParserException: "+e.getMessage(), e);
410        }
411    }
412
413    /** {@inheritDoc} */
414    @Override
415    public String toString() {
416        return Bundle.getMessage("SignalMast_Short");
417    }
418
419    @Override
420    public void dispose() {
421    }
422
423
424//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExpressionSignalMastSwing.class);
425
426}