001package jmri.jmrit.simplelightctrl; 002 003import java.awt.event.ActionEvent; 004import java.awt.event.ActionListener; 005import java.beans.PropertyChangeListener; 006import java.text.DecimalFormat; 007 008import javax.swing.BoxLayout; 009import javax.swing.JPanel; 010 011import jmri.*; 012import jmri.swing.NamedBeanComboBox; 013 014import org.slf4j.Logger; 015import org.slf4j.LoggerFactory; 016 017/** 018 * Frame controlling a single light. 019 * <p> 020 * Built from a copy of simple turnout control. 021 * 022 * @author Ken Cameron Copyright (C) 2008 023 * @author Bob Jacobsen Copyright (C) 2001, 2008 024 */ 025public class SimpleLightCtrlFrame extends jmri.util.JmriJFrame { 026 027 DecimalFormat threeDigits = new DecimalFormat("000"); 028 DecimalFormat oneDigits = new DecimalFormat("0"); 029 DecimalFormat oneDotTwoDigits = new DecimalFormat("0.00"); 030 031 Light light = null; 032 String newState = ""; 033 034 // GUI member declarations 035 javax.swing.JButton onButton = new javax.swing.JButton(); 036 javax.swing.JButton offButton = new javax.swing.JButton(); 037 038 javax.swing.JLabel textStateLabel = new javax.swing.JLabel(); 039 javax.swing.JLabel nowStateTextField = new javax.swing.JLabel(); 040 javax.swing.JLabel nowControllersTextField = new javax.swing.JLabel(); 041 javax.swing.JLabel textIsEnabledLabel = new javax.swing.JLabel(); 042 javax.swing.JCheckBox statusIsEnabledCheckBox = new javax.swing.JCheckBox(); 043 javax.swing.JLabel textIsVariableLabel = new javax.swing.JLabel(); 044 javax.swing.JCheckBox statusIsVariableCheckBox = new javax.swing.JCheckBox(); 045 javax.swing.JLabel textIsTransitionLabel = new javax.swing.JLabel(); 046 javax.swing.JCheckBox statusIsTransitionCheckBox = new javax.swing.JCheckBox(); 047 048 javax.swing.JLabel intensityTextLabel1 = new javax.swing.JLabel(); 049 javax.swing.JLabel nowIntensityLabel = new javax.swing.JLabel(); 050 javax.swing.JTextField intensityTextField = new javax.swing.JTextField(4); 051 javax.swing.JLabel intensityTextLabel2 = new javax.swing.JLabel(); 052 javax.swing.JButton intensityButton = new javax.swing.JButton(); 053 054 javax.swing.JLabel intensityMinTextLabel = new javax.swing.JLabel(); 055 javax.swing.JLabel nowIntensityMinLabel = new javax.swing.JLabel(); 056 javax.swing.JTextField intensityMinTextField = new javax.swing.JTextField(4); 057 javax.swing.JLabel intensityMaxTextLabel = new javax.swing.JLabel(); 058 javax.swing.JLabel nowIntensityMaxLabel = new javax.swing.JLabel(); 059 javax.swing.JTextField intensityMaxTextField = new javax.swing.JTextField(4); 060 javax.swing.JLabel transitionTimeTextLabel = new javax.swing.JLabel(); 061 javax.swing.JLabel nowTransitionTimeLabel = new javax.swing.JLabel(); 062 javax.swing.JTextField transitionTimeTextField = new javax.swing.JTextField(4); 063 064 javax.swing.JButton applyButton = new javax.swing.JButton(); 065 private final NamedBeanComboBox<Light> to1; 066 private PropertyChangeListener _parentLightListener = null; 067 068 public SimpleLightCtrlFrame() { 069 super(); 070 071 to1 = new NamedBeanComboBox<>(InstanceManager.lightManagerInstance()); 072 to1.setAllowNull(true); 073 to1.addActionListener(new ActionListener() { 074 @Override 075 public void actionPerformed(ActionEvent e) { 076 log.debug("actionevent"); 077 resetLightToCombo(); 078 } 079 }); 080 081 // configure items for GUI 082 textStateLabel.setText(Bundle.getMessage("LightStatusLabel")); 083 textStateLabel.setVisible(true); 084 nowStateTextField.setText(Bundle.getMessage("BeanStateUnknown")); 085 nowStateTextField.setVisible(true); 086 nowControllersTextField.setText(""); 087 nowControllersTextField.setVisible(true); 088 textIsEnabledLabel.setText(Bundle.getMessage("LightIsEnabledLabel")); 089 textIsEnabledLabel.setToolTipText(Bundle.getMessage("LightIsEnabledLabelToolTip")); 090 textIsEnabledLabel.setVisible(true); 091 statusIsEnabledCheckBox.setVisible(true); 092 statusIsEnabledCheckBox.addActionListener(new ActionListener() { 093 @Override 094 public void actionPerformed(ActionEvent e) { 095 enabledCheckboxActionPerformed(e); 096 } 097 }); 098 textIsVariableLabel.setText(Bundle.getMessage("LightIsVariableLabel")); 099 textIsVariableLabel.setVisible(true); 100 statusIsVariableCheckBox.setVisible(true); 101 statusIsVariableCheckBox.setEnabled(false); 102 textIsTransitionLabel.setText(Bundle.getMessage("LightIsTransitionLabel")); 103 textIsTransitionLabel.setVisible(true); 104 statusIsTransitionCheckBox.setVisible(true); 105 statusIsTransitionCheckBox.setEnabled(false); 106 107 onButton.setText(Bundle.getMessage("StateOn")); 108 onButton.setVisible(true); 109 onButton.setToolTipText(Bundle.getMessage("LightOnButtonToolTip")); 110 onButton.addActionListener(new ActionListener() { 111 @Override 112 public void actionPerformed(ActionEvent e) { 113 onButtonActionPerformed(e); 114 } 115 }); 116 117 offButton.setText(Bundle.getMessage("StateOff")); 118 offButton.setVisible(true); 119 offButton.setToolTipText(Bundle.getMessage("LightOffButtonToolTip")); 120 offButton.addActionListener(new ActionListener() { 121 @Override 122 public void actionPerformed(ActionEvent e) { 123 offButtonActionPerformed(e); 124 } 125 }); 126 127 intensityTextLabel1.setText(Bundle.getMessage("LightIntensityTextLabel")); 128 intensityTextLabel1.setVisible(true); 129 nowIntensityLabel.setText(""); 130 nowIntensityLabel.setVisible(true); 131 intensityTextField.setText(oneDigits.format(0)); 132 intensityTextField.setVisible(true); 133 intensityTextLabel2.setText("%"); 134 intensityTextField.setToolTipText(Bundle.getMessage("LightIntensityTextToolTip")); 135 136 intensityMinTextLabel.setText(Bundle.getMessage("LightMinIntensityLabel")); 137 nowIntensityMinLabel.setText(""); 138 nowIntensityMinLabel.setVisible(true); 139 intensityMinTextField.setText(oneDigits.format(0)); 140 intensityMinTextField.setVisible(true); 141 intensityMinTextField.setToolTipText(Bundle.getMessage("LightMinIntensityToolTip")); 142 intensityMaxTextLabel.setText(Bundle.getMessage("LightMaxIntensityLabel")); 143 nowIntensityMaxLabel.setText(""); 144 nowIntensityMaxLabel.setVisible(true); 145 intensityMaxTextField.setText(oneDigits.format(100)); 146 intensityMaxTextField.setVisible(true); 147 intensityMaxTextField.setToolTipText(Bundle.getMessage("LightMinIntensityToolTip")); 148 transitionTimeTextLabel.setText(Bundle.getMessage("LightTransitionTimeLabel")); 149 nowTransitionTimeLabel.setText(""); 150 nowTransitionTimeLabel.setVisible(true); 151 transitionTimeTextField.setText(oneDigits.format(0)); 152 transitionTimeTextField.setVisible(true); 153 transitionTimeTextField.setEnabled(true); 154 transitionTimeTextField.setToolTipText(Bundle.getMessage("LightTransitionTimeToolTip")); 155 intensityButton.setText(Bundle.getMessage("LightSetButton")); 156 intensityButton.setVisible(true); 157 intensityButton.setToolTipText(Bundle.getMessage("LightSetButtonToolTip")); 158 intensityButton.addActionListener(new ActionListener() { 159 @Override 160 public void actionPerformed(ActionEvent e) { 161 intensityButtonActionPerformed(e); 162 } 163 }); 164 165 applyButton.setText(Bundle.getMessage("ButtonApply")); 166 applyButton.setVisible(true); 167 applyButton.setToolTipText(Bundle.getMessage("LightApplyButtonToolTip")); 168 applyButton.addActionListener(new ActionListener() { 169 @Override 170 public void actionPerformed(ActionEvent e) { 171 applyButtonActionPerformed(e); 172 } 173 }); 174 175 // set buttons inactive as no Light yet selected 176 setControlFrameActive(false); 177 178 // general GUI config 179 setTitle(Bundle.getMessage("LightBorder")); 180 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 181 182 // Light select 183 JPanel pane2 = new JPanel(); 184 pane2.add(to1); 185 getContentPane().add(pane2); 186 187 // status text 188 pane2 = new JPanel(); 189 pane2.add(textStateLabel); 190 pane2.add(nowStateTextField); 191 getContentPane().add(pane2); 192 193 // on off buttons 194 pane2 = new JPanel(); 195 pane2.add(onButton); 196 pane2.add(offButton); 197 getContentPane().add(pane2); 198 getContentPane().add(new javax.swing.JSeparator(javax.swing.SwingConstants.HORIZONTAL)); 199 200 // Controllers enabled checkbox 201 pane2 = new JPanel(); 202 pane2.add(textIsEnabledLabel); 203 pane2.add(statusIsEnabledCheckBox); 204 getContentPane().add(pane2); 205 206 // Controllers text 207 pane2 = new JPanel(); 208 pane2.add(nowControllersTextField); 209 getContentPane().add(pane2); 210 getContentPane().add(new javax.swing.JSeparator(javax.swing.SwingConstants.HORIZONTAL)); 211 212 // intensity field and button 213 pane2 = new JPanel(); 214 pane2.add(intensityTextLabel1); 215 pane2.add(nowIntensityLabel); 216 pane2.add(intensityTextField); 217 pane2.add(intensityTextLabel2); 218 pane2.add(intensityButton); 219 getContentPane().add(pane2); 220 getContentPane().add(new javax.swing.JSeparator(javax.swing.SwingConstants.HORIZONTAL)); 221 222 // min max textfields 223 pane2 = new JPanel(); 224 pane2.add(intensityMinTextLabel); 225 pane2.add(nowIntensityMinLabel); 226 pane2.add(intensityMinTextField); 227 pane2.add(intensityMaxTextLabel); 228 pane2.add(nowIntensityMaxLabel); 229 pane2.add(intensityMaxTextField); 230 getContentPane().add(pane2); 231 232 // time textfield, apply button 233 pane2 = new JPanel(); 234 pane2.add(transitionTimeTextLabel); 235 pane2.add(nowTransitionTimeLabel); 236 pane2.add(transitionTimeTextField); 237 pane2.add(applyButton); 238 getContentPane().add(pane2); 239 240 // add help menu to window 241 addHelpMenu("package.jmri.jmrit.simplelightctrl.SimpleLightCtrl", true); 242 243 pack(); 244 245 } 246 247 private void setControlFrameActive(boolean showLight) { 248 log.debug("selected light is {}", to1.getSelectedItem()); 249 onButton.setEnabled(showLight); 250 offButton.setEnabled(showLight); 251 statusIsEnabledCheckBox.setEnabled(showLight); 252 253 if (showLight && (light instanceof VariableLight)) { 254 intensityButton.setEnabled(true); 255 intensityMinTextField.setEnabled(true); 256 intensityMaxTextField.setEnabled(true); 257 intensityTextField.setEnabled(true); 258 applyButton.setEnabled(true); 259 } else { 260 intensityButton.setEnabled(false); 261 intensityMinTextField.setEnabled(false); 262 intensityMaxTextField.setEnabled(false); 263 intensityTextField.setEnabled(false); 264 intensityButton.setEnabled(false); 265 applyButton.setEnabled(false); 266 } 267 268 if (showLight && (light instanceof VariableLight) 269 && ((VariableLight)light).isTransitionAvailable()) { 270 transitionTimeTextField.setEnabled(true); 271 } else { 272 transitionTimeTextField.setEnabled(false); 273 } 274 275 } 276 277 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="SLF4J_SIGN_ONLY_FORMAT", 278 justification="I18N of log message") 279 public void offButtonActionPerformed(ActionEvent e) { 280 if (to1.getSelectedItem() == null) { 281 nowStateTextField.setText(Bundle.getMessage("ErrorTitle")); 282 return; 283 } 284 try { 285 // and set commanded state to ON 286 light.setState(Light.OFF); 287 } catch (Exception ex) { 288 log.error("{}{}", Bundle.getMessage("ErrorTitle"), ex.toString()); 289 nowStateTextField.setText(Bundle.getMessage("ErrorTitle")); 290 } 291 } 292 293 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="SLF4J_SIGN_ONLY_FORMAT", 294 justification="I18N of log message") 295 public void onButtonActionPerformed(ActionEvent e) { 296 if (to1.getSelectedItem() == null) { 297 nowStateTextField.setText(Bundle.getMessage("ErrorTitle")); 298 return; 299 } 300 try { 301 // and set commanded state to ON 302 light.setState(Light.ON); 303 } catch (Exception ex) { 304 log.error("{}{}", Bundle.getMessage("ErrorTitle"), ex.toString()); 305 nowStateTextField.setText(Bundle.getMessage("ErrorTitle")); 306 } 307 } 308 309 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="SLF4J_SIGN_ONLY_FORMAT", 310 justification="I18N of log message") 311 public void intensityButtonActionPerformed(ActionEvent e) { 312 if (to1.getSelectedItem() == null) { 313 nowStateTextField.setText(Bundle.getMessage("ErrorTitle")); 314 return; 315 } 316 try { 317 log.debug("about to command DIM"); // NOI18N 318 // and set commanded state to DIM 319 if (light instanceof VariableLight) { 320 ((VariableLight)light).setTargetIntensity( 321 Double.parseDouble(intensityTextField.getText().trim()) / 100); 322 } 323 } catch (NumberFormatException ex) { 324 log.error("{}{}", Bundle.getMessage("LightErrorIntensityButtonException"), ex.toString()); 325 nowStateTextField.setText(Bundle.getMessage("ErrorTitle")); 326 } 327 } 328 329 private void enabledCheckboxActionPerformed(ActionEvent e) { 330 if (statusIsEnabledCheckBox.isSelected()) { 331 light.setEnabled(true); 332 } else { 333 light.setEnabled(false); 334 } 335 } 336 337 /** 338 * Handle changes for intensity, rate, etc. 339 * @param e unused. 340 */ 341 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="SLF4J_SIGN_ONLY_FORMAT", 342 justification="I18N of log message") 343 public void applyButtonActionPerformed(ActionEvent e) { 344 if (to1.getSelectedItem() == null) { 345 nowStateTextField.setText(Bundle.getMessage("ErrorTitle")); 346 resetLightToCombo(); 347 return; 348 } 349 // load address from switchAddrTextField 350 try { 351 if (light instanceof VariableLight) { 352 VariableLight variableLight = (VariableLight)light; 353 double min = Double.parseDouble(intensityMinTextField.getText()) / 100.; 354 double max = Double.parseDouble(intensityMaxTextField.getText()) / 100.; 355 double time = Double.parseDouble(transitionTimeTextField.getText()); 356 log.debug("setting min: {} max: {} transition: {}", min, max, time); // NOI18N 357 if (!variableLight.isTransitionAvailable()) { 358 time = 0.0d; 359 } 360 361 variableLight.setMinIntensity(min); 362 variableLight.setMaxIntensity(max); 363 variableLight.setTransitionTime(time); 364 updateLightStatusFields(false); 365 } 366 } catch (NumberFormatException ex) { 367 log.error("{}{}", Bundle.getMessage("ErrorTitle"), ex.toString()); 368 nowStateTextField.setText(Bundle.getMessage("ErrorTitle")); 369 } 370 } 371 372 private void resetLightToCombo() { 373 if (light != null && light == to1.getSelectedItem()) { 374 return; 375 } 376 log.debug("Light changed in combobox to {}", to1.getSelectedItem()); 377 // remove changelistener from previous Light 378 if (light != null) { 379 light.removePropertyChangeListener(_parentLightListener); 380 } 381 light = to1.getSelectedItem(); 382 if (light != null) { 383 light.addPropertyChangeListener( 384 _parentLightListener = new PropertyChangeListener() { 385 @Override 386 public void propertyChange(java.beans.PropertyChangeEvent e) { 387 log.debug("recv propChange: {} {} -> {}", e.getPropertyName(), e.getOldValue(), e.getNewValue()); 388 updateLightStatusFields(false); 389 } 390 }); 391 setControlFrameActive(true); 392 updateLightStatusFields(true); 393 394 StringBuilder name = new StringBuilder("<html>"); 395 light.getLightControlList().forEach((otherLc) -> { 396 name.append(jmri.jmrit.beantable.LightTableAction.getDescriptionText(otherLc, otherLc.getControlType())); 397 name.append("<br>"); 398 }); 399 400 if (light.getLightControlList().isEmpty()) { 401 name.append("None"); 402 } 403 name.append("</html>"); 404 nowControllersTextField.setText(name.toString()); 405 406 repaint(); 407 revalidate(); 408 pack(); 409 410 } else { 411 setControlFrameActive(false); 412 nowStateTextField.setText(Bundle.getMessage("BeanStateUnknown")); 413 nowControllersTextField.setText(""); 414 } 415 } 416 417 // if flag true, sets intensity and time fields 418 private void updateLightStatusFields(boolean flag) { 419 int knownState = light.getState(); 420 switch (knownState) { 421 case Light.ON: 422 nowStateTextField.setText(Bundle.getMessage("StateOn")); 423 break; 424 case Light.INTERMEDIATE: 425 nowStateTextField.setText(Bundle.getMessage("LightStateIntermediate")); 426 break; 427 case Light.OFF: 428 nowStateTextField.setText(Bundle.getMessage("StateOff")); 429 break; 430 case Light.TRANSITIONINGTOFULLON: 431 nowStateTextField.setText(Bundle.getMessage("LightStateTransitioningToFullOn")); 432 break; 433 case Light.TRANSITIONINGHIGHER: 434 nowStateTextField.setText(Bundle.getMessage("LightStateTransitioningHigher")); 435 break; 436 case Light.TRANSITIONINGLOWER: 437 nowStateTextField.setText(Bundle.getMessage("LightStateTransitioningLower")); 438 break; 439 case Light.TRANSITIONINGTOFULLOFF: 440 nowStateTextField.setText(Bundle.getMessage("LightStateTransitioningToFullOff")); 441 break; 442 default: 443 nowStateTextField.setText(Bundle.getMessage("UnexpectedValueLabel", knownState)); 444 break; 445 } 446 statusIsEnabledCheckBox.setSelected(light.getEnabled()); 447 if (light instanceof VariableLight) { 448 VariableLight variableLight = (VariableLight)light; 449 statusIsVariableCheckBox.setSelected(true); 450 statusIsTransitionCheckBox.setSelected(variableLight.isTransitionAvailable()); 451 nowIntensityLabel.setText(oneDigits.format(variableLight.getCurrentIntensity() * 100)); 452 nowTransitionTimeLabel.setText(oneDotTwoDigits.format(variableLight.getTransitionTime())); 453 nowIntensityMinLabel.setText(oneDigits.format(variableLight.getMinIntensity() * 100)); 454 nowIntensityMaxLabel.setText(oneDigits.format(variableLight.getMaxIntensity() * 100)); 455 if (flag) { 456 intensityTextField.setText(oneDigits.format(variableLight.getTargetIntensity() * 100)); 457 transitionTimeTextField.setText(oneDotTwoDigits.format(variableLight.getTransitionTime())); 458 intensityMinTextField.setText(oneDigits.format(variableLight.getMinIntensity() * 100)); 459 intensityMaxTextField.setText(oneDigits.format(variableLight.getMaxIntensity() * 100)); 460 } 461 } else { 462 statusIsVariableCheckBox.setSelected(false); 463 statusIsTransitionCheckBox.setSelected(false); 464 if (light.getState() == Light.ON) { 465 nowIntensityLabel.setText(oneDigits.format(1)); 466 } else { 467 nowIntensityLabel.setText(oneDigits.format(0)); 468 } 469 nowTransitionTimeLabel.setText(oneDotTwoDigits.format(0.0)); 470 nowIntensityMinLabel.setText(oneDigits.format(0)); 471 nowIntensityMaxLabel.setText(oneDigits.format(1)); 472 if (flag) { 473 if (light.getState() == Light.ON) { 474 nowIntensityLabel.setText(oneDigits.format(1)); 475 } else { 476 nowIntensityLabel.setText(oneDigits.format(0)); 477 } 478 transitionTimeTextField.setText(oneDotTwoDigits.format(0.0)); 479 intensityMinTextField.setText(oneDigits.format(0)); 480 intensityMaxTextField.setText(oneDigits.format(1)); 481 } 482 } 483 } 484 485 private final static Logger log = LoggerFactory.getLogger(SimpleLightCtrlFrame.class); 486 487}