001package jmri.jmrix.pricom.pockettester; 002 003import java.util.Hashtable; 004import javax.swing.JLabel; 005import javax.swing.JPanel; 006import javax.swing.JTabbedPane; 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010/** 011 * Simple to display DCC status from Pocket Tester. 012 * <p> 013 * For more info on the product, see http://www.pricom.com 014 * 015 * @author Bob Jacobsen Copyright (C) 2005 016 */ 017public class StatusFrame extends jmri.util.JmriJFrame implements DataListener { 018 019 javax.swing.Timer timer = new javax.swing.Timer(500, new java.awt.event.ActionListener() { 020 @Override 021 public void actionPerformed(java.awt.event.ActionEvent e) { 022 sendRequest(); 023 } 024 }); 025 026 JTabbedPane tabPane = new JTabbedPane(); 027 Hashtable<String, JLabel> displayHash = new Hashtable<String, JLabel>(); 028 Hashtable<String, String> formatHash = new Hashtable<String, String>(); 029 DataSource source = null; 030 031 public StatusFrame() { 032 super(Bundle.getMessage("TitleStatus")); 033 } 034 035 /** 036 * Add GUI elements 037 */ 038 @Override 039 public void initComponents() { 040 getContentPane().add(tabPane); 041 042 // loop over the auto definitions from the properties file, adding panes 043 // get pane count 044 int numAutoPane = Integer.parseInt(Bundle.getMessage("CSNumAutoPanes")); 045 046 for (int i = 0; i < numAutoPane; i++) { 047 // create and install tabbed pane 048 JPanel p = new JPanel(); 049 p.setLayout(new java.awt.GridLayout(0, 2)); // 0 rows is a dummy value 050 tabPane.addTab(Bundle.getMessage("CS" + i + "Title"), p); 051 052 // install variables 053 int numVars = Integer.parseInt(Bundle.getMessage("CS" + i + "NumVars")); 054 for (int j = 0; j < numVars; j++) { 055 p.add(new JLabel(Bundle.getMessage("CS" + i + "Var" + j + "Name"))); 056 JLabel val = new JLabel("-----"); 057 // record the label and format for later 058 displayHash.put(Bundle.getMessage("CS" + i + "Var" + j + "ID"), val); 059 formatHash.put(Bundle.getMessage("CS" + i + "Var" + j + "ID"), Bundle.getMessage("CS" + i + "Var" + j + "Format")); 060 p.add(val); 061 } 062 } 063 064 // add a listener to hear about selections 065 tabPane.addChangeListener(new javax.swing.event.ChangeListener() { 066 @Override 067 public void stateChanged(javax.swing.event.ChangeEvent e) { 068 sendRequest(); // to get a fast update 069 } 070 } 071 ); 072 073 // get ready to display 074 pack(); 075 076 } 077 078 protected String title() { 079 return Bundle.getMessage("TitleStatus"); 080 } 081 082 // note that the message coming from the unit has 083 // an invisible null character after the "=" in version 1.5.1 084 // but not in later versions 085 @Override 086 public void asciiFormattedMessage(String input) { 087 String m = input + " "; // extra space to make stripping easier 088 // check if interesting 089 if (!m.substring(0, 1).equals(" ")) { 090 return; 091 } 092 if (!m.substring(3, 4).equals("=")) { 093 return; 094 } 095 int addOne = 0; 096 if (m.substring(4, 5).equals("\000")) { 097 addOne = 1; 098 } 099 // basically OK. Break into tokens, store if match, quit when done. 100 while (m.length() >= 14 + addOne) { 101 String id = m.substring(1, 3); 102 String value = m.substring(4 + addOne, 14 + addOne); 103 if (log.isDebugEnabled()) { 104 log.debug("set var {}:{}", id, value); 105 } 106 JLabel label = displayHash.get(id); 107 String format = formatHash.get(id); 108 if (label != null) { 109 label.setText(convertValue(value, format)); 110 } 111 m = m.substring(14 + addOne); 112 } 113 } 114 115 protected String convertValue(String val, String format) { 116 if (format.equals("address")) { 117 // long or short address format 118 int address = Integer.parseInt(val); 119 if (address >= 0x8000) { 120 return "" + (address - 0x8000) + " (long)"; 121 } else { 122 return "" + address + " (short)"; 123 } 124 125 } else if (format.equals("msec")) { 126 // value is in 10's of nsec, add decimal point for msec 127 return val.substring(0, 5) + "." + val.substring(5) + " msec"; 128 129 } else if (format.equals("none")) { 130 // no formatting, used for counts, etc 131 return val; // don't change the content 132 133 } else // didn't find matching format name, warn 134 { 135 return val + " (bad format)"; 136 } 137 } 138 139 /** 140 * Time to send the next request 141 */ 142 private void sendRequest() { 143 int i = tabPane.getSelectedIndex(); 144 String prompt = Bundle.getMessage("CS" + i + "PromptChar"); 145 log.debug("send {} for pane {}", prompt, i); 146 147 if (source == null) { 148 log.error("DataSource should not be null in sendRequest"); 149 timer.stop(); 150 return; 151 } 152 153 source.sendBytes(prompt.getBytes()); 154 155 } 156 157 public void setSource(DataSource s) { 158 source = s; 159 // start the timer for updates 160 timer.setRepeats(true); // in case we run by 161 timer.start(); 162 } 163 164 @Override 165 public void dispose() { 166 // stop timer 167 timer.stop(); 168 // and clean up parent 169 super.dispose(); 170 } 171 172 private final static Logger log = LoggerFactory.getLogger(StatusFrame.class); 173 174}