001package jmri.jmrix.lenz.swing.stackmon; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004import java.awt.Dimension; 005import java.awt.FlowLayout; 006import javax.swing.BoxLayout; 007import javax.swing.JButton; 008import javax.swing.JLabel; 009import javax.swing.JMenuBar; 010import javax.swing.JPanel; 011import javax.swing.JScrollPane; 012import javax.swing.JTextField; 013import jmri.jmrix.lenz.XNetConstants; 014import jmri.jmrix.lenz.XNetListener; 015import jmri.jmrix.lenz.XNetMessage; 016import jmri.jmrix.lenz.XNetReply; 017import jmri.jmrix.lenz.XNetTrafficController; 018import org.slf4j.Logger; 019import org.slf4j.LoggerFactory; 020 021/** 022 * This frame provides a method for searching the command station stack. 023 * <p> 024 * Current functionality is to search the stack and delete entries. 025 * Future capabilities may include the ability to set the status of function buttons. 026 * 027 * @author Paul Bender Copyright (C) 2005-2010 028 */ 029public class StackMonFrame extends jmri.util.JmriJFrame implements XNetListener { 030 031 // buttons currently (4.8) not displayed 032 final JButton nextButton = new JButton(Bundle.getMessage("NextButtonLabel")); 033 final JButton previousButton = new JButton(Bundle.getMessage("PreviousButtonLabel")); 034 final JButton deleteButton = new JButton(Bundle.getMessage("ButtonDelete")); 035 final JButton refreshButton = new JButton(Bundle.getMessage("RefreshButtonLabel")); 036 final JLabel currentStatus = new JLabel(" "); 037 038 final JTextField adrTextField = new javax.swing.JTextField(4); 039 040 StackMonDataModel stackModel; 041 javax.swing.JTable stackTable; 042 043 // flag to know if Get All or Get Next/Previous was pressed 044 private boolean _getAll = false; 045 046 protected XNetTrafficController tc; 047 048 public StackMonFrame(jmri.jmrix.lenz.XNetSystemConnectionMemo memo) { 049 super(); 050 // Configure GUI components 051 stackModel = new StackMonDataModel(1, 4, memo); 052 stackTable = new javax.swing.JTable(stackModel); 053 054 // Add listener object to retrieve the next entry 055 nextButton.addActionListener(e -> getNextEntry()); 056 057 // Set the Next button to visible 058 nextButton.setVisible(true); 059 // add listener object to retrieve the previous entry 060 previousButton.addActionListener(e -> getPreviousEntry()); 061 062 // Set the Previous button to visible. 063 previousButton.setVisible(true); 064 // The previous function is not currently implemented on the 065 // command station, so we're going to disable the button for now 066 previousButton.setEnabled(false); 067 068 // Set the Delete button to visible 069 deleteButton.setVisible(true); 070 // add listener object to remove the current entry 071 deleteButton.addActionListener(e -> deleteEntry()); 072 073 // Set the nextButton to visible 074 refreshButton.setVisible(true); 075 // add listener object to retrieve the next entry 076 refreshButton.addActionListener(e -> getAllEntries()); 077 078 // Set the adrTextField to visible 079 adrTextField.setVisible(true); 080 081 // general GUI config 082 setTitle(Bundle.getMessage("MenuItemCSDatabaseManager")); 083 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 084 085 // install items in GUI 086 JPanel pane1 = new JPanel(); 087 pane1.setLayout(new FlowLayout()); 088 089 pane1.add(refreshButton); 090 getContentPane().add(pane1); 091 //pane1.setMaximumSize(pane1.getSize()); 092 093 JPanel manualPanel = new JPanel(); 094 manualPanel.setLayout(new FlowLayout()); 095 manualPanel.add(previousButton); 096 manualPanel.add(nextButton); 097 manualPanel.add(deleteButton); 098 099 //getContentPane().add(manualPanel); // not working? 100 JPanel pane2 = new JPanel(); 101 pane2.setLayout(new FlowLayout()); 102 pane2.add(adrTextField); 103 //getContentPane().add(pane2); // not working? 104 105 JPanel pane3 = new JPanel(); 106 pane3.setLayout(new FlowLayout()); 107 pane3.add(currentStatus); 108 //getContentPane().add(pane3); // not working? 109 110 // Set up the JTable in a Scroll Pane 111 JScrollPane stackPane = new JScrollPane(stackTable); 112 stackPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); 113 stackModel.initTable(stackTable, this); 114 getContentPane().add(stackPane); 115 116 addHelpMenu("package.jmri.jmrix.lenz.stackmon.StackMonFrame", true); 117 118 pack(); 119 120 tc = memo.getXNetTrafficController(); 121 122 tc.addXNetListener(~0, this); 123 } 124 125 @Override 126 public void addNotify() { 127 super.addNotify(); 128 129 // resize frame to account for menubar 130 JMenuBar jMenuBar = getJMenuBar(); 131 if (jMenuBar != null) { 132 int jMenuBarHeight = jMenuBar.getPreferredSize().height; 133 Dimension dimension = getSize(); 134 dimension.height += jMenuBarHeight; 135 setSize(dimension); 136 } 137 } 138 139 /** 140 * Request ALL entries. 141 */ 142 private void getAllEntries() { 143 stackModel.clearData(); 144 _getAll = true; 145 getNextEntry(); 146 } 147 148 /** 149 * Request the next entry. 150 */ 151 private void getNextEntry() { 152 int address = 0; 153 if (!adrTextField.getText().equals("")) { 154 address = Integer.parseInt(adrTextField.getText()); 155 } 156 XNetMessage msg = XNetMessage.getNextAddressOnStackMsg(address, true); 157 tc.sendXNetMessage(msg, this); 158 } 159 160 /** 161 * Request the next entry by ID. 162 */ 163 private void getNextEntry(int address) { 164 XNetMessage msg = XNetMessage.getNextAddressOnStackMsg(address, true); 165 tc.sendXNetMessage(msg, this); 166 } 167 168 /** 169 * Request the previous entry. 170 */ 171 private void getPreviousEntry() { 172 int address = 0; 173 if (!adrTextField.getText().equals("")) { 174 address = Integer.parseInt(adrTextField.getText()); 175 } 176 XNetMessage msg = XNetMessage.getNextAddressOnStackMsg(address, false); 177 tc.sendXNetMessage(msg, this); 178 } 179 180 /** 181 * Remove the current entry. 182 */ 183 private void deleteEntry() { 184 int address; 185 if (!adrTextField.getText().equals("")) { 186 address = Integer.parseInt(adrTextField.getText()); 187 XNetMessage msg = XNetMessage.getDeleteAddressOnStackMsg(address); 188 tc.sendXNetMessage(msg, this); 189 } 190 } 191 192 /** 193 * Request the status of the current address. 194 */ 195 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", 196 justification = "This is part of work in progress code to allow display of all information about the locomotives in the stack.") 197 private void requestStatus() { 198 int address; 199 if (!adrTextField.getText().equals("")) { 200 address = Integer.parseInt(adrTextField.getText()); 201 XNetMessage msg = XNetMessage.getLocomotiveInfoRequestMsg(address); 202 tc.sendXNetMessage(msg, this); 203 } 204 } 205 206 /** 207 * Request the momentary/continuous status of functions for the 208 * current address. 209 */ 210 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD", 211 justification = "This is part of work in progress code to allow display of all information about the locomotives in the stack.") 212 private void requestFunctionStatus() { 213 int address; 214 if (!adrTextField.getText().equals("")) { 215 address = Integer.parseInt(adrTextField.getText()); 216 XNetMessage msg = XNetMessage.getLocomotiveFunctionStatusMsg(address); 217 tc.sendXNetMessage(msg, this); 218 } 219 } 220 221 // The XNet Listener Interface 222 223 /** 224 * Receive information from the command station. 225 */ 226 @Override 227 public void message(XNetReply r) { 228 if (r.getElement(0) == XNetConstants.LOCO_INFO_RESPONSE) { 229 int address = r.getThrottleMsgAddr(); 230 Integer intAddress = address; 231 switch (r.getElement(1)) { 232 case XNetConstants.LOCO_SEARCH_RESPONSE_N: 233 currentStatus.setText(Bundle.getMessage("SearchNormal")); 234 adrTextField.setText("" + address); 235 stackModel.updateData(intAddress, Bundle.getMessage("SearchNormal")); 236 // Request Address Status 237 // requestStatus(); 238 // requestFunctionStatus(); 239 if (_getAll) { 240 getNextEntry(address); 241 } 242 break; 243 case XNetConstants.LOCO_SEARCH_RESPONSE_DH: 244 currentStatus.setText(Bundle.getMessage("SearchDH")); 245 adrTextField.setText("" + r.getThrottleMsgAddr()); 246 stackModel.updateData(intAddress, Bundle.getMessage("SearchDH")); 247 // Request Address Status 248 // requestStatus(); 249 // requestFunctionStatus(); 250 if (_getAll) { 251 getNextEntry(address); 252 } 253 break; 254 case XNetConstants.LOCO_SEARCH_RESPONSE_MU_BASE: 255 currentStatus.setText(Bundle.getMessage("SearchMUBase")); 256 adrTextField.setText("" + r.getThrottleMsgAddr()); 257 stackModel.updateData(intAddress, Bundle.getMessage("SearchMUBase")); 258 // Request Address Status 259 // requestStatus(); 260 // requestFunctionStatus(); 261 if (_getAll) { 262 getNextEntry(address); 263 } 264 break; 265 case XNetConstants.LOCO_SEARCH_RESPONSE_MU: 266 currentStatus.setText(Bundle.getMessage("SearchMU")); 267 adrTextField.setText("" + r.getThrottleMsgAddr()); 268 stackModel.updateData(intAddress, Bundle.getMessage("SearchMU")); 269 // Request Address Status 270 // requestStatus(); 271 // requestFunctionStatus(); 272 if (_getAll) { 273 getNextEntry(address); 274 } 275 break; 276 case XNetConstants.LOCO_SEARCH_NO_RESULT: 277 currentStatus.setText(Bundle.getMessage("SearchFail")); 278 adrTextField.setText("" + r.getThrottleMsgAddr()); 279 if (_getAll) { 280 _getAll = false; //finished getting all entries 281 } 282 break; 283 default: 284 if (log.isDebugEnabled()) { 285 log.debug("not search result"); 286 } 287 } 288 } 289 290 } 291 292 /** 293 * Receive information sent by the computer to the command station. 294 */ 295 @Override 296 public void message(XNetMessage m) { 297 } 298 299 /** 300 * Handle a timeout notification. 301 */ 302 @Override 303 public void notifyTimeout(XNetMessage msg) { 304 if (log.isDebugEnabled()) { 305 log.debug("Notified of timeout on message{}", msg.toString()); 306 } 307 } 308 309 // Register for logging 310 private static final Logger log = LoggerFactory.getLogger(StackMonFrame.class); 311 312}