001package jmri.jmrit.logixng.actions.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.actions.ActionSignalMast;
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 ActionSignalMast object with a Swing JPanel.
026 *
027 * @author Daniel Bergqvist Copyright 2021
028 */
029public class ActionSignalMastSwing extends AbstractDigitalActionSwing {
030
031    public static final int NUM_COLUMNS_TEXT_FIELDS = 20;
032
033    private LogixNG_SelectNamedBeanSwing<SignalMast> _selectNamedBeanSwing;
034
035    private JTabbedPane _tabbedPaneOperationType;
036    private JPanel _panelOperationTypeDirect;
037    private JPanel _panelOperationTypeReference;
038    private JPanel _panelOperationTypeLocalVariable;
039    private JPanel _panelOperationTypeFormula;
040
041    private JComboBox<ActionSignalMast.OperationType> _operationComboBox;
042    private JTextField _signalMastOperationReferenceTextField;
043    private JTextField _signalMastOperationLocalVariableTextField;
044    private JTextField _signalMastOperationFormulaTextField;
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 ActionSignalMastSwing() {
061    }
062
063    public ActionSignalMastSwing(JDialog dialog) {
064        super.setJDialog(dialog);
065    }
066
067    @Override
068    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
069        ActionSignalMast action = (ActionSignalMast)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 (action != null) {
080            _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(action.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 actionPanel = 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
109        // Set up the tabbed pane for selecting the operation
110        _tabbedPaneOperationType = new JTabbedPane();
111        _panelOperationTypeDirect = new javax.swing.JPanel();
112        _panelOperationTypeDirect.setLayout(new BoxLayout(_panelOperationTypeDirect, BoxLayout.Y_AXIS));
113        _panelOperationTypeReference = new javax.swing.JPanel();
114        _panelOperationTypeReference.setLayout(new BoxLayout(_panelOperationTypeReference, BoxLayout.Y_AXIS));
115        _panelOperationTypeLocalVariable = new javax.swing.JPanel();
116        _panelOperationTypeLocalVariable.setLayout(new BoxLayout(_panelOperationTypeLocalVariable, BoxLayout.Y_AXIS));
117        _panelOperationTypeFormula = new javax.swing.JPanel();
118        _panelOperationTypeFormula.setLayout(new BoxLayout(_panelOperationTypeFormula, BoxLayout.Y_AXIS));
119
120        _tabbedPaneOperationType.addTab(NamedBeanAddressing.Direct.toString(), _panelOperationTypeDirect);
121        _tabbedPaneOperationType.addTab(NamedBeanAddressing.Reference.toString(), _panelOperationTypeReference);
122        _tabbedPaneOperationType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelOperationTypeLocalVariable);
123        _tabbedPaneOperationType.addTab(NamedBeanAddressing.Formula.toString(), _panelOperationTypeFormula);
124
125        _tabbedPaneOperationType.addChangeListener((ChangeEvent e) -> {
126            setGuiEnabledStates();
127        });
128
129        _operationComboBox = new JComboBox<>();
130        for (ActionSignalMast.OperationType e : ActionSignalMast.OperationType.values()) {
131            _operationComboBox.addItem(e);
132        }
133        JComboBoxUtil.setupComboBoxMaxRows(_operationComboBox);
134
135        _operationComboBox.addActionListener(e -> {
136            setGuiEnabledStates();
137        });
138
139        _panelOperationTypeDirect.add(new JLabel(Bundle.getMessage("ActionSignalMast_Operation")));
140        _panelOperationTypeDirect.add(_operationComboBox);
141
142        _signalMastOperationReferenceTextField = new JTextField();
143        _signalMastOperationReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
144        _panelOperationTypeReference.add(new JLabel(Bundle.getMessage("ActionSignalMast_Operation")));
145        _panelOperationTypeReference.add(_signalMastOperationReferenceTextField);
146
147        _signalMastOperationLocalVariableTextField = new JTextField();
148        _signalMastOperationLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
149        _panelOperationTypeLocalVariable.add(new JLabel(Bundle.getMessage("ActionSignalMast_Operation")));
150        _panelOperationTypeLocalVariable.add(_signalMastOperationLocalVariableTextField);
151
152        _signalMastOperationFormulaTextField = new JTextField();
153        _signalMastOperationFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
154        _panelOperationTypeFormula.add(new JLabel(Bundle.getMessage("ActionSignalMast_Operation")));
155        _panelOperationTypeFormula.add(_signalMastOperationFormulaTextField);
156
157
158        // Set up the tabbed pane for selecting the appearance
159        _tabbedPaneAspectType = new JTabbedPane();
160        _panelAspectTypeDirect = new javax.swing.JPanel();
161        _panelAspectTypeDirect.setLayout(new BoxLayout(_panelAspectTypeDirect, BoxLayout.Y_AXIS));
162        _panelAspectTypeReference = new javax.swing.JPanel();
163        _panelAspectTypeReference.setLayout(new BoxLayout(_panelAspectTypeReference, BoxLayout.Y_AXIS));
164        _panelAspectTypeLocalVariable = new javax.swing.JPanel();
165        _panelAspectTypeLocalVariable.setLayout(new BoxLayout(_panelAspectTypeLocalVariable, BoxLayout.Y_AXIS));
166        _panelAspectTypeFormula = new javax.swing.JPanel();
167        _panelAspectTypeFormula.setLayout(new BoxLayout(_panelAspectTypeFormula, BoxLayout.Y_AXIS));
168
169        _tabbedPaneAspectType.addTab(NamedBeanAddressing.Direct.toString(), _panelAspectTypeDirect);
170        _tabbedPaneAspectType.addTab(NamedBeanAddressing.Reference.toString(), _panelAspectTypeReference);
171        _tabbedPaneAspectType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelAspectTypeLocalVariable);
172        _tabbedPaneAspectType.addTab(NamedBeanAddressing.Formula.toString(), _panelAspectTypeFormula);
173
174        _tabbedPaneAspectType.addChangeListener((ChangeEvent e) -> {
175            setGuiEnabledStates();
176        });
177
178        _signalMastAspectComboBox = new JComboBox<>();
179        _panelAspectTypeDirect.add(new JLabel(Bundle.getMessage("ActionSignalMast_Aspect")));
180        _panelAspectTypeDirect.add(_signalMastAspectComboBox);
181
182        _signalMastAspectReferenceTextField = new JTextField();
183        _signalMastAspectReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
184        _panelAspectTypeReference.add(new JLabel(Bundle.getMessage("ActionSignalMast_Aspect")));
185        _panelAspectTypeReference.add(_signalMastAspectReferenceTextField);
186
187        _signalMastAspectLocalVariableTextField = new JTextField();
188        _signalMastAspectLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
189        _panelAspectTypeLocalVariable.add(new JLabel(Bundle.getMessage("ActionSignalMast_Aspect")));
190        _panelAspectTypeLocalVariable.add(_signalMastAspectLocalVariableTextField);
191
192        _signalMastAspectFormulaTextField = new JTextField();
193        _signalMastAspectFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
194        _panelAspectTypeFormula.add(new JLabel(Bundle.getMessage("ActionSignalMast_Aspect")));
195        _panelAspectTypeFormula.add(_signalMastAspectFormulaTextField);
196
197
198        JPanel notePanel = new JPanel();
199        notePanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.white));
200        examplePanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.white));
201
202        JLabel noteLabel = new JLabel(Bundle.getMessage("SignalExampleText",
203                Bundle.getMessage("SignalExampleMast"),
204                Bundle.getMessage("SignalExampleAspects")));
205        notePanel.add(noteLabel);
206
207
208        examplePanel.add(new JLabel(Bundle.getMessage("ActionSignalMast_ExampleBean")));
209        examplePanel.add(innerExamplePanel);
210
211
212        if (action != null) {
213            if (action.getSelectExampleNamedBean().getNamedBean() != null) {
214                _exampleSignalMastBeanPanel.setDefaultNamedBean(action.getSelectExampleNamedBean().getNamedBean().getBean());
215            }
216
217            switch (action.getOperationAddressing()) {
218                case Direct: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeDirect); break;
219                case Reference: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeReference); break;
220                case LocalVariable: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeLocalVariable); break;
221                case Formula: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeFormula); break;
222                default: throw new IllegalArgumentException("invalid _addressing state: " + action.getOperationAddressing().name());
223            }
224            _operationComboBox.setSelectedItem(action.getOperationType());
225            _signalMastOperationReferenceTextField.setText(action.getOperationReference());
226            _signalMastOperationLocalVariableTextField.setText(action.getOperationLocalVariable());
227            _signalMastOperationFormulaTextField.setText(action.getOperationFormula());
228
229
230            switch (action.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: " + action.getAspectAddressing().name());
236            }
237            _signalMastAspectReferenceTextField.setText(action.getAspectReference());
238            _signalMastAspectLocalVariableTextField.setText(action.getAspectLocalVariable());
239            _signalMastAspectFormulaTextField.setText(action.getAspectFormula());
240
241            jmri.util.ThreadingUtil.runOnGUIEventually(() -> { setAspectComboBox(action); });
242        }
243
244        JComponent[] components = new JComponent[]{
245            _tabbedPaneNamedBean,
246            _tabbedPaneOperationType,
247            _tabbedPaneAspectType
248        };
249
250        List<JComponent> componentList = SwingConfiguratorInterface.parseMessage(
251                Bundle.getMessage("ActionSignalMast_Components"), components);
252
253        for (JComponent c : componentList) actionPanel.add(c);
254
255        panel.add(actionPanel);
256        panel.add(notePanel);
257        panel.add(examplePanel);
258
259        setGuiEnabledStates();
260    }
261
262    private void setGuiEnabledStates() {
263        _tabbedPaneAspectType.setEnabled(false);
264        _signalMastAspectComboBox.setEnabled(false);
265        _signalMastAspectReferenceTextField.setEnabled(false);
266        _signalMastAspectLocalVariableTextField.setEnabled(false);
267        _signalMastAspectFormulaTextField.setEnabled(false);
268        _exampleSignalMastBeanPanel.getBeanCombo().setEnabled(false);
269
270        if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeDirect &&
271                _operationComboBox.getSelectedItem() != ActionSignalMast.OperationType.Aspect) {
272            return;
273        }
274
275        _tabbedPaneAspectType.setEnabled(true);
276
277        if (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct &&
278                _tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) {
279            _exampleSignalMastBeanPanel.getBeanCombo().setEnabled(true);
280        }
281
282        if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) {
283            _signalMastAspectComboBox.setEnabled(true);
284        }
285        if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeReference) {
286            _signalMastAspectReferenceTextField.setEnabled(true);
287        }
288        if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeLocalVariable) {
289            _signalMastAspectLocalVariableTextField.setEnabled(true);
290        }
291        if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeFormula) {
292            _signalMastAspectFormulaTextField.setEnabled(true);
293        }
294    }
295
296    private void setAspectComboBox(ActionSignalMast action) {
297        SignalMast sm;
298        if (_selectNamedBeanSwing.getAddressing() == NamedBeanAddressing.Direct) {
299            sm = _selectNamedBeanSwing.getBean();
300        } else {
301            sm = _exampleSignalMastBeanPanel.getBeanCombo().getSelectedItem();
302        }
303
304        if (sm != null) {
305            _signalMastAspectComboBox.removeAllItems();
306            for (String aspect : sm.getValidAspects()) {
307                _signalMastAspectComboBox.addItem(aspect);
308                if (action != null) {
309                    if (aspect.equals(action.getAspect())) _signalMastAspectComboBox.setSelectedItem(aspect);
310                }
311            }
312            JComboBoxUtil.setupComboBoxMaxRows(_signalMastAspectComboBox);
313        }
314    }
315
316
317    /** {@inheritDoc} */
318    @Override
319    public boolean validate(@Nonnull List<String> errorMessages) {
320        // Create a temporary action to test formula
321        ActionSignalMast action = new ActionSignalMast("IQDA1", null);
322
323        _selectNamedBeanSwing.validate(action.getSelectNamedBean(), errorMessages);
324
325        try {
326            if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeReference) {
327                action.setOperationReference(_signalMastOperationReferenceTextField.getText());
328            }
329        } catch (IllegalArgumentException e) {
330            errorMessages.add(e.getMessage());
331            return false;
332        }
333
334        return errorMessages.isEmpty();
335    }
336
337    /** {@inheritDoc} */
338    @Override
339    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
340        ActionSignalMast action = new ActionSignalMast(systemName, userName);
341        updateObject(action);
342        return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action);
343    }
344
345    /** {@inheritDoc} */
346    @Override
347    public void updateObject(@Nonnull Base object) {
348        if (! (object instanceof ActionSignalMast)) {
349            throw new IllegalArgumentException("object must be an ActionSignalMast but is a: "+object.getClass().getName());
350        }
351        ActionSignalMast action = (ActionSignalMast)object;
352
353        _selectNamedBeanSwing.updateObject(action.getSelectNamedBean());
354
355        if (!_exampleSignalMastBeanPanel.isEmpty()
356                && (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct)
357                && (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect)) {
358
359            SignalMast signalMast = _exampleSignalMastBeanPanel.getNamedBean();
360            if (signalMast != null) {
361                NamedBeanHandle<SignalMast> handle
362                        = InstanceManager.getDefault(NamedBeanHandleManager.class)
363                                .getNamedBeanHandle(signalMast.getDisplayName(), signalMast);
364                action.getSelectExampleNamedBean().setNamedBean(handle);
365            }
366        } else {
367            action.getSelectExampleNamedBean().removeNamedBean();
368        }
369
370        try {
371            if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeDirect) {
372                action.setOperationAddressing(NamedBeanAddressing.Direct);
373                action.setOperationType((ActionSignalMast.OperationType)_operationComboBox.getSelectedItem());
374            } else if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeReference) {
375                action.setOperationAddressing(NamedBeanAddressing.Reference);
376                action.setOperationReference(_signalMastOperationReferenceTextField.getText());
377            } else if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeLocalVariable) {
378                action.setOperationAddressing(NamedBeanAddressing.LocalVariable);
379                action.setOperationLocalVariable(_signalMastOperationLocalVariableTextField.getText());
380            } else if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeFormula) {
381                action.setOperationAddressing(NamedBeanAddressing.Formula);
382                action.setOperationFormula(_signalMastOperationFormulaTextField.getText());
383            } else {
384                throw new IllegalArgumentException("_tabbedPaneOperationType has unknown selection");
385            }
386
387            if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) {
388                action.setAspectAddressing(NamedBeanAddressing.Direct);
389
390                if (_signalMastAspectComboBox.getItemCount() > 0) {
391                    action.setAspect(_signalMastAspectComboBox
392                            .getItemAt(_signalMastAspectComboBox.getSelectedIndex()));
393                }
394            } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeReference) {
395                action.setAspectAddressing(NamedBeanAddressing.Reference);
396                action.setAspectReference(_signalMastAspectReferenceTextField.getText());
397            } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeLocalVariable) {
398                action.setAspectAddressing(NamedBeanAddressing.LocalVariable);
399                action.setAspectLocalVariable(_signalMastAspectLocalVariableTextField.getText());
400            } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeFormula) {
401                action.setAspectAddressing(NamedBeanAddressing.Formula);
402                action.setAspectFormula(_signalMastAspectFormulaTextField.getText());
403            } else {
404                throw new IllegalArgumentException("_tabbedPaneAspectType has unknown selection");
405            }
406        } catch (ParserException e) {
407            throw new RuntimeException("ParserException: "+e.getMessage(), e);
408        }
409    }
410
411    /** {@inheritDoc} */
412    @Override
413    public String toString() {
414        return Bundle.getMessage("SignalMast_Short");
415    }
416
417    @Override
418    public void dispose() {
419    }
420
421
422//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionSignalMastSwing.class);
423
424}