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