001package jmri.jmrit.logixng.actions.swing;
002
003import java.awt.event.ActionEvent;
004import java.util.List;
005
006import javax.annotation.CheckForNull;
007import javax.annotation.Nonnull;
008import javax.swing.*;
009import javax.swing.filechooser.FileNameExtensionFilter;
010
011import jmri.InstanceManager;
012import jmri.jmrit.logixng.*;
013import jmri.jmrit.logixng.actions.ActionSound;
014import jmri.jmrit.logixng.actions.ActionSound.Operation;
015import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
016import jmri.jmrit.logixng.util.parser.ParserException;
017import jmri.jmrit.logixng.util.swing.LogixNG_SelectEnumSwing;
018import jmri.util.FileUtil;
019
020/**
021 * Configures an ActionSound object with a Swing JPanel.
022 *
023 * @author Daniel Bergqvist 2021
024 */
025public class ActionSoundSwing extends AbstractDigitalActionSwing {
026
027    public static final int NUM_COLUMNS_TEXT_FIELDS = 20;
028
029    private LogixNG_SelectEnumSwing<Operation> _selectOperationSwing;
030
031    private JTabbedPane _tabbedPaneSoundType;
032    private JPanel _panelSoundTypeDirect;
033    private JPanel _panelSoundTypeReference;
034    private JPanel _panelSoundTypeLocalVariable;
035    private JPanel _panelSoundTypeFormula;
036
037    private JFileChooser soundFileChooser;
038    private JTextField _soundTextField;
039    private JTextField _soundReferenceTextField;
040    private JTextField _soundLocalVariableTextField;
041    private JTextField _soundFormulaTextField;
042
043
044    public ActionSoundSwing() {
045    }
046
047    public ActionSoundSwing(JDialog dialog) {
048        super.setJDialog(dialog);
049    }
050
051    @Override
052    protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) {
053        ActionSound action = (ActionSound)object;
054
055        _selectOperationSwing = new LogixNG_SelectEnumSwing<>(getJDialog(), this);
056
057        panel = new JPanel();
058        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
059
060        JPanel actionPanel = new JPanel();
061
062
063        // Set up the tabbed pane for selecting the operation
064        JPanel _tabbedPaneOperation;
065        if (action != null) {
066            _tabbedPaneOperation = _selectOperationSwing.createPanel(action.getSelectEnum(), Operation.values());
067        } else {
068            _tabbedPaneOperation = _selectOperationSwing.createPanel(null, Operation.values());
069        }
070
071
072        // Set up the tabbed pane for selecting the appearance
073        _tabbedPaneSoundType = new JTabbedPane();
074        _panelSoundTypeDirect = new javax.swing.JPanel();
075//        _panelSoundTypeDirect.setLayout(new BoxLayout(_panelSoundTypeDirect, BoxLayout.Y_AXIS));
076        _panelSoundTypeReference = new javax.swing.JPanel();
077        _panelSoundTypeReference.setLayout(new BoxLayout(_panelSoundTypeReference, BoxLayout.Y_AXIS));
078        _panelSoundTypeLocalVariable = new javax.swing.JPanel();
079        _panelSoundTypeLocalVariable.setLayout(new BoxLayout(_panelSoundTypeLocalVariable, BoxLayout.Y_AXIS));
080        _panelSoundTypeFormula = new javax.swing.JPanel();
081        _panelSoundTypeFormula.setLayout(new BoxLayout(_panelSoundTypeFormula, BoxLayout.Y_AXIS));
082
083        _tabbedPaneSoundType.addTab(NamedBeanAddressing.Direct.toString(), _panelSoundTypeDirect);
084        _tabbedPaneSoundType.addTab(NamedBeanAddressing.Reference.toString(), _panelSoundTypeReference);
085        _tabbedPaneSoundType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelSoundTypeLocalVariable);
086        _tabbedPaneSoundType.addTab(NamedBeanAddressing.Formula.toString(), _panelSoundTypeFormula);
087
088        JButton _actionSelectFileButton = new JButton("..."); // "File" replaced by ...
089        _actionSelectFileButton.setMaximumSize(_actionSelectFileButton.getPreferredSize());
090        _actionSelectFileButton.setToolTipText(Bundle.getMessage("FileButtonHint"));  // NOI18N
091        _actionSelectFileButton.addActionListener((ActionEvent e) -> {
092            soundFileChooser = new jmri.util.swing.JmriJFileChooser(System.getProperty("user.dir") // NOI18N
093                    + java.io.File.separator + "resources" // NOI18N
094                    + java.io.File.separator + "sounds");  // NOI18N
095            soundFileChooser.setFileFilter(new FileNameExtensionFilter("wav sound files", "wav")); // NOI18N
096            soundFileChooser.rescanCurrentDirectory();
097            int retVal = soundFileChooser.showOpenDialog(null);
098            // handle selection or cancel
099            if (retVal == JFileChooser.APPROVE_OPTION) {
100                // set selected file location
101                try {
102                    _soundTextField.setText(FileUtil.getPortableFilename(soundFileChooser.getSelectedFile().getCanonicalPath()));
103                } catch (java.io.IOException ex) {
104                    log.error("exception setting file location", ex);  // NOI18N
105                    _soundTextField.setText("");
106                }
107            }
108        });
109        _panelSoundTypeDirect.add(_actionSelectFileButton);
110        JPanel _soundTextPanel = new JPanel();
111        _soundTextPanel.setLayout(new BoxLayout(_soundTextPanel, BoxLayout.Y_AXIS));
112        _soundTextField = new JTextField(30);
113        _soundTextPanel.add(new JLabel(Bundle.getMessage("ActionSound_Sound")));
114        _soundTextPanel.add(_soundTextField);
115        _panelSoundTypeDirect.add(_soundTextPanel);
116
117        _soundReferenceTextField = new JTextField();
118        _soundReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
119        _panelSoundTypeReference.add(new JLabel(Bundle.getMessage("ActionSound_Sound")));
120        _panelSoundTypeReference.add(_soundReferenceTextField);
121
122        _soundLocalVariableTextField = new JTextField();
123        _soundLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
124        _panelSoundTypeLocalVariable.add(new JLabel(Bundle.getMessage("ActionSound_Sound")));
125        _panelSoundTypeLocalVariable.add(_soundLocalVariableTextField);
126
127        _soundFormulaTextField = new JTextField();
128        _soundFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS);
129        _panelSoundTypeFormula.add(new JLabel(Bundle.getMessage("ActionSound_Sound")));
130        _panelSoundTypeFormula.add(_soundFormulaTextField);
131
132
133        if (action != null) {
134            switch (action.getSoundAddressing()) {
135                case Direct: _tabbedPaneSoundType.setSelectedComponent(_panelSoundTypeDirect); break;
136                case Reference: _tabbedPaneSoundType.setSelectedComponent(_panelSoundTypeReference); break;
137                case LocalVariable: _tabbedPaneSoundType.setSelectedComponent(_panelSoundTypeLocalVariable); break;
138                case Formula: _tabbedPaneSoundType.setSelectedComponent(_panelSoundTypeFormula); break;
139                default: throw new IllegalArgumentException("invalid _addressing state: " + action.getSoundAddressing().name());
140            }
141            _soundTextField.setText(action.getSound());
142            _soundReferenceTextField.setText(action.getSoundReference());
143            _soundLocalVariableTextField.setText(action.getSoundLocalVariable());
144            _soundFormulaTextField.setText(action.getSoundFormula());
145        }
146
147        JComponent[] components = new JComponent[]{
148            _tabbedPaneOperation,
149            _tabbedPaneSoundType
150        };
151
152        List<JComponent> componentList = SwingConfiguratorInterface.parseMessage(
153                Bundle.getMessage("ActionSound_Components"), components);
154
155        for (JComponent c : componentList) actionPanel.add(c);
156        panel.add(actionPanel);
157    }
158
159    /** {@inheritDoc} */
160    @Override
161    public boolean validate(@Nonnull List<String> errorMessages) {
162        // Create a temporary action to test formula
163        ActionSound action = new ActionSound("IQDA1", null);
164
165        _selectOperationSwing.validate(action.getSelectEnum(), errorMessages);
166
167        try {
168            action.setSoundFormula(_soundFormulaTextField.getText());
169            if (_tabbedPaneSoundType.getSelectedComponent() == _panelSoundTypeDirect) {
170                action.setSoundAddressing(NamedBeanAddressing.Direct);
171            } else if (_tabbedPaneSoundType.getSelectedComponent() == _panelSoundTypeReference) {
172                action.setSoundAddressing(NamedBeanAddressing.Reference);
173            } else if (_tabbedPaneSoundType.getSelectedComponent() == _panelSoundTypeLocalVariable) {
174                action.setSoundAddressing(NamedBeanAddressing.LocalVariable);
175            } else if (_tabbedPaneSoundType.getSelectedComponent() == _panelSoundTypeFormula) {
176                action.setSoundAddressing(NamedBeanAddressing.Formula);
177            } else {
178                throw new IllegalArgumentException("_tabbedPaneSoundType has unknown selection");
179            }
180        } catch (ParserException e) {
181            errorMessages.add("Cannot parse formula: " + e.getMessage());
182        }
183        return true;
184    }
185
186    /** {@inheritDoc} */
187    @Override
188    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) {
189        ActionSound action = new ActionSound(systemName, userName);
190        updateObject(action);
191        return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action);
192    }
193
194    /** {@inheritDoc} */
195    @Override
196    public void updateObject(@Nonnull Base object) {
197        if (! (object instanceof ActionSound)) {
198            throw new IllegalArgumentException("object must be an ActionSound but is a: "+object.getClass().getName());
199        }
200        ActionSound action = (ActionSound)object;
201
202        _selectOperationSwing.updateObject(action.getSelectEnum());
203
204        try {
205            if (_tabbedPaneSoundType.getSelectedComponent() == _panelSoundTypeDirect) {
206                action.setSoundAddressing(NamedBeanAddressing.Direct);
207                action.setSound(_soundTextField.getText());
208            } else if (_tabbedPaneSoundType.getSelectedComponent() == _panelSoundTypeReference) {
209                action.setSoundAddressing(NamedBeanAddressing.Reference);
210                action.setSoundReference(_soundReferenceTextField.getText());
211            } else if (_tabbedPaneSoundType.getSelectedComponent() == _panelSoundTypeLocalVariable) {
212                action.setSoundAddressing(NamedBeanAddressing.LocalVariable);
213                action.setSoundLocalVariable(_soundLocalVariableTextField.getText());
214            } else if (_tabbedPaneSoundType.getSelectedComponent() == _panelSoundTypeFormula) {
215                action.setSoundAddressing(NamedBeanAddressing.Formula);
216                action.setSoundFormula(_soundFormulaTextField.getText());
217            } else {
218                throw new IllegalArgumentException("_tabbedPaneAspectType has unknown selection");
219            }
220        } catch (ParserException e) {
221            throw new RuntimeException("ParserException: "+e.getMessage(), e);
222        }
223    }
224
225    /** {@inheritDoc} */
226    @Override
227    public String toString() {
228        return Bundle.getMessage("ActionSound_Short");
229    }
230
231    @Override
232    public void dispose() {
233        _selectOperationSwing.dispose();
234    }
235
236
237    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionSoundSwing.class);
238
239}