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