001package jmri.jmrix.secsi.nodeconfig; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004 005import java.awt.Container; 006import java.awt.FlowLayout; 007import javax.swing.BorderFactory; 008import javax.swing.BoxLayout; 009import javax.swing.JComboBox; 010import javax.swing.JLabel; 011import javax.swing.JPanel; 012import javax.swing.border.Border; 013import jmri.jmrix.secsi.SerialNode; 014import jmri.jmrix.secsi.SerialSensorManager; 015import jmri.jmrix.secsi.SecsiSystemConnectionMemo; 016import jmri.util.swing.JmriJOptionPane; 017 018/** 019 * Frame for user configuration of serial nodes. 020 * 021 * @author Bob Jacobsen Copyright (C) 2004, 2007, 2008 022 * @author Dave Duchamp Copyright (C) 2004, 2006 023 */ 024public class NodeConfigFrame extends jmri.util.JmriJFrame { 025 026 private SecsiSystemConnectionMemo memo; 027 028 protected javax.swing.JTextField nodeAddrField = new javax.swing.JTextField(3); 029 protected javax.swing.JLabel nodeAddrStatic = new javax.swing.JLabel("000"); 030 protected javax.swing.JComboBox<String> nodeTypeBox; 031 032 protected javax.swing.JButton addButton = new javax.swing.JButton(Bundle.getMessage("ButtonAdd")); 033 protected javax.swing.JButton editButton = new javax.swing.JButton(Bundle.getMessage("ButtonEdit")); 034 protected javax.swing.JButton deleteButton = new javax.swing.JButton(Bundle.getMessage("ButtonDelete")); 035 protected javax.swing.JButton doneButton = new javax.swing.JButton(Bundle.getMessage("ButtonDone")); 036 protected javax.swing.JButton updateButton = new javax.swing.JButton(Bundle.getMessage("ButtonUpdate")); 037 protected javax.swing.JButton cancelButton = new javax.swing.JButton(Bundle.getMessage("ButtonCancel")); 038 039 protected javax.swing.JLabel statusText1 = new javax.swing.JLabel(); 040 protected javax.swing.JLabel statusText2 = new javax.swing.JLabel(); 041 protected javax.swing.JLabel statusText3 = new javax.swing.JLabel(); 042 043 protected boolean changedNode = false; // true if a node was changed, deleted, or added 044 protected boolean editMode = false; // true if in edit mode 045 private boolean checkEnabled = jmri.InstanceManager.getDefault(jmri.configurexml.ShutdownPreferences.class).isStoreCheckEnabled(); 046 047 protected SerialNode curNode = null; // Serial Node being editted 048 protected int nodeAddress = 0; // Node address 049 protected int nodeType = SerialNode.DAUGHTER; // Node type 050 051 protected boolean errorInStatus1 = false; 052 protected boolean errorInStatus2 = false; 053 protected String stdStatus1 = Bundle.getMessage("NotesStd1"); 054 protected String stdStatus2 = Bundle.getMessage("NotesStd2"); 055 protected String stdStatus3 = Bundle.getMessage("NotesStd3"); 056 protected String editStatus1 = Bundle.getMessage("NotesEdit1"); 057 protected String editStatus2 = Bundle.getMessage("NotesEdit2"); 058 protected String editStatus3 = Bundle.getMessage("NotesEdit3"); 059 060 /** 061 * Constructor method 062 * @param _memo system connection. 063 */ 064 public NodeConfigFrame(SecsiSystemConnectionMemo _memo) { 065 super(); 066 memo = _memo; 067 } 068 069 /** 070 * Initialize the node config window. 071 */ 072 @Override 073 public void initComponents() { 074 setTitle(Bundle.getMessage("ConfigNodesTitle")); 075 076 Container contentPane = getContentPane(); 077 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 078 079 // Set up node address and node type 080 JPanel panel1 = new JPanel(); 081 panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS)); 082 083 // panel11 is the node address and type 084 JPanel panel11 = new JPanel(); 085 panel11.setLayout(new FlowLayout()); 086 panel11.add(new JLabel(Bundle.getMessage("LabelNodeAddress") + " ")); 087 panel11.add(nodeAddrField); 088 nodeAddrField.setToolTipText(Bundle.getMessage("TipNodeAddress")); 089 nodeAddrField.setText("0"); 090 panel11.add(nodeAddrStatic); 091 nodeAddrStatic.setVisible(false); 092 panel11.add(new JLabel(" " + Bundle.getMessage("LabelNodeType") + " ")); 093 nodeTypeBox = new JComboBox<String>(SerialNode.getBoardNames()); 094 panel11.add(nodeTypeBox); 095 nodeTypeBox.setToolTipText(Bundle.getMessage("TipNodeType")); 096 contentPane.add(panel11); 097 098 // Set up the notes panel 099 JPanel panel3 = new JPanel(); 100 panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS)); 101 JPanel panel31 = new JPanel(); 102 panel31.setLayout(new FlowLayout()); 103 statusText1.setText(stdStatus1); 104 statusText1.setVisible(true); 105 panel31.add(statusText1); 106 JPanel panel32 = new JPanel(); 107 panel32.setLayout(new FlowLayout()); 108 statusText2.setText(stdStatus2); 109 statusText2.setVisible(true); 110 panel32.add(statusText2); 111 JPanel panel33 = new JPanel(); 112 panel33.setLayout(new FlowLayout()); 113 statusText3.setText(stdStatus3); 114 statusText3.setVisible(true); 115 panel33.add(statusText3); 116 panel3.add(panel31); 117 panel3.add(panel32); 118 panel3.add(panel33); 119 Border panel3Border = BorderFactory.createEtchedBorder(); 120 Border panel3Titled = BorderFactory.createTitledBorder(panel3Border, 121 Bundle.getMessage("BoxLabelNotes")); 122 panel3.setBorder(panel3Titled); 123 contentPane.add(panel3); 124 125 // Set up buttons 126 JPanel panel4 = new JPanel(); 127 panel4.setLayout(new FlowLayout()); 128 addButton.setText(Bundle.getMessage("ButtonAdd")); 129 addButton.setVisible(true); 130 addButton.setToolTipText(Bundle.getMessage("TipAddButton")); 131 addButton.addActionListener(new java.awt.event.ActionListener() { 132 @Override 133 public void actionPerformed(java.awt.event.ActionEvent e) { 134 addButtonActionPerformed(); 135 } 136 }); 137 panel4.add(addButton); 138 editButton.setText(Bundle.getMessage("ButtonEdit")); 139 editButton.setVisible(true); 140 editButton.setToolTipText(Bundle.getMessage("TipEditButton")); 141 panel4.add(editButton); 142 editButton.addActionListener(new java.awt.event.ActionListener() { 143 @Override 144 public void actionPerformed(java.awt.event.ActionEvent e) { 145 editButtonActionPerformed(); 146 } 147 }); 148 panel4.add(deleteButton); 149 deleteButton.setText(Bundle.getMessage("ButtonDelete")); 150 deleteButton.setVisible(true); 151 deleteButton.setToolTipText(Bundle.getMessage("TipDeleteButton")); 152 panel4.add(deleteButton); 153 deleteButton.addActionListener(new java.awt.event.ActionListener() { 154 @Override 155 public void actionPerformed(java.awt.event.ActionEvent e) { 156 deleteButtonActionPerformed(); 157 } 158 }); 159 panel4.add(doneButton); 160 doneButton.setText(Bundle.getMessage("ButtonDone")); 161 doneButton.setVisible(true); 162 doneButton.setToolTipText(Bundle.getMessage("TipDoneButton")); 163 panel4.add(doneButton); 164 doneButton.addActionListener(new java.awt.event.ActionListener() { 165 @Override 166 public void actionPerformed(java.awt.event.ActionEvent e) { 167 doneButtonActionPerformed(); 168 } 169 }); 170 panel4.add(updateButton); 171 updateButton.setText(Bundle.getMessage("ButtonUpdate")); 172 updateButton.setVisible(true); 173 updateButton.setToolTipText(Bundle.getMessage("TipUpdateButton")); 174 panel4.add(updateButton); 175 updateButton.addActionListener(new java.awt.event.ActionListener() { 176 @Override 177 public void actionPerformed(java.awt.event.ActionEvent e) { 178 updateButtonActionPerformed(); 179 } 180 }); 181 updateButton.setVisible(false); 182 panel4.add(cancelButton); 183 cancelButton.setText(Bundle.getMessage("ButtonCancel")); 184 cancelButton.setVisible(true); 185 cancelButton.setToolTipText(Bundle.getMessage("TipCancelButton")); 186 panel4.add(cancelButton); 187 cancelButton.addActionListener(new java.awt.event.ActionListener() { 188 @Override 189 public void actionPerformed(java.awt.event.ActionEvent e) { 190 cancelButtonActionPerformed(); 191 } 192 }); 193 cancelButton.setVisible(false); 194 contentPane.add(panel4); 195 196 // pack for display 197 pack(); 198 } 199 200 /** 201 * Handle Add button. 202 */ 203 public void addButtonActionPerformed() { 204 // Check that a node with this address does not exist 205 int nodeAddress = readNodeAddress(); 206 if (nodeAddress < 0) { 207 return; 208 } 209 // get a SerialNode corresponding to this node address if one exists 210 curNode = (SerialNode) memo.getTrafficController().getNodeFromAddress(nodeAddress); 211 if (curNode != null) { 212 log.debug("Asked for new node address {}", Integer.toString(nodeAddress)); 213 statusText1.setText(Bundle.getMessage("Error1", Integer.toString(nodeAddress))); 214 statusText1.setVisible(true); 215 errorInStatus1 = true; 216 resetNotes2(); 217 return; 218 } 219 nodeType = nodeTypeBox.getSelectedIndex(); 220 221 // all ready, create the new node 222 curNode = new SerialNode(nodeAddress, nodeType, memo.getTrafficController()); 223 // configure the new node 224 setNodeParameters(); 225 // register any orphan sensors that this node may have 226 ((SerialSensorManager)memo.getSensorManager()).registerSensorsForNode(curNode); 227 // reset after succefully adding node 228 resetNotes(); 229 changedNode = true; 230 // provide user feedback 231 statusText1.setText(Bundle.getMessage("FeedBackAdd") + " " 232 + Integer.toString(nodeAddress)); 233 errorInStatus1 = true; 234 } 235 236 /** 237 * Handle Edit button. 238 */ 239 public void editButtonActionPerformed() { 240 // Find Serial Node address 241 nodeAddress = readNodeAddress(); 242 if (nodeAddress < 0) { 243 return; 244 } 245 // get the SerialNode corresponding to this node address 246 curNode = (SerialNode) memo.getTrafficController().getNodeFromAddress(nodeAddress); 247 if (curNode == null) { 248 statusText1.setText(Bundle.getMessage("Error4")); 249 statusText1.setVisible(true); 250 errorInStatus1 = true; 251 resetNotes2(); 252 return; 253 } 254 // Set up static node address 255 nodeAddrStatic.setText(Integer.toString(nodeAddress)); 256 nodeAddrField.setVisible(false); 257 nodeAddrStatic.setVisible(true); 258 // get information for this node and set up combo box 259 nodeType = curNode.getNodeType(); 260 nodeTypeBox.setSelectedIndex(nodeType); 261 // Switch buttons 262 editMode = true; 263 addButton.setVisible(false); 264 editButton.setVisible(false); 265 deleteButton.setVisible(false); 266 doneButton.setVisible(false); 267 updateButton.setVisible(true); 268 cancelButton.setVisible(true); 269 // Switch to edit notes 270 statusText1.setText(editStatus1); 271 statusText2.setText(editStatus2); 272 statusText3.setText(editStatus3); 273 } 274 275 /** 276 * Handle Delete button. 277 */ 278 public void deleteButtonActionPerformed() { 279 // Find Serial Node address 280 int nodeAddress = readNodeAddress(); 281 if (nodeAddress < 0) { 282 return; 283 } 284 // get the SerialNode corresponding to this node address 285 curNode = (SerialNode) memo.getTrafficController().getNodeFromAddress(nodeAddress); 286 if (curNode == null) { 287 statusText1.setText(Bundle.getMessage("Error4")); 288 statusText1.setVisible(true); 289 errorInStatus1 = true; 290 resetNotes2(); 291 return; 292 } 293 // confirm deletion with the user 294 if (JmriJOptionPane.OK_OPTION == JmriJOptionPane.showConfirmDialog( 295 this, Bundle.getMessage("ConfirmDelete1") + "\n" 296 + Bundle.getMessage("ConfirmDelete2"), Bundle.getMessage("ConfirmDeleteTitle"), 297 JmriJOptionPane.OK_CANCEL_OPTION, 298 JmriJOptionPane.WARNING_MESSAGE)) { 299 // delete this node 300 memo.getTrafficController().deleteNode(nodeAddress); 301 // provide user feedback 302 resetNotes(); 303 statusText1.setText(Bundle.getMessage("FeedBackDelete") + " " 304 + Integer.toString(nodeAddress)); 305 errorInStatus1 = true; 306 changedNode = true; 307 } else { 308 // reset as needed 309 resetNotes(); 310 } 311 } 312 313 /** 314 * Handle Done button. 315 */ 316 public void doneButtonActionPerformed() { 317 if (editMode) { 318 // Reset 319 editMode = false; 320 curNode = null; 321 // Switch buttons 322 addButton.setVisible(true); 323 editButton.setVisible(true); 324 deleteButton.setVisible(true); 325 doneButton.setVisible(true); 326 updateButton.setVisible(false); 327 cancelButton.setVisible(false); 328 nodeAddrField.setVisible(true); 329 nodeAddrStatic.setVisible(false); 330 } 331 if (changedNode && !checkEnabled) { 332 // Remind user to Save new configuration 333 JmriJOptionPane.showMessageDialog(this, 334 Bundle.getMessage("ReminderNode1") + "\n" + Bundle.getMessage("Reminder2"), 335 Bundle.getMessage("ReminderTitle"), 336 JmriJOptionPane.INFORMATION_MESSAGE); 337 } 338 setVisible(false); 339 dispose(); 340 } 341 342 /** 343 * Handle Update button. 344 */ 345 public void updateButtonActionPerformed() { 346 // update node information 347 nodeType = nodeTypeBox.getSelectedIndex(); 348 log.debug("update performed: was {} request {}", curNode.getNodeType(), nodeType); 349 if (curNode.getNodeType() != nodeType) { 350 // node type has changed 351 curNode.setNodeType(nodeType); 352 } 353 setNodeParameters(); 354 changedNode = true; 355 // Reset Edit Mode 356 editMode = false; 357 curNode = null; 358 // Switch buttons 359 addButton.setVisible(true); 360 editButton.setVisible(true); 361 deleteButton.setVisible(true); 362 doneButton.setVisible(true); 363 updateButton.setVisible(false); 364 cancelButton.setVisible(false); 365 // make node address editable again 366 nodeAddrField.setVisible(true); 367 nodeAddrStatic.setVisible(false); 368 // refresh notes panel 369 statusText2.setText(stdStatus2); 370 statusText3.setText(stdStatus3); 371 // provide user feedback 372 statusText1.setText(Bundle.getMessage("FeedBackUpdate") + " " 373 + Integer.toString(nodeAddress)); 374 errorInStatus1 = true; 375 } 376 377 /** 378 * Handle Cancel button. 379 */ 380 public void cancelButtonActionPerformed() { 381 // Reset 382 editMode = false; 383 curNode = null; 384 // Switch buttons 385 addButton.setVisible(true); 386 editButton.setVisible(true); 387 deleteButton.setVisible(true); 388 doneButton.setVisible(true); 389 updateButton.setVisible(false); 390 cancelButton.setVisible(false); 391 // make node address editable again 392 nodeAddrField.setVisible(true); 393 nodeAddrStatic.setVisible(false); 394 // refresh notes panel 395 statusText1.setText(stdStatus1); 396 statusText2.setText(stdStatus2); 397 statusText3.setText(stdStatus3); 398 } 399 400 /** 401 * Do the done action if the window is closed early. 402 */ 403 @Override 404 @SuppressFBWarnings(value = "OVERRIDING_METHODS_MUST_INVOKE_SUPER", 405 justification = "This calls doneButtonActionPerformed which handles window closing") 406 public void windowClosing(java.awt.event.WindowEvent e) { 407 doneButtonActionPerformed(); 408 } 409 410 /** 411 * Method to set node parameters The node must exist, and be in 'curNode' 412 * Also, the node type must be set and in 'nodeType' 413 */ 414 void setNodeParameters() { 415 // set curNode type 416 curNode.setNodeType(nodeType); 417 // Cause reinitialization of this Node to reflect these parameters 418 memo.getTrafficController().initializeSerialNode(curNode); 419 } 420 421 /** 422 * Method to reset the notes error after error display 423 */ 424 private void resetNotes() { 425 if (errorInStatus1) { 426 if (editMode) { 427 statusText1.setText(editStatus1); 428 } else { 429 statusText1.setText(stdStatus1); 430 } 431 errorInStatus1 = false; 432 } 433 resetNotes2(); 434 } 435 436 /** 437 * Reset the second line of Notes area 438 */ 439 private void resetNotes2() { 440 if (errorInStatus2) { 441 if (editMode) { 442 statusText1.setText(editStatus2); 443 } else { 444 statusText2.setText(stdStatus2); 445 } 446 errorInStatus2 = false; 447 } 448 } 449 450 /** 451 * Read node address and check for legal range If successful, a node address 452 * in the range 0-255 is returned. If not successful, -1 is returned and an 453 * appropriate error message is placed in statusText1. 454 */ 455 private int readNodeAddress() { 456 int addr = -1; 457 try { 458 addr = Integer.parseInt(nodeAddrField.getText()); 459 } catch (Exception e) { 460 statusText1.setText(Bundle.getMessage("Error5")); 461 statusText1.setVisible(true); 462 errorInStatus1 = true; 463 resetNotes2(); 464 return -1; 465 } 466 if ((addr < 0) || (addr > 255)) { 467 statusText1.setText(Bundle.getMessage("Error6")); 468 statusText1.setVisible(true); 469 errorInStatus1 = true; 470 resetNotes2(); 471 return -1; 472 } 473 return (addr); 474 } 475 476 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NodeConfigFrame.class); 477 478}