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.*;
010import jmri.jmrit.logix.Warrant;
011import jmri.jmrit.logix.WarrantManager;
012import jmri.jmrit.logixng.*;
013import jmri.jmrit.logixng.actions.ActionWarrant;
014import jmri.jmrit.logixng.actions.ActionWarrant.DirectOperation;
015import jmri.jmrit.logixng.actions.ActionWarrant.ControlAutoTrain;
016import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
017import jmri.jmrit.logixng.util.LogixNG_SelectEnum;
018import jmri.jmrit.logixng.util.parser.ParserException;
019import jmri.jmrit.logixng.util.swing.LogixNG_SelectNamedBeanSwing;
020import jmri.jmrit.logixng.util.swing.LogixNG_SelectEnumSwing;
021import jmri.util.swing.BeanSelectPanel;
022import jmri.util.swing.JComboBoxUtil;
023
024/**
025 * Configures an ActionWarrant object with a Swing JPanel.
026 *
027 * @author Daniel Bergqvist  Copyright 2021
028 * @author Dave Sand         Copyright 2021
029 * @author Pete Cressman     Copyright (C) 2022
030 */
031public class ActionWarrantSwing extends AbstractDigitalActionSwing {
032
033    private LogixNG_SelectNamedBeanSwing<Warrant> _selectNamedBeanSwing;
034
035    private LogixNG_SelectEnumSwing<DirectOperation> _selectOperationSwing;
036
037    private JTabbedPane _tabbedPaneData;
038    private JPanel _panelDataDirect;
039    private JPanel _panelDataReference;
040    private JPanel _panelDataLocalVariable;
041    private JPanel _panelDataFormula;
042    private JTextField _warrantDataReferenceTextField;
043    private JTextField _warrantDataLocalVariableTextField;
044    private JTextField _warrantDataFormulaTextField;
045
046    private JPanel _panelControlTrainCombo;
047    private JPanel _panelTrainData;
048    private JTextField _trainIdNameTextField;
049    private JComboBox<ControlAutoTrain> _controlTrainComboBox;
050    private BeanSelectPanel<Memory> _panelMemoryBean;
051    private JPanel _memoryPanel;
052
053
054    public ActionWarrantSwing() {
055    }
056
057    public ActionWarrantSwing(JDialog dialog) {
058        super.setJDialog(dialog);
059    }
060
061    @Override
062    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
063        ActionWarrant action = (ActionWarrant)object;
064
065        _selectNamedBeanSwing = new LogixNG_SelectNamedBeanSwing<>(
066                InstanceManager.getDefault(WarrantManager.class), getJDialog(), this);
067
068        _selectOperationSwing = new LogixNG_SelectEnumSwing<>(getJDialog(), this);
069
070        panel = new JPanel();
071        _memoryPanel = new JPanel();
072
073        // Left and center section
074        JPanel _tabbedPaneNamedBean;
075        JPanel _tabbedPaneOperation;
076
077        if (action != null) {
078            _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(action.getSelectNamedBean());
079            _tabbedPaneOperation = _selectOperationSwing.createPanel(action.getSelectEnum(), DirectOperation.values());
080        } else {
081            _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(null);
082            _tabbedPaneOperation = _selectOperationSwing.createPanel(null, DirectOperation.values());
083        }
084
085
086        // Right section
087        _tabbedPaneData = new JTabbedPane();
088        _panelDataDirect = new javax.swing.JPanel();
089        _panelDataDirect.setLayout(new BoxLayout(_panelDataDirect, BoxLayout.Y_AXIS));
090        _panelDataReference = new javax.swing.JPanel();
091        _panelDataLocalVariable = new javax.swing.JPanel();
092        _panelDataFormula = new javax.swing.JPanel();
093
094        _tabbedPaneData.addTab(NamedBeanAddressing.Direct.toString(), _panelDataDirect);
095        _tabbedPaneData.addTab(NamedBeanAddressing.Reference.toString(), _panelDataReference);
096        _tabbedPaneData.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelDataLocalVariable);
097        _tabbedPaneData.addTab(NamedBeanAddressing.Formula.toString(), _panelDataFormula);
098
099        _panelMemoryBean = new BeanSelectPanel<>(InstanceManager.getDefault(MemoryManager.class), null);
100        _memoryPanel.add(_panelMemoryBean);
101        _panelDataDirect.add(_panelMemoryBean);
102
103        _controlTrainComboBox = new JComboBox<>();
104        for (ControlAutoTrain e : ControlAutoTrain.values()) {
105            _controlTrainComboBox.addItem(e);
106        }
107        JComboBoxUtil.setupComboBoxMaxRows(_controlTrainComboBox);
108        _panelControlTrainCombo = new JPanel();
109        _panelControlTrainCombo.add(_controlTrainComboBox);
110        _panelDataDirect.add(_panelControlTrainCombo);
111
112        _trainIdNameTextField = new JTextField();
113        _trainIdNameTextField.setColumns(30);
114        _panelTrainData = new JPanel();
115        _panelTrainData.add(_trainIdNameTextField);
116        _panelDataDirect.add(_panelTrainData);
117       
118        _warrantDataReferenceTextField = new JTextField();
119        _warrantDataReferenceTextField.setColumns(30);
120        _panelDataReference.add(_warrantDataReferenceTextField);
121
122        _warrantDataLocalVariableTextField = new JTextField();
123        _warrantDataLocalVariableTextField.setColumns(30);
124        _panelDataLocalVariable.add(_warrantDataLocalVariableTextField);
125
126        _warrantDataFormulaTextField = new JTextField();
127        _warrantDataFormulaTextField.setColumns(30);
128        _panelDataFormula.add(_warrantDataFormulaTextField);
129
130//        setDataPanelState();
131        _panelTrainData.setVisible(false);
132        _panelControlTrainCombo.setVisible(false);
133        _panelMemoryBean.setVisible(false);
134
135        if (action != null) {
136            switch (action.getDataAddressing()) {
137                case Direct: _tabbedPaneData.setSelectedComponent(_panelDataDirect); break;
138                case Reference: _tabbedPaneData.setSelectedComponent(_panelDataReference); break;
139                case LocalVariable: _tabbedPaneData.setSelectedComponent(_panelDataLocalVariable); break;
140                case Formula: _tabbedPaneData.setSelectedComponent(_panelDataFormula); break;
141                default: throw new IllegalArgumentException("invalid _addressing state: " + action.getDataAddressing().name());
142            }
143            _warrantDataReferenceTextField.setText(action.getDataReference());
144            _warrantDataLocalVariableTextField.setText(action.getDataLocalVariable());
145            _warrantDataFormulaTextField.setText(action.getDataFormula());
146
147            _trainIdNameTextField.setText(action.getTrainData());
148            _controlTrainComboBox.setSelectedItem(action.getControlAutoTrain());
149            if (action.getSelectMemoryNamedBean().getNamedBean() != null) {
150                _panelMemoryBean.setDefaultNamedBean(action.getSelectMemoryNamedBean().getNamedBean().getBean());
151            }
152
153            LogixNG_SelectEnum<DirectOperation> selectEnum = action.getSelectEnum();
154            if (selectEnum.getEnum() != null) {
155                switch (selectEnum.getEnum()) {
156                    case GetTrainLocation:
157                        _panelMemoryBean.setVisible(true);
158                        break;
159                    case SetTrainId:
160                    case SetTrainName:
161                        _panelTrainData.setVisible(true);
162                        break;
163                    case ControlAutoTrain:
164                        _panelControlTrainCombo.setVisible(true);
165                        break;
166                    default:
167                }
168            }
169        }
170
171        setDataPanelState();
172
173        _selectOperationSwing.addAddressingListener((evt) -> { setDataPanelState(); });
174        _selectOperationSwing.addEnumListener((evt) -> { setDataPanelState(); });
175
176        JComponent[] components = new JComponent[]{
177            _tabbedPaneNamedBean,
178            _tabbedPaneOperation,
179            _tabbedPaneData};
180
181        List<JComponent> componentList = SwingConfiguratorInterface.parseMessage(
182                Bundle.getMessage("ActionWarrant_Components"), components);
183
184        for (JComponent c : componentList) panel.add(c);
185    }
186
187    private void setDataPanelState() {
188        _panelControlTrainCombo.setVisible(false);
189        _panelTrainData.setVisible(false);
190        _panelMemoryBean.setVisible(false);
191
192        boolean newState = false;
193
194        if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.ControlAutoTrain)) {
195            _panelControlTrainCombo.setVisible(true);
196            newState = true;
197        } else if ( _selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.GetTrainLocation)) {
198            _panelMemoryBean.setVisible(true);
199            newState = true;
200        } else if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.SetTrainId) ||
201                _selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.SetTrainName)) {
202            _panelTrainData.setVisible(true);
203            newState = true;
204        }
205
206        _tabbedPaneData.setEnabled(newState);
207        _warrantDataReferenceTextField.setEnabled(newState);
208        _warrantDataLocalVariableTextField.setEnabled(newState);
209        _warrantDataFormulaTextField.setEnabled(newState);
210    }
211
212    /** {@inheritDoc} */
213    @Override
214    public boolean validate(@Nonnull List<String> errorMessages) {
215        ActionWarrant action = new ActionWarrant("IQDA1", null);
216        _selectNamedBeanSwing.validate(action.getSelectNamedBean(), errorMessages);
217        _selectOperationSwing.validate(action.getSelectEnum(), errorMessages);
218        validateDataSection(errorMessages);
219        return errorMessages.isEmpty();
220    }
221
222    private void validateDataSection(List<String> errorMessages) {
223        // Create a temporary action to test formula
224        ActionWarrant action = new ActionWarrant("IQDA3", null);
225
226        try {
227            if (_tabbedPaneData.getSelectedComponent() == _panelDataReference) {
228                action.setDataReference(_warrantDataReferenceTextField.getText());
229            }
230        } catch (IllegalArgumentException e) {
231            errorMessages.add(e.getMessage());
232            return;
233        }
234
235        try {
236            action.setDataFormula(_warrantDataFormulaTextField.getText());
237            if (_tabbedPaneData.getSelectedComponent() == _panelDataDirect) {
238                action.setDataAddressing(NamedBeanAddressing.Direct);
239            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataReference) {
240                action.setDataAddressing(NamedBeanAddressing.Reference);
241            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataLocalVariable) {
242                action.setDataAddressing(NamedBeanAddressing.LocalVariable);
243            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataFormula) {
244                action.setDataAddressing(NamedBeanAddressing.Formula);
245            } else {
246                throw new IllegalArgumentException("_tabbedPane has unknown selection");
247            }
248        } catch (ParserException e) {
249            errorMessages.add("Cannot parse formula: " + e.getMessage());
250        }
251
252        if (_tabbedPaneData.getSelectedComponent() == _panelDataDirect) {
253            if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.SetTrainId)
254                    || _selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.SetTrainName)) {
255                if (_trainIdNameTextField.getText().isEmpty()) {
256                    errorMessages.add(Bundle.getMessage("ActionWarrant_ErrorValue"));
257                }
258            } else if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.GetTrainLocation)) {
259                if (_panelMemoryBean.isEmpty() || _panelMemoryBean.getNamedBean() == null) {
260                    errorMessages.add(Bundle.getMessage("ActionWarrant_ErrorMemory"));
261                }
262            }
263        }
264    }
265
266    /** {@inheritDoc} */
267    @Override
268    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
269        ActionWarrant action = new ActionWarrant(systemName, userName);
270        updateObject(action);
271        return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action);
272    }
273
274    /** {@inheritDoc} */
275    @Override
276    public void updateObject(@Nonnull Base object) {
277        if (! (object instanceof ActionWarrant)) {
278            throw new IllegalArgumentException("object must be an ActionWarrant but is a: "+object.getClass().getName());
279        }
280        ActionWarrant action = (ActionWarrant) object;
281        _selectNamedBeanSwing.updateObject(action.getSelectNamedBean());
282        _selectOperationSwing.updateObject(action.getSelectEnum());
283
284        try {
285            // Right section
286            if (_tabbedPaneData.getSelectedComponent() == _panelDataDirect) {
287                action.setDataAddressing(NamedBeanAddressing.Direct);
288                // Handle optional data field
289                if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.SetTrainId)
290                        || _selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.SetTrainName)) {
291                    action.setTrainData(_trainIdNameTextField.getText());
292                } else if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.ControlAutoTrain)) {
293                    action.setControlAutoTrain((ControlAutoTrain) _controlTrainComboBox.getSelectedItem());
294                } else if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing(DirectOperation.GetTrainLocation)) {
295                    Memory memory = _panelMemoryBean.getNamedBean();
296                    if (memory != null) {
297                        NamedBeanHandle<Memory> handle
298                                = InstanceManager.getDefault(NamedBeanHandleManager.class)
299                                        .getNamedBeanHandle(memory.getDisplayName(), memory);
300                        action.getSelectMemoryNamedBean().setNamedBean(handle);
301                    } else {
302                        action.getSelectMemoryNamedBean().removeNamedBean();
303                    }
304                }
305            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataReference) {
306                action.setDataAddressing(NamedBeanAddressing.Reference);
307                action.setDataReference(_warrantDataReferenceTextField.getText());
308            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataLocalVariable) {
309                action.setDataAddressing(NamedBeanAddressing.LocalVariable);
310                action.setDataLocalVariable(_warrantDataLocalVariableTextField.getText());
311            } else if (_tabbedPaneData.getSelectedComponent() == _panelDataFormula) {
312                action.setDataAddressing(NamedBeanAddressing.Formula);
313                action.setDataFormula(_warrantDataFormulaTextField.getText());
314            } else {
315                throw new IllegalArgumentException("_tabbedPaneData has unknown selection");
316            }
317        } catch (ParserException e) {
318            throw new RuntimeException("ParserException: "+e.getMessage(), e);
319        }
320    }
321
322    /** {@inheritDoc} */
323    @Override
324    public String toString() {
325        return Bundle.getMessage("ActionWarrant_Short");
326    }
327
328    @Override
329    public void dispose() {
330        _selectNamedBeanSwing.dispose();
331        _selectOperationSwing.dispose();
332    }
333
334
335//     private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionWarrantSwing.class);
336
337}