001package jmri.jmrix.ieee802154.swing.nodeconfig; 002 003import java.awt.Container; 004import java.awt.FlowLayout; 005import javax.swing.BorderFactory; 006import javax.swing.BoxLayout; 007import javax.swing.JLabel; 008import javax.swing.JPanel; 009import javax.swing.border.Border; 010import jmri.jmrix.ieee802154.IEEE802154Node; 011import jmri.jmrix.ieee802154.IEEE802154TrafficController; 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015/** 016 * Frame for user configuration of IEEE 802.15.4 nodes. 017 * Derived from node configuration for c/mri nodes. 018 * 019 * @author Bob Jacobsen Copyright (C) 2004 020 * @author Dave Duchamp Copyright (C) 2004 021 * @author Paul Bender Copyright (C) 2013 022 */ 023public class NodeConfigFrame extends jmri.util.JmriJFrame { 024 025 protected javax.swing.JComboBox<String> nodeAddrField = new javax.swing.JComboBox<String>(); 026 protected javax.swing.JComboBox<String> nodeAddr64Field = new javax.swing.JComboBox<String>(); 027 protected javax.swing.JButton addButton = new javax.swing.JButton(Bundle.getMessage("ButtonAdd")); 028 protected javax.swing.JButton editButton = new javax.swing.JButton(Bundle.getMessage("ButtonEdit")); 029 protected javax.swing.JButton deleteButton = new javax.swing.JButton(Bundle.getMessage("ButtonDelete")); 030 protected javax.swing.JButton doneButton = new javax.swing.JButton(Bundle.getMessage("ButtonDone")); 031 protected javax.swing.JButton updateButton = new javax.swing.JButton(Bundle.getMessage("ButtonUpdate")); 032 protected javax.swing.JButton cancelButton = new javax.swing.JButton(Bundle.getMessage("ButtonCancel")); 033 034 protected javax.swing.JLabel statusText1 = new javax.swing.JLabel(); 035 protected javax.swing.JLabel statusText2 = new javax.swing.JLabel(); 036 protected javax.swing.JLabel statusText3 = new javax.swing.JLabel(); 037 038 protected javax.swing.JPanel panel2 = new JPanel(); 039 protected javax.swing.JPanel panel2a = new JPanel(); 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 044 protected IEEE802154Node curNode = null; // IEEE802154 Node being editted 045 046 protected boolean errorInStatus1 = false; 047 protected boolean errorInStatus2 = false; 048 protected String stdStatus1 = Bundle.getMessage("NotesStd1"); 049 protected String stdStatus2 = Bundle.getMessage("NotesStd2"); 050 protected String stdStatus3 = Bundle.getMessage("NotesStd3"); 051 protected String editStatus1 = Bundle.getMessage("NotesEdit1"); 052 protected String editStatus2 = Bundle.getMessage("NotesEdit2"); 053 protected String editStatus3 = Bundle.getMessage("NotesEdit3"); 054 055 private IEEE802154TrafficController itc = null; 056 057 /** 058 * Constructor method 059 * @param tc connector for node 060 */ 061 public NodeConfigFrame(IEEE802154TrafficController tc) { 062 super(); 063 addHelpMenu("package.jmri.jmrix.ieee802154.swing.nodeconfig.NodeConfigFrame", true); 064 itc = tc; 065 } 066 067 /** 068 * Initialize the config window 069 */ 070 @Override 071 public void initComponents() { 072 setTitle(Bundle.getMessage("WindowTitle")); 073 Container contentPane = getContentPane(); 074 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 075 076 contentPane.add(initAddressPanel()); 077 contentPane.add(initNotesPanel()); 078 contentPane.add(initButtonPanel()); 079 080 081 // pack for display 082 pack(); 083 } 084 085 086 /* 087 * Initilaize the address panel. 088 */ 089 protected JPanel initAddressPanel(){ 090 // Set up node address and node type 091 JPanel panel1 = new JPanel(); 092 panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS)); 093 JPanel panel11 = new JPanel(); 094 panel11.setLayout(new FlowLayout()); 095 panel11.add(new JLabel(Bundle.getMessage("LabelNodeAddress") + " ")); 096 panel11.add(nodeAddrField); 097 nodeAddrField.addActionListener(new java.awt.event.ActionListener() { 098 099 @Override 100 public void actionPerformed(java.awt.event.ActionEvent e) { 101 nodeSelected(); 102 } 103 }); 104 nodeAddrField.setToolTipText(Bundle.getMessage("TipNodeAddress")); 105 panel11.add(new JLabel(Bundle.getMessage("LabelNodeAddress64") + " ")); 106 panel11.add(nodeAddr64Field); 107 nodeAddr64Field.setToolTipText(Bundle.getMessage("TipNodeAddress64")); 108 nodeAddr64Field.addActionListener(new java.awt.event.ActionListener() { 109 110 @Override 111 public void actionPerformed(java.awt.event.ActionEvent e) { 112 nodeAddrField.setSelectedIndex(nodeAddr64Field.getSelectedIndex()); 113 } 114 }); 115 116 initAddressBoxes(); 117 panel1.add(panel11); 118 return panel1; 119 } 120 121 122 /* 123 * Initialize the notes panel. 124 */ 125 protected JPanel initNotesPanel(){ 126 // Set up the notes panel 127 JPanel panel3 = new JPanel(); 128 panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS)); 129 JPanel panel31 = new JPanel(); 130 panel31.setLayout(new FlowLayout()); 131 statusText1.setText(stdStatus1); 132 statusText1.setVisible(true); 133 panel31.add(statusText1); 134 JPanel panel32 = new JPanel(); 135 panel32.setLayout(new FlowLayout()); 136 statusText2.setText(stdStatus2); 137 statusText2.setVisible(true); 138 panel32.add(statusText2); 139 JPanel panel33 = new JPanel(); 140 panel33.setLayout(new FlowLayout()); 141 statusText3.setText(stdStatus3); 142 statusText3.setVisible(true); 143 panel33.add(statusText3); 144 panel3.add(panel31); 145 panel3.add(panel32); 146 panel3.add(panel33); 147 Border panel3Border = BorderFactory.createEtchedBorder(); 148 Border panel3Titled = BorderFactory.createTitledBorder(panel3Border, 149 Bundle.getMessage("BoxLabelNotes")); 150 panel3.setBorder(panel3Titled); 151 return panel3; 152 } 153 154 /* 155 * Initialize the Button panel. 156 */ 157 protected JPanel initButtonPanel(){ 158 // Set up buttons 159 JPanel panel4 = new JPanel(); 160 panel4.setLayout(new FlowLayout()); 161 addButton.setText(Bundle.getMessage("ButtonAdd")); 162 addButton.setVisible(true); 163 addButton.setToolTipText(Bundle.getMessage("TipAddButton")); 164 addButton.addActionListener(new java.awt.event.ActionListener() { 165 @Override 166 public void actionPerformed(java.awt.event.ActionEvent e) { 167 addButtonActionPerformed(); 168 } 169 }); 170 panel4.add(addButton); 171 editButton.setText(Bundle.getMessage("ButtonEdit")); 172 editButton.setVisible(true); 173 editButton.setToolTipText(Bundle.getMessage("TipEditButton")); 174 panel4.add(editButton); 175 editButton.addActionListener(new java.awt.event.ActionListener() { 176 @Override 177 public void actionPerformed(java.awt.event.ActionEvent e) { 178 editButtonActionPerformed(); 179 } 180 }); 181 panel4.add(deleteButton); 182 deleteButton.setText(Bundle.getMessage("ButtonDelete")); 183 deleteButton.setVisible(true); 184 deleteButton.setToolTipText(Bundle.getMessage("TipDeleteButton")); 185 panel4.add(deleteButton); 186 deleteButton.addActionListener(new java.awt.event.ActionListener() { 187 @Override 188 public void actionPerformed(java.awt.event.ActionEvent e) { 189 deleteButtonActionPerformed(); 190 } 191 }); 192 panel4.add(doneButton); 193 doneButton.setText(Bundle.getMessage("ButtonDone")); 194 doneButton.setVisible(true); 195 doneButton.setToolTipText(Bundle.getMessage("TipDoneButton")); 196 panel4.add(doneButton); 197 doneButton.addActionListener(new java.awt.event.ActionListener() { 198 @Override 199 public void actionPerformed(java.awt.event.ActionEvent e) { 200 doneButtonActionPerformed(); 201 } 202 }); 203 panel4.add(updateButton); 204 updateButton.setText(Bundle.getMessage("ButtonUpdate")); 205 updateButton.setVisible(true); 206 updateButton.setToolTipText(Bundle.getMessage("TipUpdateButton")); 207 panel4.add(updateButton); 208 updateButton.addActionListener(new java.awt.event.ActionListener() { 209 @Override 210 public void actionPerformed(java.awt.event.ActionEvent e) { 211 updateButtonActionPerformed(); 212 } 213 }); 214 updateButton.setVisible(false); 215 panel4.add(cancelButton); 216 cancelButton.setText(Bundle.getMessage("ButtonCancel")); 217 cancelButton.setVisible(true); 218 cancelButton.setToolTipText(Bundle.getMessage("TipCancelButton")); 219 panel4.add(cancelButton); 220 cancelButton.addActionListener(new java.awt.event.ActionListener() { 221 @Override 222 public void actionPerformed(java.awt.event.ActionEvent e) { 223 cancelButtonActionPerformed(); 224 } 225 }); 226 cancelButton.setVisible(false); 227 return panel4; 228 } 229 230 /** 231 * Method to handle add button 232 */ 233 public void addButtonActionPerformed() { 234 // create a new Add Frame and display it. 235 jmri.util.JmriJFrame addFrame = new AddNodeFrame(itc); 236 try { 237 addFrame.initComponents(); 238 } catch(Exception ex) { 239 log.error("Exception initializing Frame: {}",ex.toString()); 240 return; 241 } 242 addFrame.setVisible(true); 243 } 244 245 /** 246 * Method to handle edit button 247 */ 248 public void editButtonActionPerformed() { 249 // Find IEEE802154 Node address 250 String nodeAddress = readNodeAddress(); 251 if (nodeAddress.equals("")) { 252 return; 253 } 254 // get the IEEE802154Node corresponding to this node address 255 curNode = (IEEE802154Node) itc.getNodeFromAddress(nodeAddress); 256 if (curNode == null) { 257 statusText1.setText(Bundle.getMessage("Error4")); 258 statusText1.setVisible(true); 259 errorInStatus1 = true; 260 resetNotes2(); 261 return; 262 } 263 264 // create a new Edit Frame and display it. 265 jmri.util.JmriJFrame editFrame = new EditNodeFrame(itc,curNode); 266 try { 267 editFrame.initComponents(); 268 } catch(Exception ex) { 269 log.error("Exception initializing Frame: {}",ex.toString()); 270 return; 271 } 272 editFrame.setVisible(true); 273 274 } 275 276 /** 277 * Method to handle delete button 278 */ 279 public void deleteButtonActionPerformed() { 280 // Find IEEE802154 Node address 281 String nodeAddress = readNodeAddress(); 282 if (nodeAddress.equals("")) { 283 return; 284 } 285 // get the IEEE802154Node corresponding to this node address 286 curNode = (IEEE802154Node) itc.getNodeFromAddress(nodeAddress); 287 if (curNode == null) { 288 statusText1.setText(Bundle.getMessage("Error4")); 289 statusText1.setVisible(true); 290 errorInStatus1 = true; 291 resetNotes2(); 292 return; 293 } 294 // confirm deletion with the user 295 if (javax.swing.JOptionPane.OK_OPTION == javax.swing.JOptionPane.showConfirmDialog( 296 this, Bundle.getMessage("ConfirmDelete1") + "\n" 297 + Bundle.getMessage("ConfirmDelete2"), Bundle.getMessage("ConfirmDeleteTitle"), 298 javax.swing.JOptionPane.OK_CANCEL_OPTION, 299 javax.swing.JOptionPane.WARNING_MESSAGE)) { 300 // delete this node 301 itc.deleteNode(nodeAddress); 302 // provide user feedback 303 resetNotes(); 304 statusText1.setText(Bundle.getMessage("FeedBackDelete") + " " + nodeAddress); 305 errorInStatus1 = true; 306 changedNode = true; 307 } else { 308 // reset as needed 309 resetNotes(); 310 } 311 initAddressBoxes(); 312 } 313 314 /** 315 * Method to handle done button 316 */ 317 public void doneButtonActionPerformed() { 318 if (editMode) { 319 // Reset 320 editMode = false; 321 curNode = null; 322 // Switch buttons 323 addButton.setVisible(true); 324 editButton.setVisible(true); 325 deleteButton.setVisible(true); 326 doneButton.setVisible(true); 327 updateButton.setVisible(false); 328 cancelButton.setVisible(false); 329 } 330 if (changedNode) { 331 // Remind user to Save new configuration 332 javax.swing.JOptionPane.showMessageDialog(this, 333 Bundle.getMessage("Reminder1") + "\n" + Bundle.getMessage("Reminder2"), 334 Bundle.getMessage("ReminderTitle"), 335 javax.swing.JOptionPane.INFORMATION_MESSAGE); 336 } 337 setVisible(false); 338 dispose(); 339 } 340 341 /** 342 * Method to handle update button 343 */ 344 public void updateButtonActionPerformed() { 345 // get node information from window 346 347 // check consistency of node information 348 if (!checkConsistency()) { 349 return; 350 } 351 // update node paramaters 352 setNodeParameters(); 353 changedNode = true; 354 // Reset Edit Mode 355 editMode = false; 356 curNode = null; 357 // Switch buttons 358 addButton.setVisible(true); 359 editButton.setVisible(true); 360 deleteButton.setVisible(true); 361 doneButton.setVisible(true); 362 updateButton.setVisible(false); 363 cancelButton.setVisible(false); 364 // refresh notes panel 365 statusText2.setText(stdStatus2); 366 statusText3.setText(stdStatus3); 367 // provide user feedback 368 statusText1.setText(Bundle.getMessage("FeedBackUpdate") + " " + readNodeAddress()); 369 errorInStatus1 = true; 370 } 371 372 /** 373 * Method to handle cancel button 374 */ 375 public void cancelButtonActionPerformed() { 376 // Reset 377 editMode = false; 378 curNode = null; 379 // Switch buttons 380 addButton.setVisible(true); 381 editButton.setVisible(true); 382 deleteButton.setVisible(true); 383 doneButton.setVisible(true); 384 updateButton.setVisible(false); 385 cancelButton.setVisible(false); 386 // refresh notes panel 387 statusText1.setText(stdStatus1); 388 statusText2.setText(stdStatus2); 389 statusText3.setText(stdStatus3); 390 } 391 392 /** 393 * Method to close the window when the close box is clicked 394 */ 395 @Override 396 public void windowClosing(java.awt.event.WindowEvent e) { 397 doneButtonActionPerformed(); 398 super.windowClosing(e); 399 } 400 401 /** 402 * Method to set node parameters The node must exist, and be in 'curNode' 403 */ 404 protected void setNodeParameters() { 405 } 406 407 /** 408 * Method to reset the notes error after error display 409 */ 410 private void resetNotes() { 411 if (errorInStatus1) { 412 if (editMode) { 413 statusText1.setText(editStatus1); 414 } else { 415 statusText1.setText(stdStatus1); 416 } 417 errorInStatus1 = false; 418 } 419 resetNotes2(); 420 } 421 422 /** 423 * Reset the second line of Notes area 424 */ 425 private void resetNotes2() { 426 if (errorInStatus2) { 427 if (editMode) { 428 statusText1.setText(editStatus2); 429 } else { 430 statusText2.setText(stdStatus2); 431 } 432 errorInStatus2 = false; 433 } 434 } 435 436 /** 437 * Read node address from the nodeAddressField or nodeAddr64Field 438 * as appropriate and return as a string. 439 * 440 * @return String containing the short (two byte) address of the node. 441 * if the two byte node address is either "FF FF" or "FF FE", 442 * returns the long (64 bit) address. 443 */ 444 private String readNodeAddress() { 445 String addr = ""; 446 addr = (String) nodeAddrField.getSelectedItem(); 447 if (addr.equals("FF FF ") || addr.equals("FF FE ")) { 448 addr = (String) nodeAddr64Field.getSelectedItem(); 449 } 450 return (addr); 451 } 452 453 /** 454 * Check for consistency errors by node type Returns 'true' if successful, 455 * 'false' if an error was detected. If an error is detected, a suitable 456 * error message is placed in the Notes area 457 * @return always true 458 */ 459 protected boolean checkConsistency() { 460 return true; 461 } 462 463 // Initialize the drop down box for the address lists. 464 protected void initAddressBoxes() { 465 IEEE802154Node current = null; 466 nodeAddrField.removeAllItems(); 467 nodeAddr64Field.removeAllItems(); 468 for (int i = 0; i < itc.getNumNodes(); i++) { 469 current = (IEEE802154Node) itc.getNode(i); 470 nodeAddrField.insertItemAt(jmri.util.StringUtil.hexStringFromBytes(current.getUserAddress()), i); 471 nodeAddr64Field.insertItemAt(jmri.util.StringUtil.hexStringFromBytes(current.getGlobalAddress()), i); 472 } 473 nodeAddrField.insertItemAt("", 0); 474 nodeAddrField.setEditable(true); 475 nodeAddr64Field.insertItemAt("", 0); 476 } 477 478 // Update the display when the selected node changes. 479 protected void nodeSelected() { 480 nodeAddr64Field.setSelectedIndex(nodeAddrField.getSelectedIndex()); 481 } 482 483 private final static Logger log = LoggerFactory.getLogger(NodeConfigFrame.class); 484 485}