001package jmri.jmrit.logixng.actions.swing;
002
003import java.util.List;
004
005import javax.annotation.CheckForNull;
006import javax.annotation.Nonnull;
007import javax.swing.*;
008
009import jmri.InstanceManager;
010import jmri.Light;
011import jmri.LightManager;
012import jmri.jmrit.logixng.*;
013import jmri.jmrit.logixng.actions.ActionLight;
014import jmri.jmrit.logixng.actions.ActionLight.LightState;
015import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
016import jmri.jmrit.logixng.util.parser.ParserException;
017import jmri.jmrit.logixng.util.swing.LogixNG_SelectNamedBeanSwing;
018import jmri.jmrit.logixng.util.swing.LogixNG_SelectEnumSwing;
019
020/**
021 * Configures an ActionLight object with a Swing JPanel.
022 *
023 * @author Daniel Bergqvist Copyright 2021
024 */
025public class ActionLightSwing extends AbstractDigitalActionSwing {
026
027    private LogixNG_SelectNamedBeanSwing<Light> _selectNamedBeanSwing;
028
029    private LogixNG_SelectEnumSwing<LightState> _selectEnumSwing;
030
031    private JTabbedPane _tabbedPaneData;
032    private JPanel _panelDataDirect;
033    private JPanel _panelDataReference;
034    private JPanel _panelDataLocalVariable;
035    private JPanel _panelDataFormula;
036    private JTextField _lightDataDirectTextField;
037    private JTextField _lightDataReferenceTextField;
038    private JTextField _lightDataLocalVariableTextField;
039    private JTextField _lightDataFormulaTextField;
040
041
042    public ActionLightSwing() {
043    }
044
045    public ActionLightSwing(JDialog dialog) {
046        super.setJDialog(dialog);
047    }
048
049    @Override
050    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
051        ActionLight action = (ActionLight)object;
052
053        _selectNamedBeanSwing = new LogixNG_SelectNamedBeanSwing<>(
054                InstanceManager.getDefault(LightManager.class), getJDialog(), this);
055
056        _selectEnumSwing = new LogixNG_SelectEnumSwing<>(getJDialog(), this);
057
058        panel = new JPanel();
059
060        JPanel _tabbedPaneNamedBean;
061        JPanel _tabbedPaneEnum;
062
063        if (action != null) {
064            _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(action.getSelectNamedBean());
065            _tabbedPaneEnum = _selectEnumSwing.createPanel(action.getSelectEnum(), LightState.values());
066        } else {
067            _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(null);
068            _tabbedPaneEnum = _selectEnumSwing.createPanel(null, LightState.values());
069        }
070
071        _selectEnumSwing.addEnumListener(e -> { setDataPanelState(); });
072
073        // Right section
074        _tabbedPaneData = new JTabbedPane();
075        _panelDataDirect = new javax.swing.JPanel();
076        _panelDataReference = new javax.swing.JPanel();
077        _panelDataLocalVariable = new javax.swing.JPanel();
078        _panelDataFormula = new javax.swing.JPanel();
079
080        _tabbedPaneData.addTab(NamedBeanAddressing.Direct.toString(), _panelDataDirect);
081        _tabbedPaneData.addTab(NamedBeanAddressing.Reference.toString(), _panelDataReference);
082        _tabbedPaneData.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelDataLocalVariable);
083        _tabbedPaneData.addTab(NamedBeanAddressing.Formula.toString(), _panelDataFormula);
084
085        _lightDataDirectTextField = new JTextField();
086        _lightDataDirectTextField.setColumns(30);
087        _panelDataDirect.add(_lightDataDirectTextField);
088
089        _lightDataReferenceTextField = new JTextField();
090        _lightDataReferenceTextField.setColumns(30);
091        _panelDataReference.add(_lightDataReferenceTextField);
092
093        _lightDataLocalVariableTextField = new JTextField();
094        _lightDataLocalVariableTextField.setColumns(30);
095        _panelDataLocalVariable.add(_lightDataLocalVariableTextField);
096
097        _lightDataFormulaTextField = new JTextField();
098        _lightDataFormulaTextField.setColumns(30);
099        _panelDataFormula.add(_lightDataFormulaTextField);
100
101        setDataPanelState();
102
103        if (action != null) {
104            switch (action.getDataAddressing()) {
105                case Direct: _tabbedPaneData.setSelectedComponent(_panelDataDirect); break;
106                case Reference: _tabbedPaneData.setSelectedComponent(_panelDataReference); break;
107                case LocalVariable: _tabbedPaneData.setSelectedComponent(_panelDataLocalVariable); break;
108                case Formula: _tabbedPaneData.setSelectedComponent(_panelDataFormula); break;
109                default: throw new IllegalArgumentException("invalid _addressing state: " + action.getDataAddressing().name());
110            }
111            _lightDataReferenceTextField.setText(action.getDataReference());
112            _lightDataLocalVariableTextField.setText(action.getDataLocalVariable());
113            _lightDataFormulaTextField.setText(action.getDataFormula());
114
115            _lightDataDirectTextField.setText(Integer.toString(action.getLightValue()));
116            setDataPanelState();
117        }
118
119        JComponent[] components = new JComponent[]{
120            _tabbedPaneNamedBean,
121            _tabbedPaneEnum,
122            _tabbedPaneData};
123
124        List<JComponent> componentList = SwingConfiguratorInterface.parseMessage(
125                Bundle.getMessage("ActionLight_Components"), components);
126
127        for (JComponent c : componentList) panel.add(c);
128    }
129
130    private void setDataPanelState() {
131        boolean newState = _selectEnumSwing.isEnumSelectedOrIndirectAddressing(LightState.Intensity) ||
132                _selectEnumSwing.isEnumSelectedOrIndirectAddressing(LightState.Interval);
133        _tabbedPaneData.setEnabled(newState);
134        _lightDataDirectTextField.setEnabled(newState);
135        _lightDataReferenceTextField.setEnabled(newState);
136        _lightDataLocalVariableTextField.setEnabled(newState);
137        _lightDataFormulaTextField.setEnabled(newState);
138    }
139
140    /** {@inheritDoc} */
141    @Override
142    public boolean validate(@Nonnull List<String> errorMessages) {
143        // Create a temporary action to test formula
144        ActionLight action = new ActionLight("IQDA1", null);
145
146        _selectNamedBeanSwing.validate(action.getSelectNamedBean(), errorMessages);
147        _selectEnumSwing.validate(action.getSelectEnum(), errorMessages);
148
149        try {
150            if (_tabbedPaneData.getSelectedComponent() == _panelDataReference) {
151                action.setDataReference(_lightDataReferenceTextField.getText());
152            }
153        } catch (IllegalArgumentException e) {
154            errorMessages.add(e.getMessage());
155            return false;
156        }
157
158        try {
159            action.setDataFormula(_lightDataFormulaTextField.getText());
160            if (_tabbedPaneData.getSelectedComponent() == _panelDataDirect) {
161                action.setDataAddressing(NamedBeanAddressing.Direct);
162            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataReference) {
163                action.setDataAddressing(NamedBeanAddressing.Reference);
164            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataLocalVariable) {
165                action.setDataAddressing(NamedBeanAddressing.LocalVariable);
166            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataFormula) {
167                action.setDataAddressing(NamedBeanAddressing.Formula);
168            } else {
169                throw new IllegalArgumentException("_tabbedPane has unknown selection");
170            }
171        } catch (ParserException e) {
172            errorMessages.add("Cannot parse formula: " + e.getMessage());
173            return false;
174        }
175
176        if (_tabbedPaneData.getSelectedComponent() == _panelDataDirect) {
177
178            if (_selectEnumSwing.isEnumSelectedOrIndirectAddressing(LightState.Intensity)) {
179                boolean result = true;
180                try {
181                    int value = Integer.parseInt(_lightDataDirectTextField.getText());
182                    if (value < 0 || value > 100) {
183                        result = false;
184                    }
185                } catch (NumberFormatException ex) {
186                    result = false;
187                }
188                if (!result) {
189                    errorMessages.add(Bundle.getMessage("Light_Error_Intensity"));
190                    return false;
191                }
192            }
193
194            if (_selectEnumSwing.isEnumSelectedOrIndirectAddressing(LightState.Interval)) {
195                boolean result = true;
196                try {
197                    int value = Integer.parseInt(_lightDataDirectTextField.getText());
198                    if (value < 0) {
199                        result = false;
200                    }
201                } catch (NumberFormatException ex) {
202                    result = false;
203                }
204                if (!result) {
205                    errorMessages.add(Bundle.getMessage("Light_Error_Interval"));
206                    return false;
207                }
208            }
209        }
210
211        return errorMessages.isEmpty();
212    }
213
214    /** {@inheritDoc} */
215    @Override
216    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
217        ActionLight action = new ActionLight(systemName, userName);
218        updateObject(action);
219        return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action);
220    }
221
222    /** {@inheritDoc} */
223    @Override
224    public void updateObject(@Nonnull Base object) {
225        if (! (object instanceof ActionLight)) {
226            throw new IllegalArgumentException("object must be an ActionLight but is a: "+object.getClass().getName());
227        }
228        ActionLight action = (ActionLight)object;
229        _selectNamedBeanSwing.updateObject(action.getSelectNamedBean());
230        _selectEnumSwing.updateObject(action.getSelectEnum());
231
232        try {
233            // Right section
234            if (_tabbedPaneData.getSelectedComponent() == _panelDataDirect) {
235                action.setDataAddressing(NamedBeanAddressing.Direct);
236                // Handle optional data field
237                if (_selectEnumSwing.isEnumSelectedOrIndirectAddressing(LightState.Intensity) ||
238                        _selectEnumSwing.isEnumSelectedOrIndirectAddressing(LightState.Interval)) {
239                    int value;
240                    try {
241                        value = Integer.parseInt(_lightDataDirectTextField.getText());
242                    } catch (NumberFormatException ex) {
243                        value = 0;
244                    }
245                    action.setLightValue(value);
246                }
247            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataReference) {
248                action.setDataAddressing(NamedBeanAddressing.Reference);
249                action.setDataReference(_lightDataReferenceTextField.getText());
250            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataLocalVariable) {
251                action.setDataAddressing(NamedBeanAddressing.LocalVariable);
252                action.setDataLocalVariable(_lightDataLocalVariableTextField.getText());
253            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataFormula) {
254                action.setDataAddressing(NamedBeanAddressing.Formula);
255                action.setDataFormula(_lightDataFormulaTextField.getText());
256            } else {
257                throw new IllegalArgumentException("_tabbedPaneData has unknown selection");
258            }
259
260        } catch (ParserException e) {
261            throw new RuntimeException("ParserException: "+e.getMessage(), e);
262        }
263    }
264
265    /** {@inheritDoc} */
266    @Override
267    public String toString() {
268        return Bundle.getMessage("Light_Short");
269    }
270
271    @Override
272    public void dispose() {
273        _selectNamedBeanSwing.dispose();
274        _selectEnumSwing.dispose();
275    }
276
277
278//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionLightSwing.class);
279
280}