001package jmri.jmrit.vsdecoder;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005import javax.swing.JComponent;
006import jmri.Throttle;
007import jmri.jmrit.vsdecoder.swing.DieselPane;
008import org.jdom2.Element;
009
010/**
011 * Handles sound events for all types.
012 *
013 * <hr>
014 * This file is part of JMRI.
015 * <p>
016 * JMRI is free software; you can redistribute it and/or modify it under
017 * the terms of version 2 of the GNU General Public License as published
018 * by the Free Software Foundation. See the "COPYING" file for a copy
019 * of this license.
020 * <p>
021 * JMRI is distributed in the hope that it will be useful, but WITHOUT
022 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
023 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
024 * for more details.
025 *
026 * @author Mark Underwood Copyright (C) 2011
027 * @author Klaus Killinger Copyright (C) 2018-2021
028 */
029public class EngineSoundEvent extends SoundEvent {
030
031    EnginePane engine_pane;
032
033    /*
034     Trigger t; // used in setXml as a temporary holder for creating the
035     // event listener class.
036
037     ButtonTrigger bt; // used in setupButtonAction() as a temporary holder
038     // for creating the button listeners.
039     */
040
041    public EngineSoundEvent(String n) {
042        super(n);
043        engine_pane = null;
044    }
045
046    @Override
047    public boolean hasButton() {
048        if ((buttontype == ButtonType.NONE) || (buttontype == ButtonType.ENGINE) || (button == null)) {
049            return false;
050        } else {
051            return true;
052        }
053    }
054
055    @Override
056    public boolean hasEnginePane() {
057        if ((buttontype == ButtonType.ENGINE) && (engine_pane != null)) {
058            return true;
059        } else {
060            return false;
061        }
062    }
063
064    @Override
065    public JComponent getButton() {
066        log.debug("engine getButton() called.");
067        return engine_pane;
068    }
069
070    @Override
071    public EnginePane getEnginePane() {
072        return engine_pane;
073    }
074
075    @Override
076    public void setEnginePane(EnginePane e) {
077        engine_pane = e;
078    }
079
080    @Override
081    public void setButtonLabel(String bl) {
082        // can't do this.  Yet.
083    }
084
085    @Override
086    public String getButtonLabel() {
087        // can't do this. Yet.
088        //return(engine_pane.getText());
089        return "Text";
090    }
091
092    @Override
093    protected ButtonTrigger setupButtonAction(Element te) {
094        /*
095         MouseListener ml;
096         bt = new ButtonTrigger(te.getAttributeValue("name"));
097         button_trigger_list.put(bt.getName(), bt);
098         log.debug("new ButtonTrigger " + bt.getName() + " type " + btype.toString());
099         switch(btype) {
100         case TOGGLE:
101         this.getButton().addActionListener(bt);
102         break;
103         case MOMENTARY:
104         default:
105         this.getButton().addMouseListener(bt);
106         // Just send the trigger a click.
107         }
108         return(bt);  // cast OK since we just instantiated it up above.
109         */
110        return null;  // cast OK since we just instantiated it up above.
111    }
112
113    public void guiAction(PropertyChangeEvent evt) {
114        if (evt.getPropertyName().equals(DieselPane.START)) {
115            log.debug("GUI Start button changed. New value: {}", evt.getNewValue());
116            if (this.getParent().getEngineSound() != null) {
117                if ((Boolean) evt.getNewValue()) {
118                        this.getParent().getEngineSound().setEngineStarted(true);
119                        this.parent.getEngineSound().startEngine();
120                } else {
121                        this.getParent().getEngineSound().setEngineStarted(false);
122                        this.getParent().getEngineSound().stopEngine();
123                }
124            } else {
125                log.warn("Lost context, VSDecoder is null. Quit JMRI and start over.");
126            }
127        } else if (evt.getPropertyName().equals(DieselPane.VOLUME)) {
128            log.debug("decoder volume: {}", evt.getOldValue());
129            this.getParent().setDecoderVolume((1.0f * (Integer) evt.getOldValue()) / 100.0f);
130            // save to Roster Media
131            if (this.getParent().getRosterEntry() != null) {
132                this.getParent().getRosterEntry().putAttribute("VSDecoder_Volume", String.valueOf(this.getParent().getDecoderVolume()));
133            }
134        }
135    }
136
137    @Override
138    public void propertyChange(PropertyChangeEvent event) {
139        super.propertyChange(event);
140        if (event.getPropertyName().equals(Throttle.SPEEDSETTING)) {
141            this.getParent().getEngineSound().handleSpeedChange((Float) event.getNewValue(), engine_pane);
142        } else if (event.getPropertyName().equals(Throttle.ISFORWARD)) {
143            this.getParent().getEngineSound().changeLocoDirection((Boolean) event.getNewValue() ? 1 : -1);
144            log.debug("is forward: {}", event.getNewValue());
145        } else if (event.getPropertyName().startsWith("F")) {
146            String ev = event.getPropertyName();
147            boolean val = (Boolean) event.getNewValue();
148            for (Trigger t : trigger_list.values()) {
149                log.debug("trigger name: {}, event: {}, target: {}", t.getName(), t.getEventName(), t.getTargetName());
150                if (ev.equals(t.getEventName())) {
151                    if (t.getName().equals("ENGINE_STARTSTOP")) {
152                        getEnginePane().startButtonClick();
153                    } else {
154                        this.getParent().getEngineSound().functionKey(ev, val, t.getName());
155                        log.debug("event {} is {}", ev, val);
156                    }
157                }
158            }
159        }
160    }
161
162    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="BC_UNCONFIRMED_CAST",
163            justification="DieselPane extends EnginePane")
164    private void setDecoderVolume() {
165        // Get decoder volume and pass it to the spinner
166        int dv = Math.round(this.getParent().getDecoderVolume() * 100f);
167        ((DieselPane) engine_pane).getVolumeSlider().setValue(dv);
168    }
169
170    @Override
171    public Element getXml() {
172        Element me = new Element("SoundEvent");
173        me.setAttribute("name", name);
174        me.setAttribute("label", me.getText());
175        for (Trigger t : trigger_list.values()) {
176            me.addContent(t.getXml());
177        }
178        return me;
179    }
180
181    @Override
182    public void setXml(Element el) {
183        this.setXml(el, null);
184    }
185
186    @Override
187    public void setXml(Element el, VSDFile vf) {
188        // Create the "button"  (should this be in constructor)
189        log.debug("Creating DieselPane");
190        engine_pane = new DieselPane("Engine");
191
192        setDecoderVolume();
193
194        // Handle common stuff
195        super.setXml(el, vf);
196
197        // Get the SoundEvent's button type and create it.
198        engine_pane.addPropertyChangeListener(new PropertyChangeListener() {
199            @Override
200            public void propertyChange(PropertyChangeEvent evt) {
201                guiAction(evt);
202            }
203        });
204
205        // Forward an option passed from the trigger ENGINE_STARTSTOP
206        // The option can force speed zero before the engine can be stopped
207        for (Trigger t : trigger_list.values()) {
208            if (t.getName().equals("ENGINE_STARTSTOP")) {
209                if (t.getTargetAction().equals(jmri.jmrit.vsdecoder.Trigger.TargetAction.STOP_AT_ZERO)) {
210                    engine_pane.setStopOption(true); // force speed zero
211                } else {
212                    engine_pane.setStopOption(false); // engine can be stopped at any speed
213                }
214            }
215        }
216
217        if (log.isDebugEnabled()) {
218            for (ButtonTrigger bt : button_trigger_list.values()) {
219                log.debug("Button Trigger: {}", bt.getName());
220                log.debug("  Target: {}", bt.getTarget().getName());
221                log.debug("  Action: {}", bt.getTargetAction());
222            }
223            for (Trigger bt : trigger_list.values()) {
224                log.debug("Trigger: {}", bt.getName());
225                log.debug("  Target: {}", bt.getTarget());
226                log.debug("  Action: {}", bt.getTargetAction());
227            }
228        }
229    }
230
231    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(EngineSoundEvent.class);
232
233}