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