001package jmri.jmrit.symbolicprog; 002 003import java.awt.event.ActionEvent; 004import java.awt.event.ActionListener; 005import java.awt.event.FocusEvent; 006import java.awt.event.FocusListener; 007import java.util.ResourceBundle; 008import javax.swing.BoxLayout; 009import javax.swing.JLabel; 010import javax.swing.JPanel; 011import javax.swing.JTextField; 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015/** 016 * Provide a graphical representation of the DCC address, either long or short 017 * 018 * <p> 019 * Expects one or more of the variables called: 020 * <ul> 021 * <li>Short Address 022 * <li>Long Address 023 * <li>Address Format (an Enum variable to select) 024 * </ul> 025 * and handles the cases where: 026 * <ul> 027 * <li>All three are present - the normal advanced decoder case 028 * <li>Short Address is present and Long Address is not 029 * <li>Long Address is present and Short Address is not 030 * </ul> 031 * At least one of Short Address and Long Address must be present! 032 * 033 * @author Bob Jacobsen Copyright (C) 2001, 2012 034 */ 035public class DccAddressPanel extends JPanel { 036 037 JTextField val = new JTextField(6); 038 039 VariableValue primaryAddr = null; 040 VariableValue extendAddr = null; 041 EnumVariableValue addMode = null; 042 043 VariableTableModel variableModel = null; 044 045 /** 046 * Ctor using default label for the address. 047 * 048 * @param mod The current table of variables, used to locate the status 049 * information needed. 050 */ 051 public DccAddressPanel(VariableTableModel mod) { 052 this(mod, ResourceBundle.getBundle("jmri.jmrit.symbolicprog.SymbolicProgBundle").getString("TextDccAddress")); 053 } 054 055 public DccAddressPanel(VariableTableModel mod, String label) { 056 variableModel = mod; 057 058 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 059 060 // arrange for the field to be updated when any of the variables change 061 java.beans.PropertyChangeListener dccNews = new java.beans.PropertyChangeListener() { 062 @Override 063 public void propertyChange(java.beans.PropertyChangeEvent e) { 064 updateDccAddress(); 065 } 066 }; 067 068 // connect to variables 069 primaryAddr = variableModel.findVar("Short Address"); 070 if (primaryAddr == null) { 071 log.debug("DCC Address monitor did not find a Short Address variable"); 072 } else { 073 primaryAddr.addPropertyChangeListener(dccNews); 074 } 075 076 extendAddr = variableModel.findVar("Long Address"); 077 if (extendAddr == null) { 078 log.debug("DCC Address monitor did not find an Long Address variable"); 079 } else { 080 extendAddr.addPropertyChangeListener(dccNews); 081 } 082 083 addMode = (EnumVariableValue) variableModel.findVar("Address Format"); 084 if (addMode == null) { 085 log.debug("DCC Address monitor didnt find an Address Format variable"); 086 } else { 087 addMode.addPropertyChangeListener(dccNews); 088 } 089 090 // show the selection 091 if (addMode != null) { 092 add(addMode.getNewRep("radiobuttons")); 093 } 094 095 // show address field 096 add(new JLabel(label)); 097 val.setToolTipText(ResourceBundle.getBundle("jmri.jmrit.symbolicprog.SymbolicProgBundle").getString("ToolTipDccAddress")); 098 add(val); 099 100 new DccAddressVarHandler(primaryAddr, extendAddr, addMode) { 101 @Override 102 protected void doPrimary() { 103 // short address commonRep will be JTextField if variable, JLabel if constant 104 JTextField f; 105 if (primaryAddr.getCommonRep() instanceof JTextField) { 106 f = (JTextField) primaryAddr.getCommonRep(); 107 } else { 108 f = new JTextField(); 109 f.setText(((JLabel) primaryAddr.getCommonRep()).getText()); 110 } 111 val.setBackground(primaryAddr.getCommonRep().getBackground()); 112 val.setDocument(f.getDocument()); 113 } 114 115 @Override 116 protected void doExtended() { 117 // long address commonRep will be JTextField if variable, JLabel if constant 118 JTextField f; 119 if (extendAddr.getCommonRep() instanceof JTextField) { 120 f = (JTextField) extendAddr.getCommonRep(); 121 } else { 122 f = new JTextField(); 123 f.setText(((JLabel) extendAddr.getCommonRep()).getText()); 124 } 125 val.setBackground(extendAddr.getCommonRep().getBackground()); 126 val.setDocument(f.getDocument()); 127 } 128 }; 129 130 // start listening for changes to this value 131 val.addActionListener(new ActionListener() { 132 @Override 133 public void actionPerformed(ActionEvent e) { 134 new DccAddressVarHandler(primaryAddr, extendAddr, addMode) { 135 @Override 136 protected void doPrimary() { 137 // short address mode 138 primaryAddr.updatedTextField(); 139 val.setBackground(primaryAddr.getCommonRep().getBackground()); 140 if (log.isDebugEnabled()) { 141 log.debug("set color: {}", primaryAddr.getCommonRep().getBackground()); 142 } 143 } 144 145 @Override 146 protected void doExtended() { 147 // long address 148 extendAddr.updatedTextField(); 149 val.setBackground(extendAddr.getCommonRep().getBackground()); 150 if (log.isDebugEnabled()) { 151 log.debug("set color: {}", extendAddr.getCommonRep().getBackground()); 152 } 153 } 154 }; 155 } 156 }); 157 val.addFocusListener(new FocusListener() { 158 @Override 159 public void focusGained(FocusEvent e) { 160 if (log.isDebugEnabled()) { 161 log.debug("focusGained"); 162 } 163 enterField(); 164 } 165 166 @Override 167 public void focusLost(FocusEvent e) { 168 if (log.isDebugEnabled()) { 169 log.debug("focusLost"); 170 } 171 exitField(); 172 } 173 }); 174 175 } 176 177 String oldContents = ""; 178 179 /** 180 * Handle focus entering the address field by recording the contents. 181 */ 182 void enterField() { 183 oldContents = val.getText(); 184 } 185 186 /** 187 * Handle focus leaving the address field by checking to see if the contents 188 * changed. We do this because we want to record that change even if it 189 * hasn't been "entered" via return key et al. 190 */ 191 void exitField() { 192 if (!oldContents.equals(val.getText())) { 193 new DccAddressVarHandler(primaryAddr, extendAddr, addMode) { 194 @Override 195 protected void doPrimary() { 196 // short address mode 197 primaryAddr.updatedTextField(); 198 val.setBackground(primaryAddr.getCommonRep().getBackground()); 199 if (log.isDebugEnabled()) { 200 log.debug("set color: {}", primaryAddr.getCommonRep().getBackground()); 201 } 202 } 203 204 @Override 205 protected void doExtended() { 206 // long address 207 extendAddr.updatedTextField(); 208 val.setBackground(extendAddr.getCommonRep().getBackground()); 209 if (log.isDebugEnabled()) { 210 log.debug("set color: {}", extendAddr.getCommonRep().getBackground()); 211 } 212 } 213 }; 214 } 215 } 216 217 /** 218 * Handle a (possible) update to the active DCC address, either because the 219 * state changed or the address mode changed. Note that value changes of the 220 * active address are directly reflected, so we don't have to do anything on 221 * those, but we still go ahead and update the state color. 222 */ 223 void updateDccAddress() { 224 if (log.isDebugEnabled()) { 225 log.debug("updateDccAddress: short {} long {} mode {}", primaryAddr == null ? "<null>" : primaryAddr.getValueString(), extendAddr == null ? "<null>" : extendAddr.getValueString(), addMode == null ? "<null>" : addMode.getValueString()); 226 } 227 new DccAddressVarHandler(primaryAddr, extendAddr, addMode) { 228 @Override 229 protected void doPrimary() { 230 // short address commonRep will be JTextField if variable, JLabel if constant 231 JTextField f; 232 if (primaryAddr.getCommonRep() instanceof JTextField) { 233 f = (JTextField) primaryAddr.getCommonRep(); 234 } else { 235 f = new JTextField(); 236 f.setText(((JLabel) primaryAddr.getCommonRep()).getText()); 237 } 238 val.setBackground(primaryAddr.getCommonRep().getBackground()); 239 val.setDocument(f.getDocument()); 240 if (log.isDebugEnabled()) { 241 log.debug("set color: {}", primaryAddr.getCommonRep().getBackground()); 242 } 243 } 244 245 @Override 246 protected void doExtended() { 247 // long address commonRep will be JTextField if variable, JLabel if constant 248 JTextField f; 249 if (extendAddr.getCommonRep() instanceof JTextField) { 250 f = (JTextField) extendAddr.getCommonRep(); 251 } else { 252 f = new JTextField(); 253 f.setText(((JLabel) extendAddr.getCommonRep()).getText()); 254 } 255 val.setBackground(extendAddr.getCommonRep().getBackground()); 256 val.setDocument(f.getDocument()); 257 if (log.isDebugEnabled()) { 258 log.debug("set color: {}", extendAddr.getCommonRep().getBackground()); 259 } 260 } 261 }; 262 } 263 264 // initialize logging 265 private final static Logger log = LoggerFactory.getLogger(DccAddressPanel.class); 266 267}