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