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}