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