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 if (addressPanel != null && addressPanel.getRosterEntry() != null && useSpeedProfile) { 142 return (addressPanel.getRosterEntry().getSpeedProfile().convertThrottleSettingToScaleSpeedWithUnits(throttleVolume, isForward)); 143 } else { 144 return (Bundle.getMessage("ThrottleSpeedPanelError")); 145 } 146 147 } 148 149 @Override 150 public void notifyAddressChosen(LocoAddress l) { 151 } 152 153 @Override 154 public void notifyNewRosterEntryHighlighted(RosterEntry re) { 155 } 156 157 @Override 158 public void notifyRosterEntryUpdated(RosterEntry re) { 159 useSpeedProfile = false; //posit false 160 if (re != null 161 && re.getSpeedProfile() != null 162 && re.getSpeedProfile().getProfileSize() > 0) { 163 useSpeedProfile = true; 164 } 165 updateSpeedLabel(useSpeedProfile, throttle.getSpeedSetting(), throttle.getIsForward()); 166 } 167 168 @Override 169 public void notifyAddressReleased(LocoAddress la) { 170 if (throttle == null) { 171 log.debug("notifyAddressReleased() throttle alreaday null, called for loc {}",la); 172 return; 173 } 174 this.setEnabled(false); 175 throttle.removePropertyChangeListener(this); 176 throttle = null; 177 updateSpeedLabel(useSpeedProfile, 0, true); 178 } 179 180 @Override 181 public void notifyAddressThrottleFound(DccThrottle t) { 182 if (log.isDebugEnabled()) { 183 log.debug("control panel received new throttle {}",t); 184 } 185 this.throttle = t; 186 this.throttle.addPropertyChangeListener(this); 187 if (log.isDebugEnabled()) { 188 jmri.DccLocoAddress Address = (jmri.DccLocoAddress) throttle.getLocoAddress(); 189 log.debug("new address is {}", Address.toString()); 190 } 191 notifyRosterEntryUpdated(addressPanel.getRosterEntry()); 192 } 193 194 @Override 195 public void notifyConsistAddressChosen(LocoAddress l) { 196 notifyAddressChosen(l); 197 } 198 199 @Override 200 public void notifyConsistAddressReleased(LocoAddress l) { 201 notifyAddressReleased(l); 202 } 203 204 @Override 205 public void notifyConsistAddressThrottleFound(DccThrottle throttle) { 206 if (log.isDebugEnabled()) { 207 log.debug("control panel received consist throttle"); 208 } 209 notifyAddressThrottleFound(throttle); 210 } 211 212 public Element getXml() { 213 Element me = new Element("SpeedPanel"); // NOI18N 214 // put nothing 215 return me; 216 } 217 218 public void setXml(Element e) { 219 // do nothing 220 } 221 222 // initialize logging 223 private static final Logger log = LoggerFactory.getLogger(SpeedPanel.class); 224}