001package jmri.jmrix.sprog.sprogslotmon; 002 003import java.awt.Dimension; 004import java.awt.FlowLayout; 005import java.awt.event.ActionEvent; 006import java.awt.event.ActionListener; 007import javax.swing.BoxLayout; 008import javax.swing.JButton; 009import javax.swing.JMenuBar; 010import javax.swing.JPanel; 011import javax.swing.JScrollPane; 012import javax.swing.JTable; 013import javax.swing.JTextArea; 014import javax.swing.table.TableRowSorter; 015import jmri.jmrix.sprog.SprogListener; 016import jmri.jmrix.sprog.SprogMessage; 017import jmri.jmrix.sprog.SprogReply; 018import jmri.jmrix.sprog.SprogSystemConnectionMemo; 019import jmri.jmrix.sprog.SprogTrafficController; 020import jmri.util.swing.JmriMouseEvent; 021import jmri.util.swing.JmriMouseListener; 022import org.slf4j.Logger; 023import org.slf4j.LoggerFactory; 024 025/** 026 * Frame providing a command station slot manager. 027 * <p> 028 * May-17 Modified to a SprogListener to handle status replies. 029 * <p> 030 * Jan-18 Moved status request generation here, based on a timer. 031 * 032 * @author Bob Jacobsen Copyright (C) 2001 033 * @author Andrew Crosland (C) 2006 ported to SPROG 2008 034 */ 035public class SprogSlotMonFrame extends jmri.util.JmriJFrame implements SprogListener { 036 037 /** 038 * Controls whether not-in-use slots are shown. 039 */ 040 javax.swing.JCheckBox showAllCheckBox = new javax.swing.JCheckBox(); 041 042 JButton estopAllButton = new JButton(Bundle.getMessage("ButtonEstopAll")); 043 SprogSlotMonDataModel slotModel = null; 044 045 JTable slotTable; 046 JScrollPane slotScroll; 047 048 JTextArea status = new JTextArea(Bundle.getMessage("TrackCurrentXString", "---")); 049 050 SprogSystemConnectionMemo _memo = null; 051 private SprogTrafficController tc = null; 052 053 private static final int STATUS_PERIOD = 500; 054 javax.swing.Timer timer = null; 055 056 public SprogSlotMonFrame(SprogSystemConnectionMemo memo) { 057 super(); 058 _memo = memo; 059 060 tc = memo.getSprogTrafficController(); 061 tc.addSprogListener(this); 062 063 slotModel = new SprogSlotMonDataModel(memo.getNumSlots(), 8, _memo); 064 065 slotTable = new JTable(slotModel); 066 slotTable.setRowSorter(new TableRowSorter<>(slotModel)); 067 slotScroll = new JScrollPane(slotTable); 068 069 // configure items for GUI 070 showAllCheckBox.setText(Bundle.getMessage("ButtonShowUnusedSlots")); 071 showAllCheckBox.setVisible(true); 072 showAllCheckBox.setSelected(true); 073 showAllCheckBox.setToolTipText(Bundle.getMessage("ButtonShowSlotsTooltip")); 074 075 slotModel.configureTable(slotTable); 076 077 // add listener object so checkboxes function 078 showAllCheckBox.addActionListener(new ActionListener() { 079 @Override 080 public void actionPerformed(ActionEvent e) { 081 slotModel.showAllSlots(showAllCheckBox.isSelected()); 082 slotModel.fireTableDataChanged(); 083 } 084 }); 085 086 // add listener object so stop all button functions 087 estopAllButton.addActionListener(new ActionListener() { 088 @Override 089 public void actionPerformed(ActionEvent e) { 090 log.debug("Estop all button pressed"); 091 _memo.getCommandStation().estopAll(); 092 } 093 }); 094 095 estopAllButton.addMouseListener(JmriMouseListener.adapt(new JmriMouseListener() { 096 @Override 097 public void mousePressed(JmriMouseEvent e) { 098 _memo.getCommandStation().estopAll(); 099 } 100 101 @Override 102 public void mouseExited(JmriMouseEvent e) { 103 } 104 105 @Override 106 public void mouseEntered(JmriMouseEvent e) { 107 } 108 109 @Override 110 public void mouseReleased(JmriMouseEvent e) { 111 } 112 113 @Override 114 public void mouseClicked(JmriMouseEvent e) { 115 } 116 })); 117 118 // adjust model to default settings 119 slotModel.showAllSlots(showAllCheckBox.isSelected()); 120 121 // general GUI config 122 setTitle(Bundle.getMessage("SprogSlotMonitorTitle")); 123 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 124 125 // install items in GUI 126 JPanel pane1 = new JPanel(); 127 pane1.setLayout(new FlowLayout()); 128 129 pane1.add(showAllCheckBox); 130 pane1.add(estopAllButton); 131 pane1.add(status); 132 133 getContentPane().add(pane1); 134 getContentPane().add(slotScroll); 135 136 setHelp(); 137 138 pack(); 139 pane1.setMaximumSize(pane1.getSize()); 140 pack(); 141 142 startTimer(STATUS_PERIOD); 143 } 144 145 /** 146 * Define system-specific help item 147 */ 148 protected void setHelp() { 149 addHelpMenu("package.jmri.jmrix.sprog.sprogslotmon.SprogSlotMonFrame", true); // NOI18N 150 } 151 152 public void update() { 153 slotModel.fireTableDataChanged(); 154 } 155 156 public void updateStatus(String a) { 157 status.setText(Bundle.getMessage("TrackCurrentXString", a)); 158 } 159 160 private boolean mShown = false; 161 162 /** 163 * Listen to outgoing messages. 164 * 165 * @param m the sprog message received 166 */ 167 @Override 168 public void notifyMessage(SprogMessage m) { 169 // Do nothing 170 } 171 172 /** 173 * Listen for status replies. 174 * 175 * @param m The SprogReply to be handled 176 */ 177 @Override 178 public void notifyReply(SprogReply m) { 179 int[] statusA = new int[4]; 180 String s = m.toString(); 181 log.debug("Reply received: {}", s); 182 if (s.indexOf('S') > -1) { 183 // Handle a status reply 184 log.debug("Status reply"); 185 int i = s.indexOf('h'); 186 // Double Check that "h" was found in the reply 187 if (i > -1) { 188 int milliAmps = (int) ((Integer.decode("0x" + s.substring(i + 7, i + 11))) 189 * tc.getAdapterMemo().getSprogType().getCurrentMultiplier()); 190 statusA[0] = milliAmps; 191 String ampString; 192 ampString = Float.toString((float) statusA[0] / 1000); 193 updateStatus(ampString); 194 } 195 } 196 } 197 198 @Override 199 public void addNotify() { 200 super.addNotify(); 201 202 if (mShown) { 203 return; 204 } 205 206 // resize frame to account for menubar 207 JMenuBar jMenuBar = getJMenuBar(); 208 if (jMenuBar != null) { 209 int jMenuBarHeight = jMenuBar.getPreferredSize().height; 210 Dimension dimension = getSize(); 211 dimension.height += jMenuBarHeight; 212 setSize(dimension); 213 } 214 mShown = true; 215 } 216 217 @Override 218 public void dispose() { 219 // deregister with the command station. 220 stopTimer(); 221 if (slotModel != null) { 222 slotModel.dispose(); 223 } 224 slotModel = null; 225 slotTable = null; 226 slotScroll = null; 227 if (tc != null) { 228 tc.removeSprogListener(this); 229 } 230 super.dispose(); 231 } 232 233 /** 234 * Internal routine to handle a timeout 235 */ 236 synchronized protected void timeout() { 237 Runnable r = () -> { 238 // Send a status request 239 log.debug("Sending status request"); 240 tc.sendSprogMessage(SprogMessage.getStatus(), this); 241 }; 242 javax.swing.SwingUtilities.invokeLater(r); 243 } 244 245 /** 246 * Internal routine to handle timer starts and restarts 247 * 248 * @param delay timer delay 249 */ 250 protected void startTimer(int delay) { 251 log.debug("Restart timer"); 252 if (timer == null) { 253 timer = new javax.swing.Timer(delay, (java.awt.event.ActionEvent e) -> { 254 timeout(); 255 }); 256 } 257 timer.stop(); 258 timer.setInitialDelay(delay); 259 timer.setRepeats(true); 260 timer.start(); 261 } 262 263 /** 264 * Internal routine to handle timer stop 265 */ 266 protected void stopTimer() { 267 log.debug("Stop timer"); 268 if (timer != null) { 269 timer.stop(); 270 } 271 } 272 273 private final static Logger log = LoggerFactory.getLogger(SprogSlotMonFrame.class); 274 275}