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