001package jmri.jmrit.display.logixng.swing;
002
003import java.awt.event.ActionEvent;
004import java.util.*;
005
006import javax.annotation.CheckForNull;
007import javax.annotation.Nonnull;
008import javax.swing.*;
009
010import jmri.InstanceManager;
011import jmri.jmrit.display.Editor;
012import jmri.jmrit.display.EditorManager;
013import jmri.jmrit.display.Positionable;
014import jmri.jmrit.logixng.*;
015import jmri.jmrit.display.logixng.ActionPositionable;
016import jmri.jmrit.display.logixng.ActionPositionable.Operation;
017import jmri.jmrit.logixng.actions.swing.AbstractDigitalActionSwing;
018import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
019import jmri.jmrit.logixng.util.parser.ParserException;
020import jmri.util.swing.JComboBoxUtil;
021
022/**
023 * Configures an ActionPositionable object with a Swing JPanel.
024 *
025 * @author Daniel Bergqvist Copyright (C) 2021
026 */
027public class ActionPositionableSwing extends AbstractDigitalActionSwing {
028
029    private String _selectedEditor;
030
031    private JComboBox<EditorItem> _editorComboBox;
032    private JTabbedPane _tabbedPanePositionable;
033    private JComboBox<String> _positionableComboBox;
034    private JPanel _panelPositionableDirect;
035    private JPanel _panelPositionableReference;
036    private JPanel _panelPositionableLocalVariable;
037    private JPanel _panelPositionableFormula;
038    private JTextField _positionableReferenceTextField;
039    private JTextField _positionableLocalVariableTextField;
040    private JTextField _positionableFormulaTextField;
041
042    private JTabbedPane _tabbedPanePositionableState;
043    private JComboBox<Operation> _isControllingComboBox;
044    private JPanel _panelPositionableStateDirect;
045    private JPanel _panelPositionableStateReference;
046    private JPanel _panelPositionableStateLocalVariable;
047    private JPanel _panelPositionableStateFormula;
048    private JTextField _positionableStateReferenceTextField;
049    private JTextField _positionableStateLocalVariableTextField;
050    private JTextField _positionableStateFormulaTextField;
051
052
053    @Override
054    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
055        ActionPositionable action = (ActionPositionable)object;
056
057        panel = new JPanel();
058
059        _selectedEditor = action != null ? action.getEditorName() : null;
060
061        _editorComboBox = new JComboBox<>();
062        JComboBoxUtil.setupComboBoxMaxRows(_editorComboBox);
063        for (Editor editor : jmri.InstanceManager.getDefault(EditorManager.class).getAll()) {
064            EditorItem item = new EditorItem(editor);
065            _editorComboBox.addItem(item);
066            if (editor.getName().equals(_selectedEditor)) _editorComboBox.setSelectedItem(item);
067        }
068        _editorComboBox.addActionListener(this::updatePositionables);
069
070        _tabbedPanePositionable = new JTabbedPane();
071        _panelPositionableDirect = new javax.swing.JPanel();
072        _panelPositionableReference = new javax.swing.JPanel();
073        _panelPositionableLocalVariable = new javax.swing.JPanel();
074        _panelPositionableFormula = new javax.swing.JPanel();
075
076        _tabbedPanePositionable.addTab(NamedBeanAddressing.Direct.toString(), _panelPositionableDirect);
077        _tabbedPanePositionable.addTab(NamedBeanAddressing.Reference.toString(), _panelPositionableReference);
078        _tabbedPanePositionable.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelPositionableLocalVariable);
079        _tabbedPanePositionable.addTab(NamedBeanAddressing.Formula.toString(), _panelPositionableFormula);
080
081        _positionableComboBox = new JComboBox<>();
082        JComboBoxUtil.setupComboBoxMaxRows(_positionableComboBox);
083        updatePositionables(null);
084        _panelPositionableDirect.add(_positionableComboBox);
085
086        _positionableReferenceTextField = new JTextField();
087        _positionableReferenceTextField.setColumns(30);
088        _panelPositionableReference.add(_positionableReferenceTextField);
089
090        _positionableLocalVariableTextField = new JTextField();
091        _positionableLocalVariableTextField.setColumns(30);
092        _panelPositionableLocalVariable.add(_positionableLocalVariableTextField);
093
094        _positionableFormulaTextField = new JTextField();
095        _positionableFormulaTextField.setColumns(30);
096        _panelPositionableFormula.add(_positionableFormulaTextField);
097
098
099        _tabbedPanePositionableState = new JTabbedPane();
100        _panelPositionableStateDirect = new javax.swing.JPanel();
101        _panelPositionableStateReference = new javax.swing.JPanel();
102        _panelPositionableStateLocalVariable = new javax.swing.JPanel();
103        _panelPositionableStateFormula = new javax.swing.JPanel();
104
105        _tabbedPanePositionableState.addTab(NamedBeanAddressing.Direct.toString(), _panelPositionableStateDirect);
106        _tabbedPanePositionableState.addTab(NamedBeanAddressing.Reference.toString(), _panelPositionableStateReference);
107        _tabbedPanePositionableState.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelPositionableStateLocalVariable);
108        _tabbedPanePositionableState.addTab(NamedBeanAddressing.Formula.toString(), _panelPositionableStateFormula);
109
110        _isControllingComboBox = new JComboBox<>();
111        for (Operation e : Operation.values()) {
112            _isControllingComboBox.addItem(e);
113        }
114        JComboBoxUtil.setupComboBoxMaxRows(_isControllingComboBox);
115
116        _panelPositionableStateDirect.add(_isControllingComboBox);
117
118        _positionableStateReferenceTextField = new JTextField();
119        _positionableStateReferenceTextField.setColumns(30);
120        _panelPositionableStateReference.add(_positionableStateReferenceTextField);
121
122        _positionableStateLocalVariableTextField = new JTextField();
123        _positionableStateLocalVariableTextField.setColumns(30);
124        _panelPositionableStateLocalVariable.add(_positionableStateLocalVariableTextField);
125
126        _positionableStateFormulaTextField = new JTextField();
127        _positionableStateFormulaTextField.setColumns(30);
128        _panelPositionableStateFormula.add(_positionableStateFormulaTextField);
129
130
131        if (action != null) {
132            switch (action.getAddressing()) {
133                case Direct: _tabbedPanePositionable.setSelectedComponent(_panelPositionableDirect); break;
134                case Reference: _tabbedPanePositionable.setSelectedComponent(_panelPositionableReference); break;
135                case LocalVariable: _tabbedPanePositionable.setSelectedComponent(_panelPositionableLocalVariable); break;
136                case Formula: _tabbedPanePositionable.setSelectedComponent(_panelPositionableFormula); break;
137                default: throw new IllegalArgumentException("invalid _addressing state: " + action.getAddressing().name());
138            }
139            if (action.getPositionableName() != null) {
140                _positionableComboBox.setSelectedItem(action.getPositionableName());
141            }
142            _positionableReferenceTextField.setText(action.getReference());
143            _positionableLocalVariableTextField.setText(action.getLocalVariable());
144            _positionableFormulaTextField.setText(action.getFormula());
145
146            switch (action.getStateAddressing()) {
147                case Direct: _tabbedPanePositionableState.setSelectedComponent(_panelPositionableStateDirect); break;
148                case Reference: _tabbedPanePositionableState.setSelectedComponent(_panelPositionableStateReference); break;
149                case LocalVariable: _tabbedPanePositionableState.setSelectedComponent(_panelPositionableStateLocalVariable); break;
150                case Formula: _tabbedPanePositionableState.setSelectedComponent(_panelPositionableStateFormula); break;
151                default: throw new IllegalArgumentException("invalid _addressing state: " + action.getAddressing().name());
152            }
153            _isControllingComboBox.setSelectedItem(action.getOperation());
154            _positionableStateReferenceTextField.setText(action.getStateReference());
155            _positionableStateLocalVariableTextField.setText(action.getStateLocalVariable());
156            _positionableStateFormulaTextField.setText(action.getStateFormula());
157        }
158
159        JComponent[] components = new JComponent[]{
160            _editorComboBox,
161            _tabbedPanePositionable,
162            _tabbedPanePositionableState};
163
164        List<JComponent> componentList = SwingConfiguratorInterface.parseMessage(
165                Bundle.getMessage("ActionPositionable_Components"), components);
166
167        for (JComponent c : componentList) panel.add(c);
168    }
169
170    private void updatePositionables(ActionEvent e) {
171        _positionableComboBox.removeAllItems();
172        if (_editorComboBox.getSelectedIndex() == -1) return;
173
174        EditorItem item = _editorComboBox.getItemAt(_editorComboBox.getSelectedIndex());
175        List<String> list = new ArrayList<>();
176        for (Positionable positionable : item._editor.getContents()) {
177            if (positionable.getId() != null) {
178                list.add(positionable.getId());
179            }
180        }
181        Collections.sort(list);
182        for (String s : list) {
183            _positionableComboBox.addItem(s);
184        }
185    }
186
187    /** {@inheritDoc} */
188    @Override
189    public boolean validate(@Nonnull List<String> errorMessages) {
190        // Create a temporary action to test formula
191        ActionPositionable action = new ActionPositionable("IQDA1", null);
192
193        try {
194            if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableReference) {
195                action.setReference(_positionableReferenceTextField.getText());
196            }
197        } catch (IllegalArgumentException e) {
198            errorMessages.add(e.getMessage());
199            return false;
200        }
201
202        try {
203            if (_tabbedPanePositionableState.getSelectedComponent() == _panelPositionableStateReference) {
204                action.setStateReference(_positionableStateReferenceTextField.getText());
205            }
206        } catch (IllegalArgumentException e) {
207            errorMessages.add(e.getMessage());
208            return false;
209        }
210
211        try {
212            action.setFormula(_positionableFormulaTextField.getText());
213            if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableDirect) {
214                action.setAddressing(NamedBeanAddressing.Direct);
215            } else if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableReference) {
216                action.setAddressing(NamedBeanAddressing.Reference);
217            } else if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableLocalVariable) {
218                action.setAddressing(NamedBeanAddressing.LocalVariable);
219            } else if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableFormula) {
220                action.setAddressing(NamedBeanAddressing.Formula);
221            } else {
222                throw new IllegalArgumentException("_tabbedPane has unknown selection");
223            }
224        } catch (ParserException e) {
225            errorMessages.add("Cannot parse formula: " + e.getMessage());
226        }
227        return true;
228    }
229
230    /** {@inheritDoc} */
231    @Override
232    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
233        ActionPositionable action = new ActionPositionable(systemName, userName);
234        updateObject(action);
235        return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action);
236    }
237
238    /** {@inheritDoc} */
239    @Override
240    public void updateObject(@Nonnull Base object) {
241        if (! (object instanceof ActionPositionable)) {
242            throw new IllegalArgumentException("object must be an ActionPositionable but is a: "+object.getClass().getName());
243        }
244        ActionPositionable action = (ActionPositionable)object;
245        if (_editorComboBox.getSelectedIndex() != -1) {
246            action.setEditor(_editorComboBox.getItemAt(_editorComboBox.getSelectedIndex())._editor.getName());
247        }
248        if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableDirect) {
249            action.setPositionable(_positionableComboBox.getItemAt(_positionableComboBox.getSelectedIndex()));
250        }
251        try {
252            if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableDirect) {
253                action.setAddressing(NamedBeanAddressing.Direct);
254            } else if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableReference) {
255                action.setAddressing(NamedBeanAddressing.Reference);
256                action.setReference(_positionableReferenceTextField.getText());
257            } else if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableLocalVariable) {
258                action.setAddressing(NamedBeanAddressing.LocalVariable);
259                action.setLocalVariable(_positionableLocalVariableTextField.getText());
260            } else if (_tabbedPanePositionable.getSelectedComponent() == _panelPositionableFormula) {
261                action.setAddressing(NamedBeanAddressing.Formula);
262                action.setFormula(_positionableFormulaTextField.getText());
263            } else {
264                throw new IllegalArgumentException("_tabbedPanePositionable has unknown selection");
265            }
266
267            if (_tabbedPanePositionableState.getSelectedComponent() == _panelPositionableStateDirect) {
268                action.setStateAddressing(NamedBeanAddressing.Direct);
269                action.setOperation(_isControllingComboBox.getItemAt(_isControllingComboBox.getSelectedIndex()));
270            } else if (_tabbedPanePositionableState.getSelectedComponent() == _panelPositionableStateReference) {
271                action.setStateAddressing(NamedBeanAddressing.Reference);
272                action.setStateReference(_positionableStateReferenceTextField.getText());
273            } else if (_tabbedPanePositionableState.getSelectedComponent() == _panelPositionableStateLocalVariable) {
274                action.setStateAddressing(NamedBeanAddressing.LocalVariable);
275                action.setStateLocalVariable(_positionableStateLocalVariableTextField.getText());
276            } else if (_tabbedPanePositionableState.getSelectedComponent() == _panelPositionableStateFormula) {
277                action.setStateAddressing(NamedBeanAddressing.Formula);
278                action.setStateFormula(_positionableStateFormulaTextField.getText());
279            } else {
280                throw new IllegalArgumentException("_tabbedPanePositionableState has unknown selection");
281            }
282        } catch (ParserException e) {
283            throw new RuntimeException("ParserException: "+e.getMessage(), e);
284        }
285    }
286
287    /** {@inheritDoc} */
288    @Override
289    public String toString() {
290        return Bundle.getMessage("ActionPositionable_Short");
291    }
292
293    @Override
294    public void dispose() {
295        // Do nothing
296    }
297
298
299    private static class EditorItem {
300
301        private final Editor _editor;
302
303        public EditorItem(Editor editor) {
304            this._editor = editor;
305        }
306
307        @Override
308        public String toString() {
309            return _editor.getName();
310        }
311    }
312
313
314//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionPositionableSwing.class);
315
316}