001package jmri.jmrit.vsdecoder; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.util.HashMap; 006import java.util.Iterator; 007import javax.swing.AbstractButton; 008import javax.swing.JComponent; 009import org.jdom2.Element; 010 011/** 012 * Process Sound Events. 013 * 014 * <hr> 015 * This file is part of JMRI. 016 * <p> 017 * JMRI is free software; you can redistribute it and/or modify it under 018 * the terms of version 2 of the GNU General Public License as published 019 * by the Free Software Foundation. See the "COPYING" file for a copy 020 * of this license. 021 * <p> 022 * JMRI is distributed in the hope that it will be useful, but WITHOUT 023 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 024 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 025 * for more details. 026 * 027 * @author Mark Underwood Copyright (C) 2011 028 */ 029public class SoundEvent implements PropertyChangeListener { 030 031 public enum ButtonType { 032 033 MOMENTARY, TOGGLE, ENGINE, NONE 034 } 035 036 String name; 037 String event_name; 038 ButtonType buttontype; 039 040 AbstractButton button; 041 EnginePane engine_pane; 042 043 Trigger t; // used in setXml as a temporary holder for creating the 044 // event listener class. 045 ButtonTrigger bt; // used in setupButtonAction() as a temporary holder 046 // for creating the button listeners. 047 VSDecoder parent; 048 049 protected HashMap<String, ButtonTrigger> button_trigger_list; 050 051 protected HashMap<String, Trigger> trigger_list; 052 VSDSound my_sound; 053 054 public SoundEvent(String n) { 055 name = n; 056 trigger_list = new HashMap<>(); 057 button_trigger_list = new HashMap<>(); 058 button = null; 059 } 060 061 public void setName(String n) { 062 name = n; 063 } 064 065 public String getName() { 066 return name; 067 } 068 069 public void setEventName(String n) { 070 event_name = n; 071 } 072 073 public String getEventName() { 074 return event_name; 075 } 076 077 public ButtonType getButtonType() { 078 return buttontype; 079 } 080 081 public boolean hasButton() { 082 if ((buttontype == ButtonType.NONE) || (buttontype == ButtonType.ENGINE) || (button == null)) { 083 return false; 084 } else { 085 return true; 086 } 087 } 088 089 public boolean hasEnginePane() { 090 if ((buttontype == ButtonType.ENGINE) && (engine_pane != null)) { 091 return true; 092 } else { 093 return false; 094 } 095 } 096 097 public void setButton(AbstractButton b) { 098 button = b; 099 } 100 101 public JComponent getButton() { 102 if ((buttontype == ButtonType.NONE) || (buttontype == ButtonType.ENGINE)) { 103 return null; 104 } else { 105 return button; 106 } 107 } 108 109 public EnginePane getEnginePane() { 110 if (buttontype == ButtonType.ENGINE) { 111 return engine_pane; 112 } else { 113 return null; 114 } 115 } 116 117 public void setEnginePane(EnginePane e) { 118 engine_pane = e; 119 } 120 121 public void setButtonLabel(String bl) { 122 button.setText(bl); 123 } 124 125 public String getButtonLabel() { 126 return button.getText(); 127 } 128 129 public void addTrigger(String s, Trigger t) { 130 trigger_list.put(s, t); 131 } 132 133 public Trigger getTrigger(String s) { 134 return trigger_list.get(s); 135 } 136 137 public void setSound(VSDSound v) { 138 my_sound = v; 139 } 140 141 public VSDSound getSound() { 142 return my_sound; 143 } 144 145 public void setParent(VSDecoder v) { 146 parent = v; 147 } 148 149 public VSDecoder getParent() { 150 return parent; 151 } 152 153 @Override 154 public void propertyChange(PropertyChangeEvent event) { 155 for (Trigger t : trigger_list.values()) { 156 t.propertyChange(event); 157 } 158 } 159 160 // What's wrong here: 161 // the anonymous MouseListeners are storing a reference to BT, which keeps getting replaced 162 // each time the function is called. 163 // what we need to do is (maybe) make the ButtonTrigger itself a MouseListener (and ActionListener) 164 // 165 protected ButtonTrigger setupButtonAction(Element te) { 166 /* 167 MouseListener ml; 168 bt = new ButtonTrigger(te.getAttributeValue("name")); 169 button_trigger_list.put(bt.getName(), bt); 170 log.debug("new ButtonTrigger " + bt.getName() + " type " + btype.toString()); 171 switch(btype) { 172 case TOGGLE: 173 this.getButton().addActionListener(bt); 174 break; 175 case MOMENTARY: 176 default: 177 this.getButton().addMouseListener(bt); 178 // Just send the trigger a click. 179 } 180 return bt; // cast OK since we just instantiated it up above. 181 */ 182 return null; // cast OK since we just instantiated it up above. 183 } 184 185 public Element getXml() { 186 Element me = new Element("SoundEvent"); 187 me.setAttribute("name", name); 188 me.setAttribute("label", me.getText()); 189 for (Trigger t : trigger_list.values()) { 190 me.addContent(t.getXml()); 191 } 192 193 return me; 194 } 195 196 public void setXml(Element el) { 197 this.setXml(el, null); 198 } 199 200 protected void addXmlTrigger(Element te, VSDFile vf) { 201 String tts; 202 Trigger.TriggerType tt; 203 if ((tts = te.getAttributeValue("type")) != null) { 204 tt = Trigger.TriggerType.valueOf(tts.toUpperCase()); 205 } else { 206 tt = Trigger.TriggerType.NONE; 207 } 208 209 switch (tt) { 210 case BUTTON: 211 if (this.buttontype != SoundEvent.ButtonType.NONE) { 212 t = setupButtonAction(te); 213 } 214 break; 215 case BOOLEAN: 216 t = new BoolTrigger(te.getAttributeValue("name")); 217 break; 218 case FLOAT: 219 t = new FloatTrigger(te.getAttributeValue("name"), 0.0f, Trigger.CompareType.EQ); 220 break; 221 case NOTCH: 222 t = new NotchTrigger(te.getAttributeValue("name")); 223 break; 224 case INT: 225 t = new IntTrigger(te.getAttributeValue("name")); 226 break; 227 case STRING: 228 //t = new StringTrigger(el.getAttributeValue("name")); 229 log.warn("Don't have StringTriggers yet..."); 230 t = null; 231 return; 232 case THROTTLE: 233 t = new ThrottleTrigger(te.getAttributeValue("name")); 234 break; 235 case NONE: 236 default: 237 break; 238 } 239 240 log.debug("Building trigger {}", t.getName()); 241 t.setXml(te); 242 trigger_list.put(te.getAttributeValue("name"), t); 243 //log.debug("target name: {}, sound: {}", t.getTargetName(), parent.getSound(t.getTargetName())); 244 t.setTarget(parent.getSound(t.getTargetName())); 245 //log.debug("target: {}", t.getTarget()); 246 247 if (t.getTarget() == null) { 248 // If the target is missing, set up a do-nothing operation. 249 // Protects against errors in the XML file. 250 // Should probably post a warning, though. 251 t.setTargetAction(Trigger.TargetAction.NOTHING); 252 } 253 switch (t.getTargetAction()) { 254 case PLAY: 255 case FADEIN: 256 //log.debug("PLAY"); 257 t.setCallback(new TriggerListener() { 258 @Override 259 public void takeAction() { 260 t.getTarget().play(); 261 } 262 263 @Override 264 public void takeAction(int i) { 265 } 266 267 @Override 268 public void takeAction(float f) { 269 } // do nothing 270 }); 271 break; 272 case LOOP: 273 //log.debug("LOOP"); 274 t.setCallback(new TriggerListener() { 275 @Override 276 public void takeAction() { 277 t.getTarget().loop(); 278 } 279 280 @Override 281 public void takeAction(int i) { 282 } 283 284 @Override 285 public void takeAction(float f) { 286 } // do nothing 287 }); 288 break; 289 case STOP: 290 case FADEOUT: 291 //log.debug("STOP"); 292 t.setCallback(new TriggerListener() { 293 @Override 294 public void takeAction() { 295 t.getTarget().stop(); 296 } 297 298 @Override 299 public void takeAction(int i) { 300 } 301 302 @Override 303 public void takeAction(float f) { 304 } // do nothing 305 }); 306 break; 307 case NOTCH: 308 //log.debug("NOTCH"); 309 log.debug("making callback t {} target {}", t, t.getTarget()); 310 t.setCallback(new TriggerListener() { 311 @Override 312 public void takeAction(int i) { 313 //log.debug("Notch Trigger Listener. t = " + t + " Target = " + t.getTarget() + " notch = " + i); 314 t.getTarget().changeNotch(i); 315 } 316 317 @Override 318 public void takeAction() { 319 } 320 321 @Override 322 public void takeAction(float f) { 323 } // do nothing 324 }); 325 break; 326 case CHANGE: 327 //log.debug("CHANGE"); 328 log.debug("making callback t {} target {}", t, t.getTarget()); 329 t.setCallback(new TriggerListener() { 330 @Override 331 public void takeAction() { 332 } // do nothing 333 334 @Override 335 public void takeAction(int i) { 336 } // do nothing 337 338 @Override 339 public void takeAction(float f) { 340 //log.debug("Throttle Trigger Listener. t = " + t + " Target = " + t.getTarget() + " value = " + f); 341 t.getTarget().changeThrottle(f); 342 } 343 }); 344 break; 345 case NOTHING: 346 case STOP_AT_ZERO: 347 // Used for when the target sound is missing. 348 //log.debug("NOTHING"); 349 t.setCallback(new TriggerListener() { 350 @Override 351 public void takeAction() { 352 } // do nothing 353 354 @Override 355 public void takeAction(int i) { 356 } // do nothing 357 358 @Override 359 public void takeAction(float f) { 360 } // do nothing 361 }); 362 break; 363 default: 364 // do nothing. 365 break; 366 } // end switch 367 } // end function 368 369 public void setXml(Element el, VSDFile vf) { 370 Element te; 371 String btv; 372 373 // Get the SoundEvent's name. 374 name = el.getAttributeValue("name"); 375 if ((btv = el.getAttributeValue("buttontype")) != null) { 376 buttontype = SoundEvent.ButtonType.valueOf(btv.toUpperCase()); 377 } else { 378 buttontype = SoundEvent.ButtonType.NONE; 379 } 380 381 // Get the SoundEvent's Triggers and set them up. 382 Iterator<Element> itr = (el.getChildren("trigger")).iterator(); 383 while (itr.hasNext()) { 384 te = itr.next(); 385 this.addXmlTrigger(te, vf); 386 } // end while 387 388 } // end setXml() 389 390 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SoundEvent.class); 391 392}