001package jmri.jmrix.loconet.ds64; 002import java.awt.FlowLayout; 003import javax.swing.BoxLayout; 004import javax.swing.ButtonGroup; 005import javax.swing.JLabel; 006import javax.swing.JPanel; 007import javax.swing.JRadioButton; 008import jmri.util.swing.ValidatedTextField; 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012/** 013 * Provides a swing object, for use by the Ds64TabbedPanel tool, which allows 014 * display and configuration of turnout number and position. 015 * <p> 016 * Turnout numbering is the same as seen on a Digitrax throttle display; Tools 017 * using values from objects of this type must provide the appropriate transform 018 * to create turnout numbering which is suitable for use within LocoNet messaging. 019 * 020 * @author B. Milhaupt Copyright (C) 2011, 2012, 2013, 2014, 2015, 2017 021 */ 022public class SimpleTurnoutStateEntry extends SimpleTurnout { 023 private JPanel entryPanel = null; 024 025 /** 026 * Tracks the "user-friendly" turnout address. 027 * <p> 028 * Turnout numbering is the same as seen on a Digitrax throttle display; Tools 029 * using values from objects of this type must provide the appropriate transform 030 * to create turnout numbering which is suitable for use within LocoNet messaging. 031 */ 032 public ValidatedTextField addressField = null; 033 034 /** 035 * Tracks whether the associated turnout is "thrown". 036 */ 037 public JRadioButton thrownRadioButton; 038 039 /** 040 * Tracks whether the associated turnout is "closed". 041 */ 042 public JRadioButton closedRadioButton; 043 044 /** 045 * Tracks whether the object is in-use or not, as seen in some aspects of 046 * DS64 configuration. 047 */ 048 public JRadioButton unusedRadioButton; 049 050 /** 051 * Constructor used when the current address and position are not known. It 052 * is assumed that the turnout address is 1, that the turnout is "closed", and 053 * that the turnout is "valid". 054 * <p> 055 * Turnout numbering is the same as seen on a Digitrax throttle display; Tools 056 * using values from objects of this type must provide the appropriate transform 057 * to create turnout numbering which is suitable for use within LocoNet messaging. 058 */ 059 public SimpleTurnoutStateEntry() { 060 this(1,true); 061 } 062 063 /** 064 * Constructor used when the current address and position are known. Turnout 065 * "validity" is assumed to be "valid". 066 * <p> 067 * Turnout numbering is the same as seen on a Digitrax throttle display; Tools 068 * using values from objects of this type must provide the appropriate transform 069 * to create turnout numbering which is suitable for use within LocoNet messaging. 070 * 071 * @param address turnout address 072 * @param isClosed true if turnout is closed, else false 073 */ 074 public SimpleTurnoutStateEntry(Integer address, boolean isClosed) { 075 super(address,isClosed); 076 thrownRadioButton = new JRadioButton(Bundle.getMessage("TurnoutStateThrown")); 077 closedRadioButton = new JRadioButton(Bundle.getMessage("TurnoutStateClosed")); 078 unusedRadioButton = null; 079 addressField = new ValidatedTextField(5, true, 1, 2048, Bundle.getMessage("ErrorTextAddressInvalid")); 080 entryPanel = null; 081 addressField.setText(Integer.toString(address)); 082 setAddressLastQueriedValue(address); 083 if (isClosed == true) { 084 thrownRadioButton.setSelected(false); 085 closedRadioButton.setSelected(true); 086 } 087 else { 088 thrownRadioButton.setSelected(true); 089 closedRadioButton.setSelected(false); 090 } 091 thrownRadioButton.addFocusListener(new java.awt.event.FocusListener() { 092 093 @Override 094 public void focusGained(java.awt.event.FocusEvent e) { 095 // eat this focus change event. 096 } 097 098 @Override 099 public void focusLost(java.awt.event.FocusEvent e) { 100 if (thrownRadioButton.isSelected()) { 101 setIsClosed(false); 102 } 103 } 104 }); 105 106 closedRadioButton.addFocusListener(new java.awt.event.FocusListener() { 107 108 @Override 109 public void focusGained(java.awt.event.FocusEvent e) { 110 // eat this focus change event. 111 } 112 113 @Override 114 public void focusLost(java.awt.event.FocusEvent e) { 115 if (closedRadioButton.isSelected()) { 116 setIsClosed(true); 117 } 118 } 119 }); 120 } 121 122 /** 123 * Constructor used when the current address, position, and "validity" 124 * state are known. 125 * <p> 126 * Turnout numbering is the same as seen on a Digitrax throttle display; Tools 127 * using values from objects of this type must provide the appropriate transform 128 * to create turnout numbering which is suitable for use within LocoNet messaging. 129 * 130 * @param address turnout address 131 * @param closed true if turnout is closed, else false 132 * @param unused true if turnout is unused, else false 133 */ 134 public SimpleTurnoutStateEntry(Integer address, boolean closed, boolean unused) { 135 super(address, closed, unused); 136 thrownRadioButton = new JRadioButton(Bundle.getMessage("TurnoutStateThrown")); 137 closedRadioButton = new JRadioButton(Bundle.getMessage("TurnoutStateClosed")); 138 unusedRadioButton = new JRadioButton(Bundle.getMessage("RadioButtonTextUnused")); 139 addressField = new ValidatedTextField(5, true, 1, 2048, Bundle.getMessage("ErrorTextAddressInvalid")); 140 entryPanel = null; 141 if (unused) { 142 addressField.setText(""); 143 } else { 144 addressField.setText(Integer.toString(address)); 145 } 146 setAddressLastQueriedValue(address); 147 if (closed == true) { 148 thrownRadioButton.setSelected(false); 149 unusedRadioButton.setSelected(false); 150 closedRadioButton.setSelected(true); 151 } 152 else { 153 thrownRadioButton.setSelected(true); 154 unusedRadioButton.setSelected(false); 155 closedRadioButton.setSelected(false); 156 } 157 158 thrownRadioButton.addFocusListener(new java.awt.event.FocusListener() { 159 @Override 160 public void focusGained(java.awt.event.FocusEvent e) { 161 // eat this focus change event. 162 } 163 164 @Override 165 public void focusLost(java.awt.event.FocusEvent e) { 166 if (thrownRadioButton.isSelected()) { 167 setIsClosed(false); 168 } 169 } 170 }); 171 172 closedRadioButton.addFocusListener(new java.awt.event.FocusListener() { 173 @Override 174 public void focusGained(java.awt.event.FocusEvent e) { 175 // eat this focus change event. 176 } 177 178 @Override 179 public void focusLost(java.awt.event.FocusEvent e) { 180 if (closedRadioButton.isSelected()) { 181 setIsClosed(true); 182 } 183 } 184 }); 185 186 unusedRadioButton.addFocusListener(new java.awt.event.FocusListener() { 187 @Override 188 public void focusGained(java.awt.event.FocusEvent e) { 189 // eat this focus change event. 190 } 191 192 @Override 193 public void focusLost(java.awt.event.FocusEvent e) { 194 if (unusedRadioButton.isSelected()) { 195 setIsUnused(); 196 addressField.setText(""); 197 } 198 } 199 }); 200 201 } 202 203 /** 204 * 205 * @return the JPanel related to this object 206 */ 207 public JPanel getEntryPanel() { return this.entryPanel; } 208 209 /** 210 * Creates a GUI Panel for managing the address and position of a turnout, 211 * as used in configuring the turnout address of a DS64 output. 212 * 213 * @param label a text string to be displayed in the JPanel with the turnout 214 * address and position 215 * @return a JPanel containing the label, the turnout address text field, and 216 * position GUI elements 217 */ 218 public JPanel createEntryPanel(String label) { 219 entryPanel = new JPanel(); 220 entryPanel.setLayout(new FlowLayout()); 221 entryPanel.add(new JLabel(label)); 222 entryPanel.add(addressField); 223 224 JPanel p2 = new JPanel(); 225 p2.setLayout(new BoxLayout(p2,BoxLayout.X_AXIS)); 226 ButtonGroup g = new ButtonGroup(); 227 228 if (addressField.getText().length() == 0) { 229 closedRadioButton.setSelected(false); 230 thrownRadioButton.setSelected(false); 231 if (unusedRadioButton != null) { 232 unusedRadioButton.setSelected(true); 233 } 234 addressField.setText(""); 235 } else if (Integer.parseInt(addressField.getText()) == 2048) { 236 closedRadioButton.setSelected(false); 237 thrownRadioButton.setSelected(false); 238 if (unusedRadioButton != null) { 239 unusedRadioButton.setSelected(true); 240 } 241 addressField.setText(""); 242 } 243 else { 244 if (unusedRadioButton != null) { 245 unusedRadioButton.setSelected(false); 246 } 247 closedRadioButton.setSelected(getIsClosed()); 248 thrownRadioButton.setSelected(!getIsClosed()); 249 } 250 251 g.add(thrownRadioButton); 252 g.add(closedRadioButton); 253 p2.add(thrownRadioButton); 254 p2.add(closedRadioButton); 255 if (unusedRadioButton != null) { 256 g.add(unusedRadioButton); 257 p2.add(unusedRadioButton); 258 } 259 entryPanel.add(p2); 260 return entryPanel; 261 } 262 263 /** 264 * Retrieve the GUI element which holds a turnout address 265 * @return turnout address 266 */ 267 public ValidatedTextField getAddressField() { 268 return addressField; 269 } 270 271 @Override 272 public void setAddress(Integer addr) { 273 log.debug("simpleturnoutstateentry - setaddress {}", addr); 274 super.setAddress(addr); 275 if (isValid()) { 276 addressField.setText(String.valueOf(addr)); 277 } 278 else { 279 addressField.setText(""); 280 } 281 addressField.updateUI(); 282 } 283 284 /** 285 * Establish the most recent value known to be found in the hardware. 286 * Value is used to help determine colorization of the swing GUI text field. 287 * 288 * @param addr Turnout address 289 */ 290 final public void setAddressLastQueriedValue(Integer addr) { 291 addressField.setLastQueriedValue(String.valueOf(addr)); 292 } 293 294 @Override 295 public void setIsClosed(boolean isclosed) { 296 super.setIsClosed(isclosed); 297 closedRadioButton.setSelected(getIsClosed()); 298 thrownRadioButton.setSelected(!getIsClosed()); 299 closedRadioButton.updateUI(); 300 thrownRadioButton.updateUI(); 301 if (unusedRadioButton != null) { 302 unusedRadioButton.setSelected(false); 303 unusedRadioButton.updateUI(); 304 } 305 } 306 307 private final static Logger log = LoggerFactory.getLogger(SimpleTurnoutStateEntry.class); 308 309}