001package jmri.jmrix.cmri.serial.nodeconfigmanager; 002 003import java.awt.*; 004import java.awt.event.*; 005import java.io.IOException; 006import java.util.ArrayList; 007 008import javax.swing.*; 009import javax.swing.border.Border; 010import javax.swing.border.TitledBorder; 011import javax.swing.table.*; 012 013import jmri.jmrix.cmri.CMRISystemConnectionMemo; 014import jmri.jmrix.cmri.serial.SerialNode; 015import jmri.jmrix.cmri.serial.nodeiolist.NodeIOListFrame; 016import jmri.util.davidflanagan.CompatibleHardcopyWriter; 017import jmri.util.swing.JmriJOptionPane; 018 019/** 020 * 021 * Frames for a table view to manage CMRInet node configuration management. c2 022 * Created a table view for node configuration operations. Add, Edit, Delete and 023 * Update are executed from the NodeTableManager. This class was derived from 024 * the NodeConfig class. 025 * 026 * @author Bob Jacobsen Copyright (C) 2004 027 * @author Dave Duchamp Copyright (C) 2004 028 * @author Chuck Catania Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018 029 */ 030public class NodeConfigManagerFrame extends jmri.util.JmriJFrame { 031 032 ArrayList<SerialNode> cmriNode = new ArrayList<>(); 033 public int numConfigNodes = 0; 034 035 public int numBits = 48; // number of bits in assignment table 036 public int numInputBits = 24; // number of input bits for selected node 037 public int numOutputBits = 48; // number of output bits for selected node 038 039 protected int selectedNodeAddr = -1; 040 protected int selectedTableRow = -1; 041 protected boolean doingPrint = false; 042 043 // node select pane items 044 JLabel nodeLabel = new JLabel(Bundle.getMessage("NodeBoxLabel") + " "); 045 046 // node table pane items 047 protected JPanel nodeTablePanel = null; 048 protected Border inputBorder = BorderFactory.createEtchedBorder(); 049 050 protected NodeTableModel nodeTableModel = null; 051 protected JTable nodeTable = null; 052 053 // button pane items 054 JButton addButton = new JButton(Bundle.getMessage("ButtonAdd")); 055 JButton doneButton = new JButton(Bundle.getMessage("ButtonDone")); 056 JButton printButton = new JButton(Bundle.getMessage("PrintButtonText")); 057 058 NodeConfigManagerFrame curFrame; 059 060 protected JTextField nodeAddrField = new JTextField(3); 061 protected JLabel nodeAddrStatic = new JLabel("000"); 062 protected JComboBox<String> nodeTypeBox; 063 protected JTextField receiveDelayField = new JTextField(3); 064 protected JTextField nodeDescription = new JTextField(32); 065 protected JTextField pulseWidthField = new JTextField(4); 066 protected JComboBox<String> cardSizeBox; 067 protected JComboBox<String> cardSize8Box; 068 protected JLabel cardSizeText = new JLabel(" " + Bundle.getMessage("LabelCardSize")); 069 protected JLabel onBoardBytesText = new JLabel(Bundle.getMessage("LabelOnBoardBytes") + " 3 Input Bytes, 6 Output Bytes"); 070 071 protected JButton addNodeButton = new JButton(Bundle.getMessage("ButtonAdd")); 072 protected JButton editNodeButton = new JButton(Bundle.getMessage("ButtonEdit")); 073 protected JButton deleteNodeButton = new JButton(Bundle.getMessage("ButtonDelete")); 074 protected JButton doneNodeButton = new JButton(Bundle.getMessage("ButtonDone")); 075 protected JButton updateNodeButton = new JButton(Bundle.getMessage("ButtonUpdate")); 076 protected JButton cancelNodeButton = new JButton(Bundle.getMessage("ButtonCancel")); 077 078 protected JLabel statusText1 = new JLabel(); 079 protected JLabel statusText2 = new JLabel(); 080 protected JLabel statusText3 = new JLabel(); 081 082 protected JPanel panel2 = new JPanel(); 083 protected JPanel panel2a = new JPanel(); 084 protected JPanel panel2b = new JPanel(); 085 protected JPanel panel2c = new JPanel(); //c2 IOX config 086 protected JPanel panelnodeDescBox = new JPanel(); //c2 node desctipion box 087 protected JPanel panelnodeDesc = new JPanel(); //c2 node description 088 protected JPanel panelnetOpt = new JPanel(); //c2 CMRInet options 089 protected JPanel panelnetOptBox = new JPanel(); //c2 CMRInet options frame 090 protected JPanel panelnodeOpt = new JPanel(); //c2 node options 091 092 protected boolean changedNode = false; // true if a node was changed, deleted, or added 093 protected boolean editMode = false; // true if in edit mode 094 095 protected SerialNode curNode = null; // Serial Node being edited 096 protected int nodeAddress = 0; // Node address 097 protected int nodeType = SerialNode.SMINI; // Node type - default SMINI 098 protected int bitsPerCard = 24; // number of bits per card 099 protected int receiveDelay = 0; // transmission delay 100 protected int pulseWidth = 500; // pulse width for turnout control (milliseconds) 101 protected int num2LSearchLights = 0; // number of 2-lead oscillating searchlights 102 103 protected int numCards = 0; //set by consistency check routine 104 protected int cpNodeOnboard = 4; //Number of fixed bytes(cards) for a cpNode 105 protected int osNodeOnboard = 8; //Number of fixed bytes(cards) for a osNode 106 107 protected boolean errorInStatus1 = false; 108 protected boolean errorInStatus2 = false; 109 110 protected String editStatus1 = Bundle.getMessage("NotesEdit1"); 111 protected String editStatus2 = Bundle.getMessage("NotesEdit2"); 112 protected String editStatus3 = Bundle.getMessage("NotesEdit3"); 113 protected String addStatus1 = Bundle.getMessage("NotesAdd1"); 114 protected String addStatus2 = Bundle.getMessage("NotesAdd2"); 115 protected String addStatus3 = Bundle.getMessage("NotesAdd3"); 116 protected String delStatus1 = Bundle.getMessage("NotesDel1"); 117 protected String delStatus2 = Bundle.getMessage("NotesDel2"); 118 protected String delStatus3 = Bundle.getMessage("NotesDel3"); 119 120 protected String nodeDescText = ""; 121 protected int deleteNodeAddress = 0; 122 123 HandlerClass nodeOptHandler = new HandlerClass(); 124 125 // -------------------------- 126 // CMRInet Options CheckBoxes 127 // -------------------------- 128 protected JCheckBox cbx_cmrinetopt_AUTOPOLL = new JCheckBox(Bundle.getMessage("cmrinetOpt0"), true); 129 protected JCheckBox cbx_cmrinetopt_USECMRIX = new JCheckBox(Bundle.getMessage("cmrinetOpt1")); 130 protected JCheckBox cbx_cmrinetopt_USEBCC = new JCheckBox(Bundle.getMessage("cmrinetOpt2")); 131 protected JCheckBox cbx_cmrinetopt_BIT8 = new JCheckBox(Bundle.getMessage("cmrinetOpt8")); 132 protected JCheckBox cbx_cmrinetopt_BIT15 = new JCheckBox(Bundle.getMessage("cmrinetOpt15")); 133 134 // ------------------------- 135 // cpNode Options CheckBoxes 136 // ------------------------- 137 protected JCheckBox cbx_cpnodeopt_SENDEOT = new JCheckBox(Bundle.getMessage("cpnodeOpt0")); 138 protected JCheckBox cbx_cpnodeopt_BIT1 = new JCheckBox(Bundle.getMessage("cpnodeOpt1")); 139 protected JCheckBox cbx_cpnodeopt_BIT2 = new JCheckBox(Bundle.getMessage("cpnodeOpt2")); 140 protected JCheckBox cbx_cpnodeopt_BIT8 = new JCheckBox(Bundle.getMessage("cpnodeOpt8")); 141 protected JCheckBox cbx_cpnodeopt_BIT15 = new JCheckBox(Bundle.getMessage("cpnodeOpt15")); 142 143 private CMRISystemConnectionMemo _memo = null; 144 145 /** 146 * Constructor method. 147 * @param memo system connection. 148 */ 149 public NodeConfigManagerFrame(CMRISystemConnectionMemo memo) { 150 super(); 151 _memo = memo; 152 curFrame = this; 153 154 // Clear information arrays 155 for (int i = 0; i < 64; i++) { 156 cardType[i] = Bundle.getMessage("CardTypeNone"); // NOI18N 157 } 158 for (int i = 0; i < 48; i++) { 159 searchlightBits[i] = false; 160 firstSearchlight[i] = false; 161 } 162 // addHelpMenu("package.jmri.jmrix.cmri.serial.nodeconfigmanager.NodeConfigManagerFrame", true); // NOI18N duplicate, see initComponents 163 } 164 165 /** 166 * {@inheritDoc} 167 */ 168 @Override 169 public void initComponents() { 170 // set the frame's initial state 171 setTitle(Bundle.getMessage("WindowTitle") + Bundle.getMessage("WindowConnectionMemo")+_memo.getUserName()); // NOI18N 172 setSize(500, 150); 173 174 Container contentPane = getContentPane(); 175 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 176 177 // load the SerialNode data 178 initializeNodes(); 179 180 // Set up the assignment panel 181 nodeTablePanel = new JPanel(); 182 nodeTablePanel.setLayout(new BoxLayout(nodeTablePanel, BoxLayout.Y_AXIS)); 183 184 nodeTableModel = new NodeTableModel(); 185 nodeTable = new JTable(nodeTableModel); 186 187 nodeTable.setShowGrid(true); 188 nodeTable.setGridColor(Color.black); 189 nodeTable.setRowSelectionAllowed(false); 190 nodeTable.setFont(new Font("Arial", Font.PLAIN, 14)); 191 nodeTable.setRowHeight(30); 192 193 nodeTable.getTableHeader().setReorderingAllowed(false); 194 nodeTable.setPreferredScrollableViewportSize(new java.awt.Dimension(300, 350)); 195 TableColumnModel assignmentColumnModel = nodeTable.getColumnModel(); 196 197 DefaultTableCellRenderer dtcen = new DefaultTableCellRenderer(); 198 dtcen.setHorizontalAlignment(SwingConstants.CENTER); 199 DefaultTableCellRenderer dtrt = new DefaultTableCellRenderer(); 200 dtrt.setHorizontalAlignment(SwingConstants.RIGHT); 201 202 TableCellRenderer rendererFromHeader = nodeTable.getTableHeader().getDefaultRenderer(); 203 JLabel headerLabel = (JLabel) rendererFromHeader; 204 headerLabel.setHorizontalAlignment(JLabel.CENTER); 205 headerLabel.setBackground(Color.LIGHT_GRAY); 206 207 TableColumn nodenumColumn = assignmentColumnModel.getColumn(NodeTableModel.NODENUM_COLUMN); 208 nodenumColumn.setMinWidth(40); 209 nodenumColumn.setMaxWidth(80); 210 nodenumColumn.setCellRenderer(dtcen); 211 nodenumColumn.setResizable(false); 212 213 TableColumn nodetypeColumn = assignmentColumnModel.getColumn(NodeTableModel.NODETYPE_COLUMN); 214 nodetypeColumn.setMinWidth(40); 215 nodetypeColumn.setMaxWidth(80); 216 nodetypeColumn.setCellRenderer(dtcen); 217 nodetypeColumn.setResizable(false); 218 219 TableColumn numbitsColumn = assignmentColumnModel.getColumn(NodeTableModel.NUMBITS_COLUMN); 220 numbitsColumn.setMinWidth(40); 221 numbitsColumn.setMaxWidth(120); 222 numbitsColumn.setCellRenderer(dtcen); 223 numbitsColumn.setResizable(false); 224 225 TableColumn numinputsColumn = assignmentColumnModel.getColumn(NodeTableModel.NUMINCARDS_COLUMN); 226 numinputsColumn.setMinWidth(40); 227 numinputsColumn.setMaxWidth(80); 228 numinputsColumn.setCellRenderer(dtcen); 229 numinputsColumn.setResizable(false); 230 231 TableColumn numoutputsColumn = assignmentColumnModel.getColumn(NodeTableModel.NUMOUTCARDS_COLUMN); 232 numoutputsColumn.setMinWidth(10); 233 numoutputsColumn.setMaxWidth(100); 234 numoutputsColumn.setCellRenderer(dtcen); 235 numoutputsColumn.setResizable(false); 236 237 TableColumn numinbytesColumn = assignmentColumnModel.getColumn(NodeTableModel.NUMINBYTES_COLUMN); 238 numinbytesColumn.setMinWidth(10); 239 numinbytesColumn.setMaxWidth(80); 240 numinbytesColumn.setCellRenderer(dtcen); 241 numinbytesColumn.setResizable(false); 242 243 TableColumn numoutbytesColumn = assignmentColumnModel.getColumn(NodeTableModel.NUMOUTBYTES_COLUMN); 244 numoutbytesColumn.setMinWidth(10); 245 numoutbytesColumn.setMaxWidth(100); 246 numoutbytesColumn.setCellRenderer(dtcen); 247 numoutbytesColumn.setResizable(false); 248 249 TableColumn selectColumn = assignmentColumnModel.getColumn(NodeTableModel.SELECT_COLUMN); 250 JComboBox<String> comboBox = new JComboBox<>(); 251 comboBox.addItem(Bundle.getMessage("SelectSelect")); 252 comboBox.addItem(Bundle.getMessage("SelectEdit")); 253 comboBox.addItem(Bundle.getMessage("SelectInfo")); 254 comboBox.addItem(Bundle.getMessage("SelectDelete")); 255 selectColumn.setCellEditor(new DefaultCellEditor(comboBox)); 256 257 selectColumn.setMinWidth(40); 258 selectColumn.setMaxWidth(90); 259 selectColumn.setCellRenderer(dtcen); 260 selectColumn.setResizable(false); 261 262 TableColumn nodedescColumn = assignmentColumnModel.getColumn(NodeTableModel.NODEDESC_COLUMN); 263 nodedescColumn.setMinWidth(40); 264 nodedescColumn.setMaxWidth(350); 265 nodedescColumn.setResizable(true); 266 JScrollPane nodeTableScrollPane = new JScrollPane(nodeTable); 267 268 Border inputBorderTitled = BorderFactory.createTitledBorder(inputBorder, 269 " ", 270 TitledBorder.LEFT, TitledBorder.ABOVE_TOP); 271 nodeTablePanel.add(nodeTableScrollPane, BorderLayout.CENTER); 272 nodeTablePanel.setBorder(inputBorderTitled); 273 setPreferredSize(new Dimension(950, 550)); 274 275 nodeTable.setAutoCreateRowSorter(true); 276 nodeTable.getRowSorter().toggleSortOrder(NodeTableModel.NODENUM_COLUMN); 277 278 contentPane.add(nodeTablePanel); 279 280 // Setup main window buttons 281 JPanel panel3 = new JPanel(); 282 panel3.setLayout(new BoxLayout(panel3, FlowLayout.RIGHT)); 283 panel3.setPreferredSize(new Dimension(950, 50)); 284 285 // Set up Add button 286 addButton.setVisible(true); 287 addButton.setToolTipText(Bundle.getMessage("AddButtonTip")); 288 addButton.addActionListener((java.awt.event.ActionEvent e) -> { 289 addButtonActionPerformed(e); 290 }); 291 panel3.add(addButton); 292 293 // Set up Print button 294 printButton.setVisible(true); 295 printButton.setToolTipText(Bundle.getMessage("PrintButtonTip")); 296 if (numConfigNodes > 0) { 297 printButton.addActionListener((java.awt.event.ActionEvent e) -> { 298 printButtonActionPerformed(e); 299 }); 300 } 301 panel3.add(printButton); 302 303 // Set up Done button 304 doneButton.setVisible(true); 305 doneButton.setToolTipText(Bundle.getMessage("DoneButtonTip")); 306 doneButton.addActionListener((java.awt.event.ActionEvent e) -> { 307 doneButtonActionPerformed(); 308 }); 309 panel3.add(doneButton); 310 311 contentPane.add(panel3); 312 addHelpMenu("package.jmri.jmrix.cmri.serial.nodeconfigmanager.NodeConfigManagerFrame", true); 313 // pack for display 314 pack(); 315 nodeTablePanel.setVisible(true); 316 } 317 318 /** 319 * Get the selected node address from the node table. 320 * @return selected node ID. 321 */ 322 public int getSelectedNodeAddr() { 323 return (Integer) nodeTable.getValueAt(nodeTable.getSelectedRow(), 0); 324 } 325 326 /** 327 * Handle the done button click. 328 */ 329 public void doneButtonActionPerformed() { 330 changedNode = false; 331 setVisible(false); 332 dispose(); 333 } 334 335 public void addButtonActionPerformed(ActionEvent e) { 336 NodeConfigManagerFrame f = new NodeConfigManagerFrame(_memo); 337 try { 338 f.initNodeConfigWindow(); 339 } catch (Exception ex) { 340 log.info("addButtonActionPerformed Exception-C2: {}", ex.toString()); 341 } 342 f.nodeTableModel = nodeTableModel; 343 f.initNodeVariables(); 344 f.buttonSet_ADD(); 345 f.setLocation(100, 100); 346 f.setVisible(true); 347 } 348 349 /** 350 * Print. 351 * 352 * @param e the triggering event 353 */ 354 public void printButtonActionPerformed(java.awt.event.ActionEvent e) { 355 int[] colWidth = new int[10]; 356 // initialize column widths 357 TableColumnModel nodeTableColumnModel = nodeTable.getColumnModel(); 358 colWidth[0] = nodeTableColumnModel.getColumn(NodeTableModel.NODENUM_COLUMN).getWidth(); 359 colWidth[1] = nodeTableColumnModel.getColumn(NodeTableModel.NODETYPE_COLUMN).getWidth(); 360 colWidth[2] = nodeTableColumnModel.getColumn(NodeTableModel.NUMBITS_COLUMN).getWidth(); 361 colWidth[3] = nodeTableColumnModel.getColumn(NodeTableModel.NUMINCARDS_COLUMN).getWidth(); 362 colWidth[4] = nodeTableColumnModel.getColumn(NodeTableModel.NUMOUTCARDS_COLUMN).getWidth(); 363 colWidth[5] = nodeTableColumnModel.getColumn(NodeTableModel.SELECT_COLUMN).getWidth(); 364 colWidth[6] = nodeTableColumnModel.getColumn(NodeTableModel.NUMBITS_COLUMN).getWidth(); 365 colWidth[7] = nodeTableColumnModel.getColumn(NodeTableModel.NUMBITS_COLUMN).getWidth(); 366 colWidth[8] = nodeTableColumnModel.getColumn(NodeTableModel.NUMBITS_COLUMN).getWidth(); 367 colWidth[9] = nodeTableColumnModel.getColumn(NodeTableModel.NUMBITS_COLUMN).getWidth(); 368 369 // set up a page title 370 String head = "CMRInet Node Table"; 371 // initialize a printer writer 372 CompatibleHardcopyWriter writer = null; 373 try { 374 writer = new CompatibleHardcopyWriter(curFrame, head, 10, .8, .5, .5, .5, false); 375 } catch (CompatibleHardcopyWriter.PrintCanceledException ex) { 376 return; 377 } 378 writer.increaseLineSpacing(20); 379 // print the assignments 380 (nodeTableModel).printTable(writer, colWidth); 381 } 382 383 /** 384 * Edit node table selection. 385 */ 386 public void editActionSelected() { 387 selectedNodeAddr = getSelectedNodeAddr(); 388 389 NodeConfigManagerFrame f = new NodeConfigManagerFrame(_memo); 390 f.nodeTableModel = nodeTableModel; 391 f.selectedTableRow = nodeTable.convertRowIndexToModel(nodeTable.getSelectedRow()); 392 393 try { 394 f.initNodeConfigWindow(); 395 f.editNodeButtonActionPerformed(selectedNodeAddr); 396 } catch (Exception ex) { 397 log.info("editActionSelected", ex); 398 399 } 400 f.setLocation(200, 200); 401 f.buttonSet_EDIT(); 402 f.setVisible(true); 403 } 404 405 /** 406 * Handle the delete button click 407 */ 408 public void deleteActionSelected() { 409 selectedNodeAddr = getSelectedNodeAddr(); 410 411 NodeConfigManagerFrame f = new NodeConfigManagerFrame(_memo); 412 f.nodeTableModel = nodeTableModel; 413 f.selectedTableRow = nodeTable.convertRowIndexToModel(nodeTable.getSelectedRow()); 414 try { 415 f.initNodeConfigWindow(); 416 f.deleteNodeButtonActionPerformed(selectedNodeAddr); 417 } catch (Exception ex) { 418 log.info("deleteActionSelected", ex); 419 420 } 421 f.setLocation(200, 200); 422 f.buttonSet_DELETE(); 423 f.setVisible(true); 424 } 425 426 /** 427 * Handle info action. 428 */ 429 public void infoActionSelected() { 430 selectedNodeAddr = getSelectedNodeAddr(); 431 432 NodeIOListFrame f = new NodeIOListFrame(_memo); 433 try { 434 f.initComponents(); 435 f.displayNodeIOBits(selectedNodeAddr); 436 } catch (Exception ex) { 437 log.info("infoActionSelected Exception-C2: {}", ex.toString()); 438 439 } 440 f.setLocation(100, 100); 441 f.setVisible(true); 442 } 443 444 /** 445 * Method to initialize configured nodes and sets up the node select combo 446 * box 447 */ 448 public void initializeNodes() { 449 // get all configured nodes 450 if (!cmriNode.isEmpty()) { 451 cmriNode.clear(); 452 } 453 454 SerialNode node = (SerialNode) _memo.getTrafficController().getNode(0); 455 int index = 1; 456 while (node != null) { 457 cmriNode.add(node); 458 node = (SerialNode) _memo.getTrafficController().getNode(index); 459 index++; 460 } 461 462 numConfigNodes = cmriNode.size(); 463 } 464 465 /** 466 * Set up table for displaying bit assignments 467 */ 468 public class NodeTableModel extends AbstractTableModel { 469 470 @Override 471 public String getColumnName(int c) { 472 return nodeTableColumnsNames[c]; 473 } 474 475 @Override 476 public Class<?> getColumnClass(int c) { 477 switch (c) { 478 case NODENUM_COLUMN: 479 return Integer.class; 480 481 case NODETYPE_COLUMN: 482 return String.class; 483 484 case NUMBITS_COLUMN: 485 case NUMINCARDS_COLUMN: 486 case NUMOUTCARDS_COLUMN: 487 case NUMINBYTES_COLUMN: 488 case NUMOUTBYTES_COLUMN: 489 return Integer.class; 490 491 case SELECT_COLUMN: 492 return String.class; 493 494 case NODEDESC_COLUMN: 495 default: 496 return String.class; 497 } 498 } 499 500 @Override 501 public boolean isCellEditable(int r, int c) { 502 if (c == SELECT_COLUMN) { 503 return true; 504 } else { 505 return false; 506 } 507 } 508 509 @Override 510 public int getColumnCount() { 511 return NUM_COLUMNS; 512 } 513 514 @Override 515 public int getRowCount() { 516 return cmriNode.size(); 517 } 518 519 public void removeRow(int row) { 520 cmriNode.remove(row); 521 numConfigNodes = cmriNode.size(); 522 fireTableRowsDeleted(row, row); 523 } 524 525 public void addRow(SerialNode newNode) { 526 cmriNode.add(newNode); 527 numConfigNodes = cmriNode.size(); 528 fireTableDataChanged(); 529 } 530 531 public void changeRow(int row, SerialNode aNode) { 532 cmriNode.set(row, aNode); 533 fireTableDataChanged(); 534 } 535 536 @Override 537 public void setValueAt(Object value, int row, int col) { 538 if (col == SELECT_COLUMN) { 539 if (Bundle.getMessage("SelectEdit").equals(value)) { 540 editActionSelected(); 541 } else if (Bundle.getMessage("SelectInfo").equals(value)) { 542 infoActionSelected(); 543 } else if (Bundle.getMessage("SelectDelete").equals(value)) { 544 deleteActionSelected(); 545 } 546 } else { 547 log.info("setValueAt Row{} value {}", row, value); 548 } 549 fireTableDataChanged(); 550 } 551 552 @Override 553 public Object getValueAt(int r, int c) { 554 switch (c) { 555 case NODENUM_COLUMN: 556 if (!doingPrint) { 557 return cmriNode.get(r).getNodeAddress(); 558 } else { 559 return Integer.toString(cmriNode.get(r).getNodeAddress()); 560 } 561 562 case NODETYPE_COLUMN: 563 return " " + nodeTableTypes[cmriNode.get(r).getNodeType()]; 564 565 case NUMBITS_COLUMN: 566 return Integer.toString(cmriNode.get(r).getNumBitsPerCard()); 567 568 case NUMINCARDS_COLUMN: 569 if (cmriNode.get(r).getNodeType() == SerialNode.SMINI) { 570 return Integer.toString(cmriNode.get(r).numInputCards() * 3); 571 } else { 572 return Integer.toString(cmriNode.get(r).numInputCards()); 573 } 574 575 case NUMOUTCARDS_COLUMN: 576 if (cmriNode.get(r).getNodeType() == SerialNode.SMINI) { 577 return Integer.toString(cmriNode.get(r).numOutputCards() * 3); 578 } else { 579 return Integer.toString(cmriNode.get(r).numOutputCards()); 580 } 581 582 case NUMINBYTES_COLUMN: 583 return Integer.toString((cmriNode.get(r).getNumBitsPerCard()) * cmriNode.get(r).numInputCards()); 584 585 case NUMOUTBYTES_COLUMN: 586 return Integer.toString((cmriNode.get(r).getNumBitsPerCard()) * cmriNode.get(r).numOutputCards()); 587 588 case SELECT_COLUMN: 589 590 return "Select"; 591 case NODEDESC_COLUMN: 592 593 return " " + cmriNode.get(r).getcmriNodeDesc(); 594 default: 595 return ""; 596 } 597 } 598 599 public static final int NODENUM_COLUMN = 0; 600 public static final int NODETYPE_COLUMN = 1; 601 public static final int NUMBITS_COLUMN = 2; 602 public static final int NUMINCARDS_COLUMN = 3; 603 public static final int NUMOUTCARDS_COLUMN = 4; 604 public static final int NUMINBYTES_COLUMN = 5; 605 public static final int NUMOUTBYTES_COLUMN = 6; 606 public static final int SELECT_COLUMN = 7; 607 public static final int NODEDESC_COLUMN = 8; 608 public static final int NUM_COLUMNS = NODEDESC_COLUMN + 1; 609 610// private String[] pollStatus = {"ERROR", "IDLE", "POLLING", "TIMEOUT", "SLOW POLL"}; 611 /** 612 * Method to print or print preview the assignment table. Printed in 613 * proportionately sized columns across the page with headings and 614 * vertical lines between each column. Data is word wrapped within a 615 * column. Can only handle 4 columns of data as strings. Adapted from 616 * routines in BeanTableDataModel.java by Bob Jacobsen and Dennis Miller 617 * @param w CompatibleHardcopyWriter instance. 618 * @param colWidth column width array. 619 */ 620 public void printTable(CompatibleHardcopyWriter w, int colWidth[]) { 621 // determine the column sizes - proportionately sized, with space between for lines 622 int[] columnSize = new int[NUM_COLUMNS]; 623 int charPerLine = w.getCharactersPerLine(); 624 int tableLineWidth = 0; // table line width in characters 625 int totalColWidth = 0; 626 627 doingPrint = true; 628 for (int j = 0; j < NUM_COLUMNS; j++) { 629 if (j != SELECT_COLUMN) { 630 totalColWidth += colWidth[j]; 631 } 632 } 633 float ratio = ((float) charPerLine) / ((float) totalColWidth); 634 for (int j = 0; j < NUM_COLUMNS; j++) { 635 if (j != SELECT_COLUMN) { 636 columnSize[j] = ((int) (colWidth[j] * ratio)) - 1; 637 tableLineWidth += (columnSize[j] + 1); 638 } 639 } 640 641 // Draw horizontal dividing line 642 w.write(w.getCurrentLineNumber(), 0, w.getCurrentLineNumber(), tableLineWidth); 643 644 // print the column header labels 645 String[] columnStrings = new String[NUM_COLUMNS]; 646 // Put each column header in the array 647 for (int i = 0; i < NUM_COLUMNS; i++) { 648 if (i != SELECT_COLUMN) { 649 columnStrings[i] = this.getColumnName(i); 650 } 651 } 652 // w.setFontStyle(Font.BOLD); 653 printColumns(w, columnStrings, columnSize); 654 w.setFontStyle(Font.PLAIN); 655 656 // draw horizontal line 657 w.write(w.getCurrentLineNumber(), 0, w.getCurrentLineNumber(), tableLineWidth); 658 // now print each row of data 659 String[] spaces = new String[NUM_COLUMNS]; 660 // create base strings the width of each of the columns 661 for (int k = 0; k < NUM_COLUMNS; k++) { 662 if (k != SELECT_COLUMN) { 663 spaces[k] = ""; 664 for (int i = 0; i < columnSize[k]; i++) { 665 spaces[k] = spaces[k] + " "; 666 } 667 } 668 } 669 for (int i = 0; i < this.getRowCount(); i++) { 670 for (int j = 0; j < NUM_COLUMNS; j++) { 671 if (j != SELECT_COLUMN) { 672 //check for special, null contents 673 if (this.getValueAt(i, j) == null) { 674 columnStrings[j] = spaces[j]; 675 } else { 676 columnStrings[j] = (String) this.getValueAt(i, j); 677 } 678 } 679 } 680 printColumns(w, columnStrings, columnSize); 681 // draw horizontal line 682 w.write(w.getCurrentLineNumber(), 0, w.getCurrentLineNumber(), tableLineWidth); 683 } 684 doingPrint = false; 685 w.close(); 686 } 687 688 protected void printColumns(CompatibleHardcopyWriter w, String columnStrings[], int columnSize[]) { 689 String columnString = ""; 690 StringBuilder lineString = new StringBuilder(""); 691 String[] spaces = new String[NUM_COLUMNS]; 692 // create base strings the width of each of the columns 693 for (int k = 0; k < NUM_COLUMNS; k++) { 694 if (k != SELECT_COLUMN) { 695 spaces[k] = ""; 696 for (int i = 0; i < columnSize[k]; i++) { 697 spaces[k] = spaces[k] + " "; 698 } 699 } 700 } 701 // loop through each column 702 boolean complete = false; 703 while (!complete) { 704 complete = true; 705 for (int i = 0; i < NUM_COLUMNS; i++) { 706 if (i != SELECT_COLUMN) { 707 // if the column string is too wide cut it at word boundary (valid delimiters are space, - and _) 708 // use the initial part of the text,pad it with spaces and place the remainder back in the array 709 // for further processing on next line 710 // if column string isn't too wide, pad it to column width with spaces if needed 711 if (columnStrings[i].length() > columnSize[i]) { 712 // this column string will not fit on one line 713 boolean noWord = true; 714 for (int k = columnSize[i]; k >= 1; k--) { 715 if (columnStrings[i].substring(k - 1, k).equals(" ") 716 || columnStrings[i].substring(k - 1, k).equals("-") 717 || columnStrings[i].substring(k - 1, k).equals("_")) { 718 columnString = columnStrings[i].substring(0, k) 719 + spaces[i].substring(columnStrings[i].substring(0, k).length()); 720 columnStrings[i] = columnStrings[i].substring(k); 721 noWord = false; 722 complete = false; 723 break; 724 } 725 } 726 if (noWord) { 727 columnString = columnStrings[i].substring(0, columnSize[i]); 728 columnStrings[i] = columnStrings[i].substring(columnSize[i]); 729 complete = false; 730 } 731 } else { 732 // this column string will fit on one line 733 columnString = columnStrings[i] + spaces[i].substring(columnStrings[i].length()); 734 columnStrings[i] = ""; 735 } 736 lineString.append(columnString).append(" "); 737 } 738 } 739 try { 740 w.write(lineString.toString()); 741 //write vertical dividing lines 742 int iLine = w.getCurrentLineNumber(); 743 for (int i = 0, k = 0; i < w.getCharactersPerLine(); k++) { 744 if (k != SELECT_COLUMN) { 745 w.write(iLine, i, iLine + 1, i); 746 if (k < NUM_COLUMNS) { 747 i = i + columnSize[k] + 1; 748 } else { 749 i = w.getCharactersPerLine(); 750 } 751 } 752 } 753 w.write("\n"); 754 lineString = new StringBuilder(""); 755 } catch (IOException e) { 756 log.warn("error during printing: ", e); 757 } 758 } 759 } 760 } 761 762 private String[] nodeTableColumnsNames 763 = {"Address", " Type", "Bits per Card", "IN Cards", "OUT Cards", "IN Bits", "OUT Bits", " ", " Description"}; 764 765 private String[] nodeTableTypes = {"--", "SMINI", "SUSIC", "CPNODE", "CPMEGA", "ESP32Node"}; 766 767 /* 768 * ---------------------------------------------------------- 769 * ------ Node Configuration Management Routines ------ 770 * ---------------------------------------------------------- 771 */ 772 public void initNodeVariables() { 773 // Clear information arrays 774 for (int i = 0; i < 64; i++) { 775 cardType[i] = Bundle.getMessage("CardTypeNone"); 776 } 777 778 //cpMega onboard bytes held in a separate array and will be copied 779 //to CardArray. 780 for (int i = 0; i < 16; i++) { 781 onBoardType[i] = Bundle.getMessage("CardTypeNone"); 782 } 783 784 for (int i = 0; i < 48; i++) { 785 searchlightBits[i] = false; 786 firstSearchlight[i] = false; 787 } 788 for (int i = 0; i < SerialNode.NUMCMRINETOPTS; i++) { 789 cmrinetOpts[i] = 0; 790 } 791 for (int i = 0; i < SerialNode.NUMCPNODEOPTS; i++) { 792 cpnodeOpts[i] = 0; 793 } 794 nodeDescText = ""; 795 } 796 797 /** 798 * Initialize the node configuration window This window is a template for 799 * ADD,EDIT,DELETE node operations 800 */ 801 public void initNodeConfigWindow() { 802 setTitle(Bundle.getMessage("WindowTitle")); 803 Container contentPane = getContentPane(); 804 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 805 806 // Set up node address and node type 807 JPanel panel1 = new JPanel(); 808 panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS)); 809 JPanel panel11 = new JPanel(); 810 panel11.setLayout(new FlowLayout()); 811 panel11.add(new JLabel(Bundle.getMessage("LabelNodeAddress") + " ")); 812 panel11.add(nodeAddrField); 813 nodeAddrField.setToolTipText(Bundle.getMessage("TipNodeAddress")); 814 nodeAddrField.setText("-1"); 815 panel11.add(nodeAddrStatic); 816 nodeAddrStatic.setVisible(false); 817 panel11.add(new JLabel(" " + Bundle.getMessage("LabelNodeType") + " ")); 818 nodeTypeBox = new JComboBox<>(); 819 panel11.add(nodeTypeBox); 820 nodeTypeBox.addItem("SMINI"); 821 nodeTypeBox.addItem("USIC_SUSIC"); 822 nodeTypeBox.addItem("CPNODE"); 823 nodeTypeBox.addItem("CPMEGA"); 824 nodeTypeBox.addItem("ESP32Node"); 825 826 /* 827 * Here add code for other types of nodes 828 */ 829 nodeTypeBox.addActionListener(new java.awt.event.ActionListener() { 830 @Override 831 public void actionPerformed(java.awt.event.ActionEvent event) { 832 String s = (String) nodeTypeBox.getSelectedItem(); 833 834 if (s.equals("SMINI")) { 835 panel2.setVisible(false); 836 panel2a.setVisible(true); 837 panel2b.setVisible(false); 838 panel2c.setVisible(false); 839 cardSizeText.setVisible(false); 840 cardSizeBox.setVisible(false); 841 cardSize8Box.setVisible(false); 842 panelnodeDescBox.setVisible(true); 843 panelnodeDesc.setVisible(true); 844 panelnetOpt.setVisible(true); 845 panelnetOptBox.setVisible(true); 846 panelnodeOpt.setVisible(false); 847 nodeType = SerialNode.SMINI; 848 onBoardBytesText.setText(Bundle.getMessage("LabelOnBoardBytes") + " 3 Input, 6 Output"); 849 } else if (s.equals("USIC_SUSIC")) { 850 panel2.setVisible(true); 851 panel2a.setVisible(false); 852 panel2b.setVisible(false); 853 panel2c.setVisible(false); 854 cardSizeText.setVisible(true); 855 cardSizeBox.setVisible(true); 856 cardSize8Box.setVisible(false); 857 panelnodeDescBox.setVisible(true); 858 panelnodeDesc.setVisible(true); 859 panelnetOpt.setVisible(true); 860 panelnetOptBox.setVisible(true); 861 panelnodeOpt.setVisible(false); 862 nodeType = SerialNode.USIC_SUSIC; 863 onBoardBytesText.setText(" "); 864 } else if (s.equals("CPNODE")) { 865 panel2.setVisible(false); 866 panel2a.setVisible(false); 867 panel2b.setVisible(true); 868 panel2c.setVisible(false); // IOX bytes 869 cardSizeText.setVisible(true); 870 cardSizeBox.setVisible(false); 871 cardSize8Box.setVisible(true); 872 panelnodeDescBox.setVisible(true); 873 panelnodeDesc.setVisible(true); 874 panelnetOpt.setVisible(true); 875 panelnetOptBox.setVisible(true); 876 panelnodeOpt.setVisible(true); 877 nodeType = SerialNode.CPNODE; 878 cpNodeOnboard = 4; 879 onBoardBytesText.setText(Bundle.getMessage("LabelOnBoardBytes") + " 2 Bytes"); 880 } else if (s.equals("CPMEGA")) { 881 panel2.setVisible(false); 882 panel2a.setVisible(false); 883 panel2b.setVisible(true); 884 panel2c.setVisible(true); // IOX bytes 885 cardSizeText.setVisible(true); 886 cardSizeBox.setVisible(false); 887 cardSize8Box.setVisible(true); 888 panelnodeDescBox.setVisible(true); 889 panelnodeDesc.setVisible(true); 890 panelnetOpt.setVisible(true); 891 panelnetOptBox.setVisible(true); 892 panelnodeOpt.setVisible(true); 893 nodeType = SerialNode.CPMEGA; 894 cpNodeOnboard = 4; 895 onBoardBytesText.setText(Bundle.getMessage("LabelOnBoardBytes") + " 8 Bytes"); 896 } else if (s.equals("ESP32Node")) { 897 panel2.setVisible(false); 898 panel2a.setVisible(false); 899 panel2b.setVisible(true); // IOX-style card grid -- ALL 16 cards, no onboard reservation 900 panel2c.setVisible(false); // no separate onboard-byte grid -- ESP32Node has no onboard I/O 901 cardSizeText.setVisible(true); 902 cardSizeBox.setVisible(false); 903 cardSize8Box.setVisible(true); 904 panelnodeDescBox.setVisible(true); 905 panelnodeDesc.setVisible(true); 906 panelnetOpt.setVisible(true); 907 panelnetOptBox.setVisible(true); 908 panelnodeOpt.setVisible(true); 909 nodeType = SerialNode.ESP32NODE; 910 cpNodeOnboard = 0; 911 onBoardBytesText.setText(Bundle.getMessage("LabelOnBoardBytes") + " None -- 8 MCP23017 chips (0x20-0x27), 16 bytes"); 912 } 913 /* 914 * Here add code for other types of nodes 915 */ 916 917 // reset notes as appropriate 918 resetNotes(); 919 } 920 }); 921 nodeTypeBox.setToolTipText(Bundle.getMessage("TipNodeType")); 922 923 JPanel panel12 = new JPanel(); 924 panel12.setLayout(new FlowLayout()); 925 panel12.add(new JLabel(Bundle.getMessage("LabelDelay") + " ")); 926 panel12.add(receiveDelayField); 927 receiveDelayField.setToolTipText(Bundle.getMessage("TipDelay")); 928 receiveDelayField.setText("0"); 929 panel12.add(cardSizeText); 930 cardSizeBox = new JComboBox<>(); 931 cardSize8Box = new JComboBox<>(); 932 panel12.add(cardSizeBox); 933 panel12.add(cardSize8Box); 934 cardSizeBox.addItem(Bundle.getMessage("CardSize24")); 935 cardSizeBox.addItem(Bundle.getMessage("CardSize32")); 936 cardSize8Box.addItem(Bundle.getMessage("CardSize8")); 937 /* 938 * Here add code for other types of nodes 939 */ 940 941 cardSizeBox.addActionListener(new java.awt.event.ActionListener() { 942 @Override 943 public void actionPerformed(java.awt.event.ActionEvent event) { 944 String s = (String) cardSizeBox.getSelectedItem(); 945 if (s.equals(Bundle.getMessage("CardSize24"))) { 946 bitsPerCard = 24; 947 } else if (s.equals(Bundle.getMessage("CardSize32"))) { 948 bitsPerCard = 32; 949 } else if (s.equals(Bundle.getMessage("CardSize8"))) { 950 bitsPerCard = 8; 951 } 952 // here add code for other node types, if required 953 } 954 }); 955 cardSizeBox.setToolTipText(Bundle.getMessage("TipCardSize")); 956 cardSizeText.setVisible(false); 957 cardSizeBox.setVisible(false); 958 cardSize8Box.setVisible(false); 959 960 JPanel panel13 = new JPanel(); 961 panel13.setLayout(new FlowLayout()); 962 panel13.add(new JLabel(Bundle.getMessage("LabelPulseWidth") + " ")); 963 panel13.add(pulseWidthField); 964 pulseWidthField.setToolTipText(Bundle.getMessage("TipPulseWidth")); 965 pulseWidthField.setText("500"); 966 panel13.add(new JLabel(Bundle.getMessage("LabelMilliseconds"))); 967 968 JPanel panel14 = new JPanel(); 969 panel14.add(onBoardBytesText); 970 panel14.setVisible(true); 971 972 // Load the top half of the common window 973 panel1.add(panel11); 974 panel1.add(panel12); 975 panel1.add(panel13); 976 panel1.add(panel14); 977 contentPane.add(panel1); 978 979 // Set up USIC/SUSIC card type configuration table 980 JPanel panel21 = new JPanel(); 981 panel21.setLayout(new BoxLayout(panel21, BoxLayout.Y_AXIS)); 982 panel21.add(new JLabel(Bundle.getMessage("HintCardTypePartA"))); 983 panel21.add(new JLabel(" " + Bundle.getMessage("HintCardTypePartB"))); 984 panel21.add(new JLabel(" " + Bundle.getMessage("HintCardTypePartC"))); 985 panel21.add(new JLabel(" ")); 986 panel21.add(new JLabel(Bundle.getMessage("HintCardTypePartD"))); 987 panel21.add(new JLabel(" " + Bundle.getMessage("HintCardTypePartE"))); 988 panel21.add(new JLabel(" " + Bundle.getMessage("HintCardTypePartF"))); 989 panel2.add(panel21); 990 TableModel cardConfigModel = new CardConfigModel(); 991 JTable cardConfigTable = new JTable(cardConfigModel); 992 cardConfigTable.setRowSelectionAllowed(false); 993 cardConfigTable.setPreferredScrollableViewportSize(new java.awt.Dimension(180, 95)); 994 995 JComboBox<String> cardTypeCombo = new JComboBox<>(); 996 cardTypeCombo.addItem(Bundle.getMessage("CardTypeOutput")); 997 cardTypeCombo.addItem(Bundle.getMessage("CardTypeInput")); 998 cardTypeCombo.addItem(Bundle.getMessage("CardTypeNone")); 999 1000 TableColumnModel typeColumnModel = cardConfigTable.getColumnModel(); 1001 TableColumn addressColumn = typeColumnModel.getColumn(CardConfigModel.ADDRESS_COLUMN); 1002 addressColumn.setMinWidth(70); 1003 addressColumn.setMaxWidth(80); 1004 TableColumn cardTypeColumn = typeColumnModel.getColumn(CardConfigModel.TYPE_COLUMN); 1005 cardTypeColumn.setCellEditor(new DefaultCellEditor(cardTypeCombo)); 1006 cardTypeColumn.setResizable(false); 1007 cardTypeColumn.setMinWidth(90); 1008 cardTypeColumn.setMaxWidth(100); 1009 1010 JScrollPane cardScrollPane = new JScrollPane(cardConfigTable); 1011 panel2.add(cardScrollPane, BorderLayout.CENTER); 1012 contentPane.add(panel2); 1013 panel2.setVisible(false); 1014 1015 // Set up SMINI oscillating 2-lead searchlight configuration table 1016 JPanel panel2a1 = new JPanel(); 1017 panel2a1.setLayout(new BoxLayout(panel2a1, BoxLayout.Y_AXIS)); 1018 panel2a1.add(new JLabel(Bundle.getMessage("HintSearchlightPartA"))); 1019 panel2a1.add(new JLabel(" " + Bundle.getMessage("HintSearchlightPartB"))); 1020 panel2a1.add(new JLabel(" " + Bundle.getMessage("HintSearchlightPartC"))); 1021 panel2a1.add(new JLabel(" ")); 1022 panel2a1.add(new JLabel(Bundle.getMessage("HintSearchlightPartD"))); 1023 panel2a1.add(new JLabel(" " + Bundle.getMessage("HintSearchlightPartE"))); 1024 panel2a1.add(new JLabel(" " + Bundle.getMessage("HintSearchlightPartF"))); 1025 panel2a.add(panel2a1); 1026 1027 TableModel searchlightConfigModel = new SearchlightConfigModel(); 1028 JTable searchlightConfigTable = new JTable(searchlightConfigModel); 1029 searchlightConfigTable.setRowSelectionAllowed(false); 1030 searchlightConfigTable.setPreferredScrollableViewportSize(new java.awt.Dimension(208, 100)); 1031 TableColumnModel searchlightColumnModel = searchlightConfigTable.getColumnModel(); 1032 TableColumn portColumn = searchlightColumnModel.getColumn(SearchlightConfigModel.PORT_COLUMN); 1033 portColumn.setMinWidth(90); 1034 portColumn.setMaxWidth(100); 1035 JScrollPane searchlightScrollPane = new JScrollPane(searchlightConfigTable); 1036 panel2a.add(searchlightScrollPane, BorderLayout.CENTER); 1037 contentPane.add(panel2a); 1038 panel2.setVisible(false); 1039 1040 // Set up CPMEGA on board byte I/O assignments 1041 JPanel panel2b3 = new JPanel(); 1042 panel2b3.setLayout(new BoxLayout(panel2b3, BoxLayout.Y_AXIS)); 1043 panel2b3.add(new JLabel("Assign Onboard Bytes")); 1044 panel2c.add(panel2b3); 1045 1046 TableModel osnodeConfigModel = new OSnodeConfigModel(); 1047 JTable osnodeConfigTable = new JTable(osnodeConfigModel); 1048 osnodeConfigTable.setRowSelectionAllowed(false); 1049 osnodeConfigTable.setPreferredScrollableViewportSize(new java.awt.Dimension(170, 95)); //160 1050 1051 JComboBox<String> osnodeTypeCombo = new JComboBox<>(); 1052 osnodeTypeCombo.addItem(Bundle.getMessage("CardTypeOutput")); 1053 osnodeTypeCombo.addItem(Bundle.getMessage("CardTypeInput")); 1054 osnodeTypeCombo.addItem(Bundle.getMessage("CardTypeNone")); 1055 1056 TableColumnModel osnodePortModel = osnodeConfigTable.getColumnModel(); 1057 TableColumn x11Column = osnodePortModel.getColumn(OSnodeConfigModel.CARDNUM_COLUMN); 1058 x11Column.setMinWidth(50); 1059 x11Column.setMaxWidth(90); 1060 TableColumn x21Column = osnodePortModel.getColumn(OSnodeConfigModel.CARDTYPE_COLUMN); 1061 x21Column.setCellEditor(new DefaultCellEditor(osnodeTypeCombo)); 1062 x21Column.setResizable(false); 1063 x21Column.setMinWidth(80); 1064 x21Column.setMaxWidth(100); 1065 1066 JScrollPane osnodeScrollPane = new JScrollPane(osnodeConfigTable); 1067 panel2c.add(osnodeScrollPane, BorderLayout.CENTER); 1068 contentPane.add(panel2c); 1069 panel2.setVisible(false); 1070 1071 // Set up I/O Expander (IOX) port assignments 1072 JPanel panel2b1 = new JPanel(); 1073 panel2b1.setLayout(new BoxLayout(panel2b1, BoxLayout.Y_AXIS)); 1074 panel2b1.add(new JLabel("Assign IOX Ports")); 1075 1076 panel2b.add(panel2b1); 1077 1078 TableModel cpnodeConfigModel = new CPnodeConfigModel(); 1079 JTable cpnodeConfigTable = new JTable(cpnodeConfigModel); 1080 cpnodeConfigTable.setRowSelectionAllowed(false); 1081 cpnodeConfigTable.setPreferredScrollableViewportSize(new java.awt.Dimension(240, 130)); //160 1082 1083 JComboBox<String> cpnodeTypeCombo = new JComboBox<>(); 1084 cpnodeTypeCombo.addItem(Bundle.getMessage("CardTypeOutput")); 1085 cpnodeTypeCombo.addItem(Bundle.getMessage("CardTypeInput")); 1086 cpnodeTypeCombo.addItem(Bundle.getMessage("CardTypeNone")); 1087 1088 TableColumnModel cpnodePortModel = cpnodeConfigTable.getColumnModel(); 1089 TableColumn x0Column = cpnodePortModel.getColumn(CPnodeConfigModel.CARD_COLUMN); 1090 x0Column.setMinWidth(30); 1091 x0Column.setMaxWidth(50); 1092 TableColumn x1Column = cpnodePortModel.getColumn(CPnodeConfigModel.CARDNUM_COLUMN); 1093 x1Column.setMinWidth(70); 1094 x1Column.setMaxWidth(120); 1095 TableColumn x2Column = cpnodePortModel.getColumn(CPnodeConfigModel.CARDTYPE_COLUMN); 1096 x2Column.setCellEditor(new DefaultCellEditor(cpnodeTypeCombo)); 1097 x2Column.setResizable(false); 1098 x2Column.setMinWidth(80); 1099 x2Column.setMaxWidth(100); 1100 1101 JScrollPane cpnodeScrollPane = new JScrollPane(cpnodeConfigTable); 1102 panel2b.add(cpnodeScrollPane, BorderLayout.CENTER); 1103 contentPane.add(panel2b); 1104 panel2b.setVisible(false); 1105 1106 // node Description field - all node types have this field 1107 panelnodeDescBox.setLayout(new BoxLayout(panelnodeDescBox, BoxLayout.Y_AXIS)); 1108 panelnodeDesc.setLayout(new FlowLayout()); 1109 panelnodeDesc.add(new JLabel("Description:")); 1110 nodeDescription.setVisible(true); 1111 panelnodeDesc.add(nodeDescription); 1112 panelnodeDesc.setVisible(true); 1113 contentPane.add(panelnodeDesc); 1114 1115 // Set up CMRInet Options 1116 panelnetOpt.setLayout(new GridLayout(0, 2)); 1117 1118 panelnetOpt.add(cbx_cmrinetopt_AUTOPOLL); 1119 cbx_cmrinetopt_AUTOPOLL.addItemListener(nodeOptHandler); 1120 1121 panelnetOpt.add(cbx_cmrinetopt_USECMRIX); 1122 cbx_cmrinetopt_USECMRIX.addItemListener(nodeOptHandler); 1123 cbx_cmrinetopt_USECMRIX.setVisible(false); 1124 1125 panelnetOpt.add(cbx_cmrinetopt_USEBCC); 1126 cbx_cmrinetopt_USEBCC.addItemListener(nodeOptHandler); 1127 cbx_cmrinetopt_USEBCC.setVisible(false); 1128 1129 panelnetOpt.add(cbx_cmrinetopt_BIT8); 1130 cbx_cmrinetopt_BIT8.addItemListener(nodeOptHandler); 1131 cbx_cmrinetopt_BIT8.setVisible(false); 1132 1133 panelnetOpt.add(cbx_cmrinetopt_BIT15); 1134 cbx_cmrinetopt_BIT15.addItemListener(nodeOptHandler); 1135 cbx_cmrinetopt_BIT15.setVisible(false); 1136 1137 Border panelnetOptBorder = BorderFactory.createEtchedBorder(); 1138 Border panelnetOptTitled = BorderFactory.createTitledBorder(panelnetOptBorder, "CMRInet Options"); 1139 panelnetOpt.setBorder(panelnetOptTitled); 1140 panelnetOpt.setVisible(true); 1141 contentPane.add(panelnetOpt); 1142 1143 panelnetOptBox.add(Box.createHorizontalStrut(50)); 1144 contentPane.add(panelnetOptBox); 1145 1146 // Set up cpNode Options 1147 panelnodeOpt.setLayout(new GridLayout(0, 2)); 1148 panelnodeOpt.add(cbx_cpnodeopt_SENDEOT); 1149 cbx_cpnodeopt_SENDEOT.addItemListener(nodeOptHandler); 1150 cbx_cpnodeopt_SENDEOT.setVisible(true); 1151 1152 panelnodeOpt.add(cbx_cpnodeopt_BIT1); 1153 cbx_cpnodeopt_BIT1.addItemListener(nodeOptHandler); 1154 cbx_cpnodeopt_BIT1.setVisible(false); 1155 1156 panelnodeOpt.add(cbx_cpnodeopt_BIT2); 1157 cbx_cpnodeopt_BIT2.addItemListener(nodeOptHandler); 1158 cbx_cpnodeopt_BIT2.setVisible(false); 1159 1160 panelnodeOpt.add(cbx_cpnodeopt_BIT8); 1161 cbx_cpnodeopt_BIT8.addItemListener(nodeOptHandler); 1162 cbx_cpnodeopt_BIT8.setVisible(false); 1163 1164 panelnodeOpt.add(cbx_cpnodeopt_BIT15); 1165 cbx_cpnodeopt_BIT15.addItemListener(nodeOptHandler); 1166 cbx_cpnodeopt_BIT15.setVisible(false); 1167 1168 Border panelnodeOptBorder = BorderFactory.createEtchedBorder(); 1169 Border panelnodeOptTitled = BorderFactory.createTitledBorder(panelnodeOptBorder, "cpNode Options"); 1170 panelnodeOpt.setBorder(panelnodeOptTitled); 1171 panelnodeOpt.setVisible(false); 1172 contentPane.add(panelnodeOpt); 1173 1174 // Set up the notes area panel for various message displays 1175 JPanel panel3 = new JPanel(); 1176 panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS)); 1177 JPanel panel31 = new JPanel(); 1178 panel31.setLayout(new FlowLayout()); 1179 statusText1.setVisible(false); 1180 panel31.add(statusText1); 1181 JPanel panel32 = new JPanel(); 1182 panel32.setLayout(new FlowLayout()); 1183 statusText2.setVisible(false); 1184 panel32.add(statusText2); 1185 JPanel panel33 = new JPanel(); 1186 panel33.setLayout(new FlowLayout()); 1187 statusText3.setVisible(false); 1188 panel33.add(statusText3); 1189 panel3.add(panel31); 1190 panel3.add(panel32); 1191 panel3.add(panel33); 1192 Border panel3Border = BorderFactory.createEtchedBorder(); 1193 Border panel3Titled = BorderFactory.createTitledBorder(panel3Border, Bundle.getMessage("BoxLabelNotes")); 1194 panel3.setBorder(panel3Titled); 1195 contentPane.add(panel3); 1196 1197 // Set up the functions buttons 1198 JPanel panel4 = new JPanel(); 1199 panel4.setLayout(new FlowLayout()); 1200 1201 addNodeButton.setText(Bundle.getMessage("ButtonAdd")); 1202 addNodeButton.setVisible(false); 1203 addNodeButton.setToolTipText(Bundle.getMessage("TipAddButton")); 1204 addNodeButton.addActionListener((java.awt.event.ActionEvent e) -> { 1205 addNodeButtonActionPerformed(); 1206 }); 1207 panel4.add(addNodeButton); 1208 1209 deleteNodeButton.setText(Bundle.getMessage("ButtonDelete")); 1210 deleteNodeButton.setVisible(false); 1211 deleteNodeButton.setToolTipText(Bundle.getMessage("TipDeleteButton")); 1212 deleteNodeButton.addActionListener((java.awt.event.ActionEvent e) -> { 1213 deleteNodeButtonActionConfirm(); 1214 }); 1215 panel4.add(deleteNodeButton); 1216 1217 updateNodeButton.setText(Bundle.getMessage("ButtonUpdate")); 1218 updateNodeButton.setVisible(false); 1219 updateNodeButton.setToolTipText(Bundle.getMessage("TipUpdateButton")); 1220 updateNodeButton.addActionListener((java.awt.event.ActionEvent e) -> { 1221 updateNodeButtonActionPerformed(); 1222 }); 1223 panel4.add(updateNodeButton); 1224 1225 cancelNodeButton.setText(Bundle.getMessage("ButtonCancel")); 1226 cancelNodeButton.setVisible(false); 1227 cancelNodeButton.setToolTipText(Bundle.getMessage("TipCancelButton")); 1228 cancelNodeButton.addActionListener((java.awt.event.ActionEvent e) -> { 1229 cancelNodeButtonActionPerformed(); 1230 }); 1231 panel4.add(cancelNodeButton); 1232 1233 doneNodeButton.setText(Bundle.getMessage("ButtonDone")); 1234 doneNodeButton.setVisible(false); 1235 doneNodeButton.setToolTipText(Bundle.getMessage("TipDoneButton")); 1236 doneNodeButton.addActionListener((java.awt.event.ActionEvent e) -> { 1237 doneNodeButtonActionPerformed(); 1238 }); 1239 panel4.add(doneNodeButton); 1240 1241 contentPane.add(panel4); 1242 pack(); 1243 } 1244 1245 /* 1246 * ------------------------------------------------------- 1247 * Methods to set the correct states of the window buttons 1248 * ------------------------------------------------------- 1249 */ 1250 public void buttonSet_ADD() { 1251 setTitle("ADD NODE"); 1252 statusText1.setText(addStatus1); 1253 statusText1.setVisible(true); 1254 statusText2.setText(addStatus2); 1255 statusText2.setVisible(true); 1256 statusText3.setText(addStatus3); 1257 statusText3.setVisible(false); 1258 1259 panel2c.setVisible(false); 1260 1261 addNodeButton.setVisible(true); 1262 deleteNodeButton.setVisible(false); 1263 updateNodeButton.setVisible(false); 1264 doneNodeButton.setVisible(false); 1265 cancelNodeButton.setVisible(true); 1266 } 1267 1268 public void buttonSet_EDIT() { 1269 setTitle("EDIT NODE"); 1270 statusText1.setText(editStatus1); 1271 statusText1.setVisible(true); 1272 statusText2.setText(editStatus2); 1273 statusText2.setVisible(true); 1274 statusText3.setText(editStatus3); 1275 statusText3.setVisible(false); 1276 1277 addNodeButton.setVisible(false); 1278 deleteNodeButton.setVisible(false); 1279 updateNodeButton.setVisible(true); 1280 doneNodeButton.setVisible(false); 1281 cancelNodeButton.setVisible(true); 1282 } 1283 1284 public void buttonSet_DELETE() { 1285 setTitle("DELETE NODE"); 1286 statusText1.setText(delStatus1); 1287 statusText1.setVisible(true); 1288 statusText2.setText(delStatus2); 1289 statusText2.setVisible(true); 1290 statusText3.setText(delStatus3); 1291 statusText3.setVisible(false); 1292 1293 addNodeButton.setVisible(false); 1294 deleteNodeButton.setVisible(true); 1295 updateNodeButton.setVisible(false); 1296 doneNodeButton.setVisible(false); 1297 cancelNodeButton.setVisible(true); 1298 } 1299 1300 public void addNodeButtonActionPerformed() { 1301 // Check that a node with this address does not exist 1302 curNode = null; 1303 int nodeAddress = readNodeAddress(); 1304 if (nodeAddress < 0) { 1305 return; 1306 } 1307 1308 // get a SerialNode corresponding to this node address if one exists 1309 curNode = (SerialNode) _memo.getTrafficController().getNodeFromAddress(nodeAddress); 1310 // curNode can never be null at this point. Was this intended to catch 1311 // an exception? 1312 if (curNode != null) { 1313 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error1", Integer.toString(nodeAddress)), 1314 "", JmriJOptionPane.ERROR_MESSAGE); 1315 1316 statusText1.setText(Bundle.getMessage("Error1", Integer.toString(nodeAddress))); 1317 statusText1.setVisible(true); 1318 errorInStatus1 = true; 1319 resetNotes2(); 1320 return; 1321 } 1322 1323 // get node information from window and check for data consistency 1324 if (!readReceiveDelay()) { 1325 return; 1326 } 1327 if (!readPulseWidth()) { 1328 return; 1329 } 1330 if (!checkConsistency()) { 1331 return; 1332 } 1333 1334 // all ready, create the new node 1335 curNode = new SerialNode(nodeAddress, nodeType, _memo.getTrafficController()); 1336 nodeTableModel.addRow(curNode); 1337 1338 // configure the new node 1339 setNodeParameters(); 1340 1341 // register any orphan sensors that this node may have 1342 if (_memo.getSensorManager() != null) { 1343 (_memo.getSensorManager()).registerSensorsForNode(curNode); 1344 } 1345 1346 // reset text displays after succefully adding node 1347 resetNotes(); 1348 changedNode = true; 1349 log.info("changedNode = {}", changedNode); 1350 // provide user feedback 1351 statusText1.setText(Bundle.getMessage("FeedBackAdd") + " " + Integer.toString(nodeAddress)); 1352 statusText2.setVisible(false); 1353 statusText3.setVisible(true); 1354 doneNodeButton.setVisible(true); 1355 cancelNodeButton.setVisible(false); 1356 errorInStatus1 = true; 1357 } 1358 1359 /** 1360 * Load all of the configured node information from the serial node class. 1361 * 1362 * @param nodeaddr the node address 1363 */ 1364 public void setupNodeInformationWindow(int nodeaddr) { 1365 // Find Serial Node address 1366 nodeAddress = nodeaddr; 1367 if (nodeAddress < 0) { 1368 return; 1369 } 1370 1371 // get the SerialNode corresponding to this node address 1372 curNode = (SerialNode) _memo.getTrafficController().getNodeFromAddress(nodeAddress); 1373 if (curNode == null) { 1374 statusText1.setText(Bundle.getMessage("Error4")); 1375 statusText1.setVisible(true); 1376 errorInStatus1 = true; 1377 resetNotes2(); 1378 return; 1379 } 1380 1381 // Set up static node address from the table, cannot be changed 1382 nodeAddrStatic.setText(Integer.toString(nodeAddress)); 1383 nodeAddrField.setVisible(false); 1384 nodeAddrStatic.setVisible(true); 1385 1386 // get information for this node and set up combo box 1387 nodeType = curNode.getNodeType(); 1388 switch (nodeType) { 1389 1390 // SMINI 1391 case SerialNode.SMINI: 1392 nodeTypeBox.setSelectedItem("SMINI"); 1393 bitsPerCard = 24; 1394 cardSizeBox.setSelectedItem(Bundle.getMessage("CardSize24")); 1395 onBoardBytesText.setText(Bundle.getMessage("LabelOnBoardBytes") + " 3 Input Bytes, 6 Output Bytes"); 1396 // set up the searchlight arrays 1397 num2LSearchLights = 0; 1398 for (int i = 0; i < 48; i++) { 1399 if (curNode.isSearchLightBit(i)) { 1400 searchlightBits[i] = true; 1401 searchlightBits[i + 1] = true; 1402 firstSearchlight[i] = true; 1403 firstSearchlight[i + 1] = false; 1404 num2LSearchLights++; 1405 i++; 1406 } else { 1407 searchlightBits[i] = false; 1408 firstSearchlight[i] = false; 1409 } 1410 } 1411 break; 1412 1413 // USIC/SUSIC 1414 case SerialNode.USIC_SUSIC: 1415 nodeTypeBox.setSelectedItem("USIC_SUSIC"); 1416 bitsPerCard = curNode.getNumBitsPerCard(); 1417 if (bitsPerCard == 24) { 1418 cardSizeBox.setSelectedItem(Bundle.getMessage("CardSize24")); 1419 } 1420 if (bitsPerCard == 32) { 1421 cardSizeBox.setSelectedItem(Bundle.getMessage("CardSize32")); 1422 } 1423 onBoardBytesText.setText(" "); 1424 1425 break; 1426 1427 // CPNODE 1428 case SerialNode.CPNODE: 1429 nodeTypeBox.setSelectedItem("CPNODE"); 1430 bitsPerCard = 8; 1431 cardSize8Box.setSelectedItem(Bundle.getMessage("CardSize8")); 1432 onBoardBytesText.setText(Bundle.getMessage("LabelOnBoardBytes") + " 2 Bytes"); 1433 1434 // cpNode Options 1435 cbx_cpnodeopt_SENDEOT.setSelected(curNode.iscpnodeBit(SerialNode.optbitNode_SENDEOT)); 1436 cbx_cpnodeopt_BIT1.setSelected(false); 1437 cbx_cpnodeopt_BIT2.setSelected(false); 1438 cbx_cpnodeopt_BIT8.setSelected(curNode.iscpnodeBit(SerialNode.optbitNode_BIT8)); 1439 cbx_cpnodeopt_BIT15.setSelected(curNode.iscpnodeBit(SerialNode.optbitNode_BIT15)); 1440 break; 1441 1442 // CPMEGA 1443 case SerialNode.CPMEGA: 1444 nodeTypeBox.setSelectedItem("CPMEGA"); 1445 bitsPerCard = 8; 1446 cardSize8Box.setSelectedItem(Bundle.getMessage("CardSize8")); 1447 onBoardBytesText.setText(Bundle.getMessage("LabelOnBoardBytes") + " 8 Bytes"); 1448 1449 // cpMega Options 1450 cbx_cpnodeopt_SENDEOT.setSelected(curNode.iscpnodeBit(SerialNode.optbitNode_SENDEOT)); 1451 cbx_cpnodeopt_BIT1.setSelected(false); 1452 cbx_cpnodeopt_BIT2.setSelected(false); 1453 cbx_cpnodeopt_BIT8.setSelected(curNode.iscpnodeBit(SerialNode.optbitNode_BIT8)); 1454 cbx_cpnodeopt_BIT15.setSelected(curNode.iscpnodeBit(SerialNode.optbitNode_BIT15)); 1455 break; 1456 1457 // ESP32Node 1458 case SerialNode.ESP32NODE: 1459 nodeTypeBox.setSelectedItem("ESP32Node"); 1460 bitsPerCard = 8; 1461 cardSize8Box.setSelectedItem(Bundle.getMessage("CardSize8")); 1462 cpNodeOnboard = 0; 1463 onBoardBytesText.setText(Bundle.getMessage("LabelOnBoardBytes") + " None -- 8 MCP23017 chips (0x20-0x27), 16 bytes"); 1464 1465 // ESP32Node Options -- same option bits as CPNODE/CPMEGA 1466 cbx_cpnodeopt_SENDEOT.setSelected(curNode.iscpnodeBit(SerialNode.optbitNode_SENDEOT)); 1467 cbx_cpnodeopt_BIT1.setSelected(false); 1468 cbx_cpnodeopt_BIT2.setSelected(false); 1469 cbx_cpnodeopt_BIT8.setSelected(curNode.iscpnodeBit(SerialNode.optbitNode_BIT8)); 1470 cbx_cpnodeopt_BIT15.setSelected(curNode.iscpnodeBit(SerialNode.optbitNode_BIT15)); 1471 break; 1472 1473 default: 1474 log.error("Unknown Node Type {}", nodeType); 1475 break; 1476 } 1477 1478 // CMRInet Options for all node types 1479 cbx_cmrinetopt_AUTOPOLL.setSelected(curNode.isCMRInetBit(SerialNode.optbitNet_AUTOPOLL)); 1480 cbx_cmrinetopt_USECMRIX.setSelected(curNode.isCMRInetBit(SerialNode.optbitNet_USECMRIX)); 1481 cbx_cmrinetopt_USEBCC.setSelected(curNode.isCMRInetBit(SerialNode.optbitNet_USEBCC)); 1482 cbx_cmrinetopt_BIT8.setSelected(curNode.isCMRInetBit(SerialNode.optbitNet_BIT8)); 1483 cbx_cmrinetopt_BIT15.setSelected(curNode.isCMRInetBit(SerialNode.optbitNet_BIT15)); 1484 1485 // set up receive delay 1486 receiveDelay = curNode.getTransmissionDelay(); 1487 receiveDelayField.setText(Integer.toString(receiveDelay)); 1488 1489 // set up pulse width 1490 pulseWidth = curNode.getPulseWidth(); 1491 pulseWidthField.setText(Integer.toString(pulseWidth)); 1492 1493 // node description 1494 nodeDescText = curNode.getcmriNodeDesc(); 1495 nodeDescription.setText(nodeDescText); 1496 1497 // set up card types 1498 for (int i = 0; i < 64; i++) { 1499 if (curNode.isOutputCard(i)) { 1500 cardType[i] = Bundle.getMessage("CardTypeOutput"); 1501 } else if (curNode.isInputCard(i)) { 1502 cardType[i] = Bundle.getMessage("CardTypeInput"); 1503 } else { 1504 cardType[i] = Bundle.getMessage("CardTypeNone"); 1505 } 1506 } 1507 1508 if (nodeType == SerialNode.CPMEGA) { 1509 for (int i = 0; i < 8; i++) // Remap the onboard bytes 1510 { 1511 if (curNode.isOutputCard(i)) { 1512 onBoardType[i] = Bundle.getMessage("CardTypeOutput"); 1513 } else if (curNode.isInputCard(i)) { 1514 onBoardType[i] = Bundle.getMessage("CardTypeInput"); 1515 } else { 1516 onBoardType[i] = Bundle.getMessage("CardTypeNone"); 1517 } 1518 } 1519 } 1520 1521 // ensure that table displays correctly 1522 panel2.setVisible(false); 1523 panel2a.setVisible(false); 1524 if (nodeType == SerialNode.USIC_SUSIC) { 1525 panel2.setVisible(true); 1526 } else if (nodeType == SerialNode.SMINI) { 1527 panel2a.setVisible(true); 1528 } else if (nodeType == SerialNode.CPNODE) { 1529 panel2c.setVisible(false); 1530 panel2b.setVisible(true); 1531 } else if (nodeType == SerialNode.CPMEGA) { 1532 panel2c.setVisible(true); 1533 panel2b.setVisible(false); 1534 } else if (nodeType == SerialNode.ESP32NODE) { 1535 panel2c.setVisible(false); 1536 panel2b.setVisible(true); 1537 } 1538 1539 } 1540 1541 /** 1542 * Create and load edit function window. 1543 * 1544 * @param nodeaddr the node address 1545 */ 1546 public void editNodeButtonActionPerformed(int nodeaddr) { 1547 // Find Serial Node address 1548 1549 nodeAddress = nodeaddr; 1550 if (nodeAddress < 0) { 1551 return; 1552 } 1553 1554 // get the SerialNode corresponding to this node address 1555 curNode = (SerialNode) _memo.getTrafficController().getNodeFromAddress(nodeAddress); 1556 if (curNode == null) { 1557 statusText1.setText(Bundle.getMessage("Error4")); 1558 statusText1.setVisible(true); 1559 errorInStatus1 = true; 1560 resetNotes2(); 1561 return; 1562 } 1563 1564 // Load the node data into the window 1565 setupNodeInformationWindow(nodeAddress); 1566 1567 // Switch to edit notes 1568 editMode = true; 1569 statusText1.setText(editStatus1); 1570 statusText1.setVisible(true); 1571 statusText2.setText(editStatus2); 1572 statusText2.setVisible(true); 1573 statusText3.setText(editStatus3); 1574 statusText3.setVisible(true); 1575 } 1576 1577 /** 1578 * Handle update button clicked. 1579 */ 1580 public void updateNodeButtonActionPerformed() { 1581 // get node information from window 1582 if (!readReceiveDelay()) { 1583 return; 1584 } 1585 if (!readPulseWidth()) { 1586 return; 1587 } 1588 1589 // check consistency of node information 1590 if (!checkConsistency()) { 1591 return; 1592 } 1593 1594 // update node information 1595 if (curNode.getNodeType() != nodeType) { 1596 // node type has changed 1597 curNode.setNodeType(nodeType); 1598 } 1599 1600 // cmri node description c2 1601 curNode.setcmriNodeDesc(nodeDescription.getText()); 1602 setNodeParameters(); 1603 nodeTableModel.changeRow(selectedTableRow, curNode); 1604 1605 // Switch buttons 1606 changedNode = true; 1607 doneNodeButton.setVisible(true); 1608 updateNodeButton.setVisible(true); 1609 cancelNodeButton.setVisible(true); 1610 nodeAddrField.setVisible(false); 1611 nodeAddrStatic.setVisible(true); 1612 1613 // provide user feedback 1614 statusText1.setText(Bundle.getMessage("FeedBackUpdate") + " " + Integer.toString(nodeAddress)); 1615 statusText2.setVisible(false); 1616 cancelNodeButton.setVisible(false); 1617 errorInStatus1 = true; 1618 } 1619 1620 /** 1621 * Handle delete button pressed. 1622 */ 1623 public void deleteNodeButtonActionConfirm() { 1624 // confirm deletion with the user 1625 1626 if (JmriJOptionPane.OK_OPTION == JmriJOptionPane.showConfirmDialog( 1627 this, Bundle.getMessage("ConfirmDelete1") + "\n" 1628 + Bundle.getMessage("ConfirmDelete2"), Bundle.getMessage("ConfirmDeleteTitle"), 1629 JmriJOptionPane.OK_CANCEL_OPTION, 1630 JmriJOptionPane.WARNING_MESSAGE)) { 1631 1632 // delete this node 1633 _memo.getTrafficController().deleteNode(deleteNodeAddress); 1634 nodeTableModel.removeRow(selectedTableRow); 1635 1636 initializeNodes(); 1637 1638 // provide user feedback 1639 resetNotes(); 1640 statusText1.setText(Bundle.getMessage("FeedBackDelete") + " " + Integer.toString(deleteNodeAddress)); 1641 statusText1.setVisible(true); 1642 errorInStatus1 = true; 1643 changedNode = true; 1644 deleteNodeButton.setVisible(false); 1645 doneNodeButton.setVisible(true); 1646 cancelNodeButton.setVisible(false); 1647 statusText2.setVisible(false); 1648 } else { 1649 // reset as needed 1650 resetNotes(); 1651 } 1652 } 1653 1654 /** 1655 * Set up delete node window. 1656 * 1657 * @param nodeAddr the node address 1658 */ 1659 public void deleteNodeButtonActionPerformed(int nodeAddr) { 1660 // Set up static node address 1661 nodeAddress = nodeAddr; 1662 nodeAddrStatic.setText(Integer.toString(nodeAddress)); 1663 nodeAddrField.setVisible(false); 1664 nodeAddrStatic.setVisible(true); 1665 1666 // Find Serial Node address 1667 if (nodeAddress < 0) { 1668 log.info("nodeAddress < 0"); 1669 return; 1670 } 1671 1672 // get the SerialNode corresponding to this node address 1673 curNode = (SerialNode) _memo.getTrafficController().getNodeFromAddress(nodeAddress); 1674 deleteNodeAddress = nodeAddr; 1675 // Load the node data into the window 1676 1677 setupNodeInformationWindow(nodeAddress); 1678 1679 // get the node corresponding to this node address 1680 if (curNode == null) { 1681 statusText1.setText(Bundle.getMessage("Error4")); 1682 statusText1.setVisible(true); 1683 errorInStatus1 = true; 1684 resetNotes2(); 1685 } else { 1686 statusText1.setText(Bundle.getMessage("NotesDel3")); 1687 statusText1.setVisible(true); 1688 } 1689 } 1690 1691 /** 1692 * Handle done button clicked. 1693 */ 1694 public void doneNodeButtonActionPerformed() { 1695 if (editMode) { 1696 // Reset 1697 editMode = false; 1698 curNode = null; 1699 // Switch buttons 1700 addNodeButton.setVisible(false); 1701 editNodeButton.setVisible(false); 1702 deleteNodeButton.setVisible(false); 1703 doneNodeButton.setVisible(true); 1704 updateNodeButton.setVisible(false); 1705 cancelNodeButton.setVisible(false); 1706 nodeAddrField.setVisible(false); 1707 nodeAddrStatic.setVisible(false); 1708 } 1709 if (changedNode) { 1710 JmriJOptionPane.showMessageDialog(this, 1711 Bundle.getMessage("Reminder1") + "\n" + Bundle.getMessage("Reminder2"), 1712 Bundle.getMessage("ReminderTitle"), 1713 JmriJOptionPane.INFORMATION_MESSAGE); 1714 } 1715 changedNode = false; 1716 1717 setVisible(false); 1718 dispose(); 1719 } 1720 1721 /** 1722 * Handle cancel button clicked. 1723 */ 1724 public void cancelNodeButtonActionPerformed() { 1725 // Reset 1726 editMode = false; 1727 changedNode = false; 1728 curNode = null; 1729 // Switch buttons 1730 addNodeButton.setVisible(false); 1731 editNodeButton.setVisible(false); 1732 deleteNodeButton.setVisible(false); 1733 doneNodeButton.setVisible(false); 1734 updateNodeButton.setVisible(false); 1735 cancelNodeButton.setVisible(false); 1736 // make node address editable again 1737 nodeAddrField.setVisible(false); 1738 nodeAddrStatic.setVisible(false); 1739 // refresh notes panel 1740 // statusText1.setText(stdStatus1); 1741 // statusText2.setText(stdStatus2); 1742 // statusText3.setText(stdStatus3); 1743 setVisible(false); 1744 dispose(); 1745 } 1746 1747 @Override 1748 public void windowClosing(java.awt.event.WindowEvent e) { 1749 doneNodeButtonActionPerformed(); 1750 super.windowClosing(e); 1751 } 1752 1753 /** 1754 * Set the node parameters by type. Some parameters are specific to a 1755 * particular node type. 1756 */ 1757 void setNodeParameters() { 1758 // receive delay is common for all node types 1759 int numInput = 0; 1760 int numOutput = 0; 1761 curNode.setTransmissionDelay(receiveDelay); 1762 1763 // pulse width is common for all node types 1764 curNode.setPulseWidth(pulseWidth); 1765 1766 // continue in a node specific way 1767 switch (nodeType) { 1768 1769 // SMINI 1770 case SerialNode.SMINI: 1771 1772 // Note: most parameters are set by default on creation 1773 int numSet = 0; 1774 // Configure 2-lead oscillating searchlights - first clear unneeded searchlights 1775 for (int j = 0; j < 47; j++) { 1776 if (curNode.isSearchLightBit(j)) { 1777 if (!firstSearchlight[j]) { 1778 // this is the first bit of a deleted searchlight - clear it 1779 curNode.clear2LeadSearchLight(j); 1780 // skip over the second bit of the cleared searchlight 1781 j++; 1782 } else { 1783 // this is the first bit of a kept searchlight - skip second bit 1784 j++; 1785 } 1786 } 1787 } 1788 // Add needed searchlights that are not already configured 1789 for (int i = 0; i < 47; i++) { 1790 if (firstSearchlight[i]) { 1791 if (!curNode.isSearchLightBit(i)) { 1792 // this is the first bit of an added searchlight 1793 curNode.set2LeadSearchLight(i); 1794 } 1795 numSet++; 1796 } 1797 } 1798 // consistency check 1799 if (numSet != num2LSearchLights) { 1800 log.error("Inconsistent numbers of 2-lead searchlights. numSet = {}, num2LSearchLights = {}", Integer.toString(numSet), Integer.toString(num2LSearchLights)); 1801 } 1802 break; 1803 1804 // USIC/SUSIC 1805 case SerialNode.USIC_SUSIC: 1806 // set number of bits per card 1807 curNode.setNumBitsPerCard(bitsPerCard); 1808 // configure the input/output cards 1809 numInput = 0; 1810 numOutput = 0; 1811 for (int i = 0; i < 64; i++) { 1812 if ("No Card".equals(cardType[i])) { 1813 curNode.setCardTypeByAddress(i, SerialNode.NO_CARD); 1814 } else if ("Input Card".equals(cardType[i])) { 1815 curNode.setCardTypeByAddress(i, SerialNode.INPUT_CARD); 1816 numInput++; 1817 } else if ("Output Card".equals(cardType[i])) { 1818 curNode.setCardTypeByAddress(i, SerialNode.OUTPUT_CARD); 1819 numOutput++; 1820 } else { 1821 log.error("Unexpected card type - {}", cardType[i]); 1822 } 1823 } 1824 // consistency check 1825 if (numCards != (numOutput + numInput)) { 1826 log.error("Inconsistent numbers of cards - setNodeParameters."); 1827 } 1828 1829 // Force created node to be polled as the default 1830 curNode.setOptNet_AUTOPOLL(1); 1831 break; 1832 1833 // CPNODE 1834 case SerialNode.CPNODE: 1835 // set number of bits per card 1836 bitsPerCard = 8; 1837 curNode.setNumBitsPerCard(bitsPerCard); 1838 numInput = 2; 1839 numOutput = 2; 1840 // configure the input/output cards 1841 for (int i = 4; i < 64; i++) // Skip the onboard bytes 1842 { 1843 if ("No Card".equals(cardType[i])) { 1844 curNode.setCardTypeByAddress(i, SerialNode.NO_CARD); 1845 } else if ("Input Card".equals(cardType[i])) { 1846 curNode.setCardTypeByAddress(i, SerialNode.INPUT_CARD); 1847 numInput++; 1848 } else if ("Output Card".equals(cardType[i])) { 1849 curNode.setCardTypeByAddress(i, SerialNode.OUTPUT_CARD); 1850 numOutput++; 1851 } else { 1852 log.error("Unexpected card type - {}", cardType[i]); 1853 } 1854 } 1855 1856 // Set the node option bits. Some are moved from the CMRInet options 1857 curNode.setOptNet_AUTOPOLL(cbx_cmrinetopt_AUTOPOLL.isSelected() ? 1 : 0); 1858 1859 curNode.setOptNode_SENDEOT(cbx_cpnodeopt_SENDEOT.isSelected() ? 1 : 0); 1860 curNode.setOptNode_USECMRIX(cbx_cmrinetopt_USECMRIX.isSelected() ? 1 : 0); // Copy from CMRInet 1861 curNode.setOptNode_USEBCC(cbx_cmrinetopt_USEBCC.isSelected() ? 1 : 0); // Copy from CMRInet 1862 curNode.setOptNode_BIT8(cbx_cpnodeopt_BIT8.isSelected() ? 1 : 0); 1863 curNode.setOptNode_BIT15(cbx_cpnodeopt_BIT15.isSelected() ? 1 : 0); 1864 1865 break; 1866 1867 // CPMEGA 1868 case SerialNode.CPMEGA: 1869 // set number of bits per card 1870 bitsPerCard = 8; 1871 curNode.setNumBitsPerCard(bitsPerCard); 1872 numInput = 0; 1873 numOutput = 0; 1874 1875 for (int i = 0; i < 8; i++) // Pick up the onboard bytes 1876 { 1877 if ("No Card".equals(onBoardType[i])) { 1878 curNode.setCardTypeByAddress(i, SerialNode.NO_CARD); 1879 } else if ("Input Card".equals(onBoardType[i])) { 1880 curNode.setCardTypeByAddress(i, SerialNode.INPUT_CARD); 1881 numInput++; 1882 } else if ("Output Card".equals(onBoardType[i])) { 1883 curNode.setCardTypeByAddress(i, SerialNode.OUTPUT_CARD); 1884 numOutput++; 1885 } else { 1886 log.error("Unexpected card type - {}", onBoardType[i]); 1887 } 1888 } 1889 1890 // configure the IOX cards 1891 for (int i = 8; i < 64; i++) // Skip the onboard bytes 1892 { 1893 if ("No Card".equals(cardType[i])) { 1894 curNode.setCardTypeByAddress(i, SerialNode.NO_CARD); 1895 } else if ("Input Card".equals(cardType[i])) { 1896 curNode.setCardTypeByAddress(i, SerialNode.INPUT_CARD); 1897 numInput++; 1898 } else if ("Output Card".equals(cardType[i])) { 1899 curNode.setCardTypeByAddress(i, SerialNode.OUTPUT_CARD); 1900 numOutput++; 1901 } else { 1902 log.error("Unexpected card type - {}", cardType[i]); 1903 } 1904 } 1905 1906 // Set the node option bits. Some are moved from the CMRInet options 1907 curNode.setOptNet_AUTOPOLL(1); // Default node to be polled 1908 1909 curNode.setOptNode_SENDEOT(cbx_cpnodeopt_SENDEOT.isSelected() ? 1 : 0); 1910 curNode.setOptNode_USECMRIX(cbx_cmrinetopt_USECMRIX.isSelected() ? 1 : 0); // Copy from CMRInet 1911 curNode.setOptNode_USEBCC(cbx_cmrinetopt_USEBCC.isSelected() ? 1 : 0); // Copy from CMRInet 1912 curNode.setOptNode_BIT8(cbx_cpnodeopt_BIT8.isSelected() ? 1 : 0); 1913 curNode.setOptNode_BIT15(cbx_cpnodeopt_BIT15.isSelected() ? 1 : 0); 1914 1915 break; 1916 1917 // ESP32Node -- no onboard bytes at all (cpNodeOnboard=0, see the 1918 // ActionListener above), so every one of the 16 cards comes from 1919 // cardType[] with no skip, unlike CPNODE (skips 4) or CPMEGA 1920 // (onboard bytes handled separately, IOX skips 8). 1921 case SerialNode.ESP32NODE: 1922 // set number of bits per card 1923 bitsPerCard = 8; 1924 curNode.setNumBitsPerCard(bitsPerCard); 1925 numInput = 0; 1926 numOutput = 0; 1927 1928 for (int i = 0; i < 64; i++) { 1929 if ("No Card".equals(cardType[i])) { 1930 curNode.setCardTypeByAddress(i, SerialNode.NO_CARD); 1931 } else if ("Input Card".equals(cardType[i])) { 1932 curNode.setCardTypeByAddress(i, SerialNode.INPUT_CARD); 1933 numInput++; 1934 } else if ("Output Card".equals(cardType[i])) { 1935 curNode.setCardTypeByAddress(i, SerialNode.OUTPUT_CARD); 1936 numOutput++; 1937 } else { 1938 log.error("Unexpected card type - {}", cardType[i]); 1939 } 1940 } 1941 1942 // Set the node option bits. Some are moved from the CMRInet options 1943 curNode.setOptNet_AUTOPOLL(1); // Default node to be polled 1944 1945 curNode.setOptNode_SENDEOT(cbx_cpnodeopt_SENDEOT.isSelected() ? 1 : 0); 1946 curNode.setOptNode_USECMRIX(cbx_cmrinetopt_USECMRIX.isSelected() ? 1 : 0); // Copy from CMRInet 1947 curNode.setOptNode_USEBCC(cbx_cmrinetopt_USEBCC.isSelected() ? 1 : 0); // Copy from CMRInet 1948 curNode.setOptNode_BIT8(cbx_cpnodeopt_BIT8.isSelected() ? 1 : 0); 1949 curNode.setOptNode_BIT15(cbx_cpnodeopt_BIT15.isSelected() ? 1 : 0); 1950 1951 break; 1952 1953 default: 1954 log.error("Unexpected node type in setNodeParameters- {}", Integer.toString(nodeType)); 1955 break; 1956 } 1957 1958 // Set the node description for all types 1959 curNode.setcmriNodeDesc(nodeDescription.getText()); 1960 1961 // Cause reinitialization of this Node to reflect these parameters 1962 _memo.getTrafficController().initializeSerialNode(curNode); 1963 } 1964 1965 /** 1966 * Reset the notes error after error display. 1967 */ 1968 private void resetNotes() { 1969 if (errorInStatus1) { 1970 if (editMode) { 1971 statusText1.setText(editStatus1); 1972 } else { 1973 // statusText1.setText(stdStatus1); 1974 } 1975 errorInStatus1 = false; 1976 } 1977 resetNotes2(); 1978 } 1979 1980 /** 1981 * Reset the second line of Notes area. 1982 */ 1983 private void resetNotes2() { 1984 if (errorInStatus2) { 1985 if (editMode) { 1986 statusText1.setText(editStatus2); 1987 } else { 1988 // statusText2.setText(stdStatus2); 1989 } 1990 errorInStatus2 = false; 1991 } 1992 } 1993 1994 /** 1995 * Read node address and check for legal range. Sets the error message in 1996 * {@link #statusText1} if not legal. 1997 * 1998 * @return A node address in the range 0-127 if legal; -1 if not legal 1999 */ 2000 private int readNodeAddress() { 2001 int addr = -1; 2002 try { 2003 addr = Integer.parseInt(nodeAddrField.getText()); 2004 } catch (NumberFormatException e) { 2005 statusText1.setText(Bundle.getMessage("Error5")); 2006 statusText1.setVisible(true); 2007 errorInStatus1 = true; 2008 resetNotes2(); 2009 return -1; 2010 } 2011 2012 if ((addr < 0) || (addr > 127)) { 2013// statusText1.setText(Bundle.getMessage("Error6")); 2014// statusText1.setVisible(true); 2015 errorInStatus1 = true; 2016 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error6"), "", JmriJOptionPane.ERROR_MESSAGE); 2017 resetNotes2(); 2018 return -1; 2019 } 2020 return (addr); 2021 } 2022 2023 /** 2024 * Read receive delay from window. If an error is detected, a suitable error 2025 * message is placed in the Notes area. 2026 * 2027 * @return true if successful; false otherwise 2028 */ 2029 protected boolean readReceiveDelay() { 2030 // get the transmission delay 2031 try { 2032 receiveDelay = Integer.parseInt(receiveDelayField.getText()); 2033 } catch (NumberFormatException e) { 2034 statusText1.setText(Bundle.getMessage("Error7")); 2035 statusText1.setVisible(true); 2036 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error7"), 2037 "", JmriJOptionPane.ERROR_MESSAGE); 2038 receiveDelay = 0; 2039 errorInStatus1 = true; 2040 resetNotes2(); 2041 return (false); 2042 } 2043 if (receiveDelay < 0) { 2044 statusText1.setText(Bundle.getMessage("Error8")); 2045 statusText1.setVisible(true); 2046 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error8"), 2047 "", JmriJOptionPane.ERROR_MESSAGE); 2048 receiveDelay = 0; 2049 errorInStatus1 = true; 2050 resetNotes2(); 2051 return (false); 2052 } 2053 if (receiveDelay > 65535) { 2054 statusText1.setText(Bundle.getMessage("Error9")); 2055 statusText1.setVisible(true); 2056 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error9"), 2057 "", JmriJOptionPane.ERROR_MESSAGE); 2058 receiveDelay = 0; 2059 errorInStatus1 = true; 2060 resetNotes2(); 2061 return (false); 2062 } 2063 // successful 2064 return true; 2065 } 2066 2067 /** 2068 * Read pulse width from window. If an error is detected, a suitable error 2069 * message is placed in the Notes area. 2070 * 2071 * @return true if successful; false otherwise 2072 */ 2073 protected boolean readPulseWidth() { 2074 // get the pulse width 2075 try { 2076 pulseWidth = Integer.parseInt(pulseWidthField.getText()); 2077 } catch (NumberFormatException e) { 2078 statusText1.setText(Bundle.getMessage("Error18")); 2079 statusText1.setVisible(true); 2080 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error18"), 2081 "", JmriJOptionPane.ERROR_MESSAGE); 2082 pulseWidth = 500; 2083 errorInStatus1 = true; 2084 resetNotes2(); 2085 return (false); 2086 } 2087 if (pulseWidth < 100) { 2088 statusText1.setText(Bundle.getMessage("Error16")); 2089 statusText1.setVisible(true); 2090 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error16"), 2091 "", JmriJOptionPane.ERROR_MESSAGE); 2092 pulseWidth = 100; 2093 pulseWidthField.setText(Integer.toString(pulseWidth)); 2094 errorInStatus1 = true; 2095 resetNotes2(); 2096 return (false); 2097 } 2098 if (pulseWidth > 10000) { 2099 statusText1.setText(Bundle.getMessage("Error17")); 2100 statusText1.setVisible(true); 2101 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error17"), 2102 "", JmriJOptionPane.ERROR_MESSAGE); 2103 pulseWidth = 500; 2104 pulseWidthField.setText(Integer.toString(pulseWidth)); 2105 errorInStatus1 = true; 2106 resetNotes2(); 2107 return (false); 2108 } 2109 // successful 2110 return true; 2111 } 2112 2113 /** 2114 * Check for consistency errors by node type. If an error is detected, a 2115 * suitable error message is placed in the Notes area. 2116 * 2117 * @return true if successful; false otherwise 2118 */ 2119 protected boolean checkConsistency() { 2120 switch (nodeType) { 2121 case SerialNode.SMINI: 2122 // ensure that number of searchlight bits is consistent 2123 int numBits = 0; 2124 for (int i = 0; i < 48; i++) { 2125 if (searchlightBits[i]) { 2126 numBits++; 2127 } 2128 } 2129 if ((2 * num2LSearchLights) != numBits) { 2130 statusText1.setText(Bundle.getMessage("Error10")); 2131 statusText1.setVisible(true); 2132 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error10"), 2133 "", JmriJOptionPane.ERROR_MESSAGE); 2134 errorInStatus1 = true; 2135 resetNotes2(); 2136 return (false); 2137 } 2138 break; 2139 case SerialNode.USIC_SUSIC: 2140 // ensure that at least one card is defined 2141 numCards = 0; 2142 boolean atNoCard = false; 2143 for (int i = 0; i < 64; i++) { 2144 if ((cardType[i].equals(Bundle.getMessage("CardTypeOutput"))) 2145 || (cardType[i].equals(Bundle.getMessage("CardTypeInput")))) { 2146 if (atNoCard) { 2147 // gap error 2148 statusText1.setText(Bundle.getMessage("Error11")); 2149 statusText1.setVisible(true); 2150 statusText2.setText(Bundle.getMessage("Error12")); 2151 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error11") + Bundle.getMessage("Error12"), 2152 "", JmriJOptionPane.ERROR_MESSAGE); 2153 errorInStatus1 = true; 2154 errorInStatus2 = true; 2155 return (false); 2156 } else { 2157 numCards++; 2158 } 2159 } else if (cardType[i].equals(Bundle.getMessage("CardTypeNone"))) { 2160 atNoCard = true; 2161 } 2162 } 2163 // ensure that at least one card has been defined 2164 if (numCards <= 0) { 2165 // no card error 2166 statusText1.setText(Bundle.getMessage("Error13")); 2167 statusText2.setText(Bundle.getMessage("Error14")); 2168 statusText1.setVisible(true); 2169 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error13") + Bundle.getMessage("Error14"), 2170 "", JmriJOptionPane.ERROR_MESSAGE); 2171 errorInStatus1 = true; 2172 errorInStatus2 = true; 2173 return (false); 2174 } 2175 // check that card size is 24 or 32 bit 2176 if ((bitsPerCard != 24) && (bitsPerCard != 32)) { 2177 // card size error 2178 statusText1.setText(Bundle.getMessage("Error15")); 2179 statusText1.setVisible(true); 2180 errorInStatus1 = true; 2181 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("Error15"), 2182 "", JmriJOptionPane.ERROR_MESSAGE); 2183 resetNotes2(); 2184 return (false); 2185 } 2186 // further checking if in Edit mode 2187 if (editMode) { 2188 // get pre-edit numbers of cards 2189 int numOutput = curNode.numOutputCards(); 2190 int numInput = curNode.numInputCards(); 2191 // will the number of cards be reduced by this edit? 2192 if (numCards < (numOutput + numInput)) { 2193 if ( JmriJOptionPane.YES_OPTION != JmriJOptionPane.showConfirmDialog(this, 2194 Bundle.getMessage("ConfirmUpdate1") + "\n" 2195 + Bundle.getMessage("ConfirmUpdate2") + "\n" 2196 + Bundle.getMessage("ConfirmUpdate3"), 2197 Bundle.getMessage("ConfirmUpdateTitle"), 2198 JmriJOptionPane.YES_NO_OPTION, 2199 JmriJOptionPane.WARNING_MESSAGE)) { 2200 // user did not click yes - cancel the update 2201 return (false); 2202 } 2203 } 2204 } 2205 break; 2206 case SerialNode.CPNODE: 2207 for (int j = 0; j < 64; j++) { 2208 if ((cardType[j].equals(Bundle.getMessage("CardTypeOutput"))) 2209 || (cardType[j].equals(Bundle.getMessage("CardTypeInput")))) { 2210 numCards++; 2211 } 2212 } 2213 break; 2214 case SerialNode.CPMEGA: 2215 for (int j = 0; j < 64; j++) { 2216 if ((cardType[j].equals(Bundle.getMessage("CardTypeOutput"))) 2217 || (cardType[j].equals(Bundle.getMessage("CardTypeInput")))) { 2218 numCards++; 2219 } 2220 } 2221 break; 2222 case SerialNode.ESP32NODE: 2223 for (int j = 0; j < 64; j++) { 2224 if ((cardType[j].equals(Bundle.getMessage("CardTypeOutput"))) 2225 || (cardType[j].equals(Bundle.getMessage("CardTypeInput")))) { 2226 numCards++; 2227 } 2228 } 2229 break; 2230 2231 // here add code for other types of nodes 2232 default: 2233 log.warn("Unexpected node type - {}", nodeType); 2234 break; 2235 } 2236 return true; 2237 } 2238 2239 /** 2240 * Set up table for selecting card type by address for USIC_SUSIC nodes 2241 */ 2242 public class CardConfigModel extends AbstractTableModel { 2243 2244 @Override 2245 public String getColumnName(int c) { 2246 return cardConfigColumnNames[c]; 2247 } 2248 2249 @Override 2250 public Class<?> getColumnClass(int c) { 2251 return String.class; 2252 } 2253 2254 @Override 2255 public int getColumnCount() { 2256 return 2; 2257 } 2258 2259 @Override 2260 public int getRowCount() { 2261 return 64; 2262 } 2263 2264 @Override 2265 public Object getValueAt(int r, int c) { 2266 if (c == 0) { 2267 return " " + Integer.toString(r); 2268 } else if (c == 1) { 2269 return " " + cardType[r]; 2270 } 2271 return ""; 2272 } 2273 2274 @Override 2275 public void setValueAt(Object type, int r, int c) { 2276 if (c == 1) { 2277 cardType[r] = (String) type; 2278 } 2279 } 2280 2281 @Override 2282 public boolean isCellEditable(int r, int c) { 2283 return (c == 1); 2284 } 2285 2286 public static final int ADDRESS_COLUMN = 0; 2287 public static final int TYPE_COLUMN = 1; 2288 } 2289 private final String[] cardConfigColumnNames = { 2290 Bundle.getMessage("HeadingCardAddress"), 2291 Bundle.getMessage("HeadingCardType") 2292 }; 2293 private final String[] cardType = new String[64]; 2294 private final String[] onBoardType = new String[16]; 2295 2296 /** 2297 * Set up model for SMINI table for designating oscillating 2-lead 2298 * searchlights 2299 */ 2300 public class SearchlightConfigModel extends AbstractTableModel { 2301 2302 @Override 2303 public String getColumnName(int c) { 2304 return searchlightConfigColumnNames[c]; 2305 } 2306 2307 @Override 2308 public Class<?> getColumnClass(int c) { 2309 if (c > 0) { 2310 return Boolean.class; 2311 } else { 2312 return String.class; 2313 } 2314 } 2315 2316 @Override 2317 public int getColumnCount() { 2318 return 9; 2319 } 2320 2321 @Override 2322 public int getRowCount() { 2323 return 6; 2324 } 2325 2326 @Override 2327 public Object getValueAt(int r, int c) { 2328 if (c == 0) { 2329 switch (r) { 2330 case 0: 2331 return ("Card 0 Port A"); 2332 case 1: 2333 return ("Card 0 Port B"); 2334 case 2: 2335 return ("Card 0 Port C"); 2336 case 3: 2337 return ("Card 1 Port A"); 2338 case 4: 2339 return ("Card 1 Port B"); 2340 case 5: 2341 return ("Card 1 Port C"); 2342 default: 2343 return (""); 2344 } 2345 } else { 2346 int index = (r * 8) + (c - 1); 2347 return searchlightBits[index]; 2348 } 2349 } 2350 2351 @Override 2352 public void setValueAt(Object type, int r, int c) { 2353 if (c > 0) { 2354 int index = (r * 8) + (c - 1); 2355 if (!((Boolean) type)) { 2356 searchlightBits[index] = false; 2357 if (firstSearchlight[index]) { 2358 searchlightBits[index + 1] = false; 2359 firstSearchlight[index] = false; 2360 } else { 2361 searchlightBits[index - 1] = false; 2362 firstSearchlight[index - 1] = false; 2363 } 2364 num2LSearchLights--; 2365 } else { 2366 if (index < 47) { 2367 if (!searchlightBits[index] && !searchlightBits[index + 1]) { 2368 searchlightBits[index] = true; 2369 searchlightBits[index + 1] = true; 2370 firstSearchlight[index] = true; 2371 firstSearchlight[index + 1] = false; 2372 if (index > 0) { 2373 firstSearchlight[index - 1] = false; 2374 } 2375 num2LSearchLights++; 2376 } 2377 } 2378 } 2379 panel2a.setVisible(false); 2380 panel2a.setVisible(true); 2381 } 2382 } 2383 2384 @Override 2385 public boolean isCellEditable(int r, int c) { 2386 return (c != 0); 2387 } 2388 2389 public static final int PORT_COLUMN = 0; 2390 } 2391 private final String[] searchlightConfigColumnNames = {Bundle.getMessage("HeadingPort"), "0", "1", "2", "3", "4", "5", "6", "7"}; 2392 private final boolean[] searchlightBits = new boolean[48]; // true if this bit is a searchlight bit 2393 private final boolean[] firstSearchlight = new boolean[48]; // true if first of a pair of searchlight bits 2394 2395 /** 2396 * Handles checkboxes for cpNode options 2397 */ 2398 private class HandlerClass implements ItemListener { 2399 2400 @Override 2401 public void itemStateChanged(ItemEvent e) { 2402 JCheckBox checkbox = (JCheckBox) e.getSource(); 2403 2404 if (checkbox == cbx_cmrinetopt_AUTOPOLL) { 2405 curNode.setCMRInetOpts(SerialNode.optbitNet_AUTOPOLL, (cbx_cmrinetopt_AUTOPOLL.isSelected() ? 1 : 0)); 2406 } else if (checkbox == cbx_cmrinetopt_USECMRIX) { 2407 curNode.setCMRInetOpts(SerialNode.optbitNet_USECMRIX, (cbx_cmrinetopt_USECMRIX.isSelected() ? 1 : 0)); 2408 curNode.setcpnodeOpts(SerialNode.optbitNet_USECMRIX, curNode.getCMRInetOpts(SerialNode.optbitNet_USECMRIX)); 2409 } else if (checkbox == cbx_cmrinetopt_USEBCC) { 2410 curNode.setCMRInetOpts(SerialNode.optbitNet_USEBCC, (cbx_cmrinetopt_USEBCC.isSelected() ? 1 : 0)); 2411 curNode.setcpnodeOpts(SerialNode.optbitNet_USEBCC, curNode.getCMRInetOpts(SerialNode.optbitNet_USEBCC)); 2412 } else if (checkbox == cbx_cmrinetopt_BIT8) { 2413 curNode.setCMRInetOpts(SerialNode.optbitNet_BIT8, (cbx_cmrinetopt_BIT8.isSelected() ? 1 : 0)); 2414 } else if (checkbox == cbx_cmrinetopt_BIT15) { 2415 curNode.setCMRInetOpts(SerialNode.optbitNet_BIT15, (cbx_cmrinetopt_BIT15.isSelected() ? 1 : 0)); 2416 } else if (checkbox == cbx_cpnodeopt_SENDEOT) { 2417 curNode.setcpnodeOpts(SerialNode.optbitNode_SENDEOT, (cbx_cpnodeopt_SENDEOT.isSelected() ? 1 : 0)); 2418 } else if (checkbox == cbx_cpnodeopt_BIT1) { 2419 cbx_cpnodeopt_BIT1.setSelected(false); 2420 } else if (checkbox == cbx_cpnodeopt_BIT2) { 2421 cbx_cpnodeopt_BIT2.setSelected(false); 2422 } else if (checkbox == cbx_cpnodeopt_BIT8) { 2423 curNode.setcpnodeOpts(SerialNode.optbitNode_BIT8, (cbx_cpnodeopt_BIT8.isSelected() ? 1 : 0)); 2424 } else if (checkbox == cbx_cpnodeopt_BIT15) { 2425 curNode.setcpnodeOpts(SerialNode.optbitNode_BIT15, (cbx_cpnodeopt_BIT15.isSelected() ? 1 : 0)); 2426 } 2427 changedNode = true; 2428 } 2429 } 2430 2431 /** 2432 * Set up table for selecting card type by address for CPNODE/CPMEGA nodes 2433 */ 2434 public class CPnodeConfigModel extends AbstractTableModel { 2435 2436 @Override 2437 public String getColumnName(int c) { 2438 return cpnodeConfigColumnNames[c]; 2439 } 2440 2441 @Override 2442 public Class<?> getColumnClass(int c) { 2443 return String.class; 2444 } 2445 2446 @Override 2447 public int getColumnCount() { 2448 return CARDTYPE_COLUMN+1; 2449 } 2450 2451 @Override 2452 public int getRowCount() { 2453 return 16; 2454 } 2455 2456 @Override 2457 public Object getValueAt(int r, int c) { 2458 String[] cdPort = {" A", " B"}; 2459 String val = " "; 2460 // ESP32Node has no onboard-reserved cards (unlike CPNODE's 2 onboard 2461 // OUTPUT bytes, which is why the diagnostic dialog and this label both 2462 // add 2 for CPNODE) -- but it's still numbered 1-based (Card 1 = first 2463 // real card) to match how people naturally count cards, hence +1 here 2464 // (cpNodeOnboard, the actual array-index skip used below for cardType[], 2465 // stays 0 for ESP32Node -- this offset is display-only). 2466 int cardLabelOffset = (nodeType == SerialNode.ESP32NODE) ? 1 : 2; 2467 switch (c) { 2468 case CARD_COLUMN: 2469 val = Integer.toString(r+cardLabelOffset); 2470 return " " + val; 2471 case CARDNUM_COLUMN: 2472 int i = r / 2; 2473 if (r % 2 == 0) { 2474 val = Integer.toHexString(0x20 + i) + " "; 2475 } 2476 return " " + val + " " + cdPort[(r % 2)]; 2477 case CARDTYPE_COLUMN: 2478 return " " + cardType[r + cpNodeOnboard]; 2479 default: 2480 return ""; 2481 } 2482 } 2483 2484 @Override 2485 public void setValueAt(Object type, int r, int c) { 2486 if (c == CARDTYPE_COLUMN) { 2487 cardType[r + cpNodeOnboard] = (String) type; 2488 } 2489 } 2490 2491 @Override 2492 public boolean isCellEditable(int r, int c) { 2493 return (c == CARDTYPE_COLUMN); 2494 } 2495 2496 public static final int CARD_COLUMN = 0; 2497 public static final int CARDNUM_COLUMN = 1; 2498 public static final int CARDTYPE_COLUMN = 2; 2499 } 2500 private final String[] cpnodeConfigColumnNames = {"Card", "IOX Addr Port", "Port Type"}; 2501 2502 /** 2503 * Set up table for selecting card type by address for CPNODE/CPMEGA nodes 2504 */ 2505 public class OSnodeConfigModel extends AbstractTableModel { 2506 2507 @Override 2508 public String getColumnName(int c) { 2509 return osnodeConfigColumnNames[c]; 2510 } 2511 2512 @Override 2513 public Class<?> getColumnClass(int c) { 2514 return String.class; 2515 } 2516 2517 @Override 2518 public int getColumnCount() { 2519 return 2; 2520 } 2521 2522 @Override 2523 public int getRowCount() { 2524 return 8; 2525 } 2526 2527 @Override 2528 public Object getValueAt(int r, int c) { 2529 switch (c) { 2530 case CARDNUM_COLUMN: 2531 int i = r; 2532 return " " + i + " "; 2533 case CARDTYPE_COLUMN: 2534 return " " + onBoardType[r]; 2535 default: 2536 return ""; 2537 } 2538 } 2539 2540 @Override 2541 public void setValueAt(Object type, int r, int c) { 2542 if (c == CARDTYPE_COLUMN) { 2543 onBoardType[r] = (String) type; 2544 } 2545 } 2546 2547 @Override 2548 public boolean isCellEditable(int r, int c) { 2549 return (c == 1); 2550 } 2551 2552 public static final int CARDNUM_COLUMN = 0; 2553 public static final int CARDTYPE_COLUMN = 1; 2554 } 2555 private final String[] osnodeConfigColumnNames = {" Byte ", "Port Type"}; 2556 2557 private final int[] cpnodeOpts = new int[16]; // Local storage for node options 2558 private final int[] cmrinetOpts = new int[16]; // Local storage for node options 2559 2560 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NodeConfigManagerFrame.class); 2561 2562}