001package jmri.jmrit.throttle; 002 003import java.awt.BorderLayout; 004import java.awt.Font; 005import javax.swing.BoxLayout; 006import javax.swing.JInternalFrame; 007import javax.swing.JLabel; 008import javax.swing.JPanel; 009import javax.swing.WindowConstants; 010import jmri.DccThrottle; 011import jmri.LocoAddress; 012import jmri.Throttle; 013import jmri.jmrit.roster.RosterEntry; 014import org.jdom2.Element; 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017 018/** 019 * A JInternalFrame that contains a label to display scale speed if available 020 * for forward, reverse and STOP. TODO: fix speed increments (14, 28) 021 * 022 * @author glen Copyright (C) 2002 023 * @author Bob Jacobsen Copyright (C) 2007 024 * @author Ken Cameron Copyright (C) 2008 025 * @author Steve Gigiel Copyright (C) 2017 026 */ 027public class SpeedPanel extends JInternalFrame implements java.beans.PropertyChangeListener, AddressListener { 028 029 private DccThrottle throttle; 030 031 private JPanel mainPanel; 032 033 private JPanel speedDisplayPanel; 034 035 private JLabel scaleSpeedLabel = new JLabel("", JLabel.CENTER); 036 037 // tracks whether we are using speed profiles 038 private boolean useSpeedProfile = false; 039 040 // last known direction 041 private boolean currentIsForward = true; 042 private float currentThrottleVol = 0.0f; 043 044 //for access to roster entry 045 private AddressPanel addressPanel; //for access to roster entry 046 047 /** 048 * Constructor. 049 */ 050 public SpeedPanel() { 051 initGUI(); 052 } 053 054 /** 055 * Set the AddressPanel this throttle control is listening for new throttle 056 * event 057 * 058 * @param addressPanel reference to the addresspanel 059 */ 060 public void setAddressPanel(AddressPanel addressPanel) { 061 this.addressPanel = addressPanel; 062 } 063 064 /** 065 * "Destructor" 066 */ 067 public void destroy() { 068 if (addressPanel != null) { 069 addressPanel.removeAddressListener(this); 070 addressPanel = null; 071 } 072 if (throttle != null) { 073 throttle.removePropertyChangeListener(this); 074 throttle = null; 075 } 076 } 077 078 /** 079 * Create, initialize and place GUI components. 080 */ 081 private void initGUI() { 082 083 mainPanel = new JPanel(); 084 this.setContentPane(mainPanel); 085 mainPanel.setLayout(new BorderLayout()); 086 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 087 088 speedDisplayPanel = new JPanel(); 089 speedDisplayPanel.setFont(new Font("", Font.PLAIN, 32)); 090 speedDisplayPanel.setLayout(new BoxLayout(speedDisplayPanel, BoxLayout.X_AXIS)); 091 speedDisplayPanel.setOpaque(false); 092 mainPanel.add(speedDisplayPanel, BorderLayout.CENTER); 093 094 speedDisplayPanel.add(scaleSpeedLabel); 095 096 } 097 098 /** 099 * update the state of this panel if direction or speed change 100 */ 101 @Override 102 public void propertyChange(java.beans.PropertyChangeEvent e) { 103 if (e.getPropertyName().equals(Throttle.SPEEDSETTING)) { 104 currentThrottleVol = ((Float) e.getNewValue()).floatValue(); 105 scaleSpeedLabel.setText(updateSpeedLabel(useSpeedProfile, currentThrottleVol, currentIsForward)); 106 } else if (e.getPropertyName().equals(Throttle.ISFORWARD)) { 107 currentIsForward = (boolean) e.getNewValue(); 108 scaleSpeedLabel.setText(updateSpeedLabel(useSpeedProfile, currentThrottleVol, currentIsForward)); 109 } 110 if (log.isDebugEnabled()) { 111 log.debug("Property change event received {} / {}", e.getPropertyName(), e.getNewValue()); 112 } 113 } 114 115 /** 116 * 117 * @param useSpeedProfile are we using speed profile 118 * @param throttleVolume throttle position (percent of 1) 119 * @param isForward true if going forward. 120 * @return a string for displaying speed if available 121 */ 122 private String updateSpeedLabel(boolean useSpeedProfile, float throttleVolume, boolean isForward) { 123 RosterEntry re = addressPanel.getRosterEntry(); 124 if (re != null && useSpeedProfile) { 125 return (re.getSpeedProfile().convertThrottleSettingToScaleSpeedWithUnits(throttleVolume, isForward)); 126 } else { 127 return (Bundle.getMessage("ThrottleSpeedPanelError")); 128 } 129 130 } 131 132 @Override 133 public void notifyAddressChosen(LocoAddress l) { 134 } 135 136 @Override 137 public void notifyAddressReleased(LocoAddress la) { 138 if (throttle == null) { 139 log.debug("notifyAddressReleased() throttle alreaday null, called for loc {}",la); 140 return; 141 } 142 this.setEnabled(false); 143 throttle.removePropertyChangeListener(this); 144 throttle = null; 145 } 146 147 @Override 148 public void notifyAddressThrottleFound(DccThrottle t) { 149 if (throttle != null) { 150 log.debug("notifyAddressThrottleFound() throttle non null, called for loc {}",t.getLocoAddress()); 151 return; 152 } 153 if (log.isDebugEnabled()) { 154 log.debug("control panel received new throttle {}",t); 155 } 156 this.throttle = t; 157 158 this.throttle.addPropertyChangeListener(this); 159 if (log.isDebugEnabled()) { 160 jmri.DccLocoAddress Address = (jmri.DccLocoAddress) throttle.getLocoAddress(); 161 log.debug("new address is {}", Address.toString()); 162 } 163 164 useSpeedProfile = false; //posit false 165 RosterEntry re = addressPanel.getRosterEntry(); 166 if (re != null 167 && re.getSpeedProfile() != null 168 && re.getSpeedProfile().getProfileSize() > 0) { 169 useSpeedProfile = true; 170 } 171 } 172 173 @Override 174 public void notifyConsistAddressChosen(LocoAddress l) { 175 notifyAddressChosen(l); 176 } 177 178 @Override 179 public void notifyConsistAddressReleased(LocoAddress l) { 180 notifyAddressReleased(l); 181 } 182 183 @Override 184 public void notifyConsistAddressThrottleFound(DccThrottle throttle) { 185 if (log.isDebugEnabled()) { 186 log.debug("control panel received consist throttle"); 187 } 188 notifyAddressThrottleFound(throttle); 189 } 190 191 /** 192 * Collect the prefs of this object into XML Element Just Positional Data 193 * <ul> 194 * <li> Window prefs 195 * </ul> 196 * 197 * 198 * @return the XML of this object. 199 */ 200 public Element getXml() { 201 Element me = new Element("SpeedPanel"); 202 java.util.ArrayList<Element> children = new java.util.ArrayList<Element>(1); 203 children.add(WindowPreferences.getPreferences(this)); 204 me.setContent(children); 205 return me; 206 } 207 208 /** 209 * Set the preferences based on the XML Element. Just positional data 210 * <ul> 211 * <li> Window prefs 212 * </ul> 213 * 214 * 215 * @param e The Element for this object. 216 */ 217 public void setXml(Element e) { 218 Element window = e.getChild("window"); 219 WindowPreferences.setPreferences(this, window); 220 } 221 222 // initialize logging 223 private final static Logger log = LoggerFactory.getLogger(SpeedPanel.class); 224}