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}