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