001package jmri.jmrix.cmri.serial.nodeiolist; 002 003import java.awt.*; 004import java.awt.event.ActionEvent; 005import java.awt.event.ActionListener; 006import java.io.IOException; 007import java.util.ArrayList; 008 009import javax.swing.*; 010import javax.swing.border.Border; 011import javax.swing.table.*; 012 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016import jmri.jmrix.cmri.CMRISystemConnectionMemo; 017import jmri.jmrix.cmri.serial.SerialNode; 018import jmri.util.davidflanagan.OriginalHardcopyWriter; 019 020/** 021 * Frame for running CMRI assignment list. 022 * 023 * @author Dave Duchamp Copyright (C) 2006 024 * @author Chuck Catania Copyright (C) 2014, 2016, 2017 025 */ 026public class NodeIOListFrame extends jmri.util.JmriJFrame { 027 028 ArrayList<SerialNode> cmriNode = new ArrayList<SerialNode>(); 029 030 protected boolean inputSelected = true; // true if displaying input assignments, false for output 031 protected SerialNode selNode = null; 032 public int selNodeNum = 0; // Address (ua) of selected Node 033 public int numBits = 48; // number of bits in assignment table 034 public int numInputBits = 24; // number of input bits for selected node 035 public int numOutputBits = 48; // number of output bits for selected node 036 037 // node select pane items 038 JLabel nodeLabel = new JLabel(Bundle.getMessage("NodeBoxLabel") + " "); 039 JLabel nodeAddrBox = new JLabel("??"); 040 ButtonGroup bitTypeGroup = new ButtonGroup(); 041 JRadioButton inputBits = new JRadioButton(Bundle.getMessage("ShowInputButton") + " ", true); 042 JRadioButton outputBits = new JRadioButton(Bundle.getMessage("ShowOutputButton"), false); 043 JLabel nodeInfoText = new JLabel("Node Information Text"); 044 045 JLabel nodeDesc = new JLabel("Description:"); 046 047 // assignment pane items 048 protected JPanel assignmentPanel = null; 049 protected Border inputBorder = BorderFactory.createEtchedBorder(); 050 protected Border inputBorderTitled = BorderFactory.createTitledBorder(inputBorder, 051 Bundle.getMessage("AssignmentPanelInputName")); 052 protected Border outputBorder = BorderFactory.createEtchedBorder(); 053 protected Border outputBorderTitled = BorderFactory.createTitledBorder(outputBorder, 054 Bundle.getMessage("AssignmentPanelOutputName")); 055 protected JTable assignmentTable = null; 056 protected TableModel assignmentListModel = null; 057 058 // button pane items 059 JButton printButton = new JButton(Bundle.getMessage("PrintButtonText")); 060 JButton doneButton = new JButton(Bundle.getMessage("DoneButtonText")); 061 062 NodeIOListFrame curFrame; 063 private CMRISystemConnectionMemo _memo = null; 064 065 public NodeIOListFrame(CMRISystemConnectionMemo memo) { 066 super(); 067 _memo = memo; 068 curFrame = this; 069 } 070 071 /** 072 * {@inheritDoc} 073 */ 074 @Override 075 public void initComponents() { 076 077 // set the frame's initial state 078 setTitle(Bundle.getMessage("WindowTitle") + Bundle.getMessage("WindowConnectionMemo") + _memo.getUserName()); // NOI18N 079 setSize(500, 300); 080 Container contentPane = getContentPane(); 081 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 082 083 // Set up the node selection panel 084 initializeNodes(); 085 if (cmriNode.size() > 0) { 086 inputBits.addActionListener(new ActionListener() { 087 @Override 088 public void actionPerformed(ActionEvent event) { 089 if (inputSelected == false) { 090 inputSelected = true; 091 displayNodeIOBits(selNodeNum); 092 } 093 } 094 }); 095 outputBits.addActionListener(new ActionListener() { 096 @Override 097 public void actionPerformed(ActionEvent event) { 098 if (inputSelected == true) { 099 inputSelected = false; 100 displayNodeIOBits(selNodeNum); 101 } 102 } 103 }); 104 } else { 105 nodeInfoText.setText(Bundle.getMessage("NoNodesError")); 106 } 107 nodeLabel.setToolTipText(Bundle.getMessage("NodeBoxTip")); 108 inputBits.setToolTipText(Bundle.getMessage("ShowInputTip")); 109 outputBits.setToolTipText(Bundle.getMessage("ShowOutputTip")); 110 111 JPanel panel1 = new JPanel(); 112 panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS)); 113 JPanel panel11 = new JPanel(); 114 panel11.add(nodeLabel); 115 bitTypeGroup.add(outputBits); 116 bitTypeGroup.add(inputBits); 117 panel11.add(inputBits); 118 panel11.add(outputBits); 119 JPanel panel12 = new JPanel(); 120 panel12.add(nodeInfoText); 121 122 JPanel panel13 = new JPanel(); 123 panel13.add(nodeDesc); 124 panel13.setVisible(true); 125 nodeDesc.setVisible(false); 126 panel1.add(panel13); 127 128 panel1.add(panel11); 129 panel1.add(panel12); 130 131 Border panel1Border = BorderFactory.createEtchedBorder(); 132 Border panel1Titled = BorderFactory.createTitledBorder(panel1Border, Bundle.getMessage("NodePanelName") + " " + _memo.getUserName()); 133 panel1.setBorder(panel1Titled); 134 contentPane.add(panel1); 135 136// Set up the assignment panel 137 assignmentPanel = new JPanel(); 138 assignmentPanel.setLayout(new BoxLayout(assignmentPanel, BoxLayout.Y_AXIS)); 139 assignmentListModel = new AssignmentTableModel(); 140 assignmentTable = new JTable(assignmentListModel); 141 assignmentTable.setRowSelectionAllowed(false); 142 assignmentTable.setPreferredScrollableViewportSize(new java.awt.Dimension(300, 350)); 143 144 TableColumnModel assignmentColumnModel = assignmentTable.getColumnModel(); 145 TableColumn bitColumn = assignmentColumnModel.getColumn(AssignmentTableModel.BIT_COLUMN); 146 bitColumn.setMinWidth(20); 147 bitColumn.setMaxWidth(40); 148 bitColumn.setResizable(true); 149 TableColumn addressColumn = assignmentColumnModel.getColumn(AssignmentTableModel.ADDRESS_COLUMN); 150 addressColumn.setMinWidth(40); 151 addressColumn.setMaxWidth(85); 152 addressColumn.setResizable(true); 153 TableColumn sysColumn = assignmentColumnModel.getColumn(AssignmentTableModel.SYSNAME_COLUMN); 154 sysColumn.setMinWidth(90); 155 sysColumn.setMaxWidth(150); 156 sysColumn.setResizable(true); 157 TableColumn userColumn = assignmentColumnModel.getColumn(AssignmentTableModel.USERNAME_COLUMN); 158 userColumn.setMinWidth(90); 159 userColumn.setMaxWidth(250); 160 userColumn.setResizable(true); 161 assignmentColumnModel.getColumn(AssignmentTableModel.COMMENT_COLUMN); 162 userColumn.setMinWidth(90); 163 userColumn.setMaxWidth(250); 164 userColumn.setResizable(true); 165 JScrollPane assignmentScrollPane = new JScrollPane(assignmentTable); 166 assignmentPanel.add(assignmentScrollPane, BorderLayout.CENTER); 167 if (inputSelected) { 168 assignmentPanel.setBorder(inputBorderTitled); 169 } else { 170 assignmentPanel.setBorder(outputBorderTitled); 171 } 172 contentPane.add(assignmentPanel); 173 174 // Set up Print button 175 JPanel panel3 = new JPanel(); 176 panel3.setLayout(new FlowLayout()); 177 printButton.setVisible(true); 178 printButton.setToolTipText(Bundle.getMessage("PrintButtonTip")); 179 if (cmriNode.size() > 0) { 180 printButton.addActionListener(new java.awt.event.ActionListener() { 181 @Override 182 public void actionPerformed(java.awt.event.ActionEvent e) { 183 printButtonActionPerformed(e); 184 } 185 }); 186 } 187 panel3.add(printButton); 188 contentPane.add(panel3); 189 190 doneButton.setVisible(true); 191 doneButton.setToolTipText(Bundle.getMessage("DoneButtonTip")); 192 if (cmriNode.size() > 0) { 193 doneButton.addActionListener(new java.awt.event.ActionListener() { 194 @Override 195 public void actionPerformed(java.awt.event.ActionEvent e) { 196 doneButtonActionPerformed(); 197 } 198 }); 199 } 200 panel3.add(doneButton); 201 202 addHelpMenu("package.jmri.jmrix.cmri.serial.assignment.ListFrame", true); 203 204 // pack for display 205 pack(); 206 } 207 208 /** 209 * Method to initialize configured nodes and set up the node select combo 210 * box 211 */ 212 public void initializeNodes() { 213 // get all configured nodes 214 215 SerialNode node = (SerialNode) _memo.getTrafficController().getNode(0); 216 217 int index = 0; //1 218 while (node != null) { 219 cmriNode.add(node); 220 node = (SerialNode) _memo.getTrafficController().getNode(index); 221 index++; 222 } 223// node = (SerialNode) SerialTrafficController.instance().getNode(index); 224// index ++; 225 } 226 227 /** 228 * Method to handle selection of a Node for info display. 229 * @param nodeID node ID number. 230 */ 231 public void displayNodeIOBits(int nodeID) { 232 nodeLabel.setText("Node: " + nodeID + " "); 233 selNodeNum = nodeID; 234 nodeDesc.setText(""); 235 for (int i = 0; i < cmriNode.size(); i++) { 236 if (cmriNode.get(i).getNodeAddress() == nodeID) { 237 selNode = cmriNode.get(i); 238 } 239 } 240 String nodeType = ""; 241 int type = selNode.getNodeType(); 242 int bitsPerCard = selNode.getNumBitsPerCard(); 243 int numInputCards = selNode.numInputCards(); 244 int numOutputCards = selNode.numOutputCards(); 245 246 switch (type) { 247 case SerialNode.SMINI: 248 numInputBits = 24; 249 numOutputBits = 48; 250 nodeType = "SMINI - "; 251 break; 252 case SerialNode.USIC_SUSIC: 253 numInputBits = bitsPerCard * numInputCards; 254 numOutputBits = bitsPerCard * numOutputCards; 255 nodeType = "USIC_SUSIC - "; 256 break; 257 case SerialNode.CPNODE: 258 numInputBits = bitsPerCard * numInputCards; 259 numOutputBits = bitsPerCard * numOutputCards; 260 nodeType = "CPNODE - "; 261 break; 262 case SerialNode.CPMEGA: 263 numInputBits = bitsPerCard * numInputCards; 264 numOutputBits = bitsPerCard * numOutputCards; 265 nodeType = "CPMEGA - "; 266 break; 267 default: 268 break; 269 } 270 nodeInfoText.setText(nodeType + bitsPerCard + " " + Bundle.getMessage("BitsPerCard") + ", " 271 + numInputBits + " " + Bundle.getMessage("InputBitsAnd") + " " 272 + numOutputBits + " " + Bundle.getMessage("OutputBits")); 273 String name = selNode.getcmriNodeDesc(); 274 if (name != null && (!name.isEmpty())) { 275 nodeDesc.setText(Bundle.getMessage("NodeDesc") + " " + name); 276 nodeDesc.setVisible(true); 277 } 278 279 // initialize for input or output assignments 280 if (inputSelected) { 281 numBits = numInputBits; 282 assignmentPanel.setBorder(inputBorderTitled); 283 } else { 284 numBits = numOutputBits; 285 assignmentPanel.setBorder(outputBorderTitled); 286 } 287 ((AssignmentTableModel) assignmentListModel).fireTableDataChanged(); 288 } 289 290 /* Done button handler */ 291 public void doneButtonActionPerformed() { 292 setVisible(false); 293 dispose(); 294 } 295 296 /** 297 * Method to handle print button in List Frame. 298 * @param e unused. 299 */ 300 public void printButtonActionPerformed(java.awt.event.ActionEvent e) { 301 int[] colWidth = new int[5]; 302 // initialize column widths 303 TableColumnModel assignmentColumnModel = assignmentTable.getColumnModel(); 304 colWidth[0] = assignmentColumnModel.getColumn(AssignmentTableModel.BIT_COLUMN).getWidth(); 305 colWidth[1] = assignmentColumnModel.getColumn(AssignmentTableModel.ADDRESS_COLUMN).getWidth(); 306 colWidth[2] = assignmentColumnModel.getColumn(AssignmentTableModel.SYSNAME_COLUMN).getWidth(); 307 colWidth[3] = assignmentColumnModel.getColumn(AssignmentTableModel.USERNAME_COLUMN).getWidth(); 308 colWidth[4] = assignmentColumnModel.getColumn(AssignmentTableModel.COMMENT_COLUMN).getWidth(); 309 // set up a page title 310 String head; 311 if (inputSelected) { 312 head = Bundle.getMessage("Connection") +" "+ _memo.getUserName() + " "+ Bundle.getMessage("AssignmentPanelInputName") + " " 313 + Bundle.getMessage("NodeBoxLabel") + " " + selNodeNum + " "; 314 } else { 315 head = Bundle.getMessage("Connection") +" "+ _memo.getUserName() + " " + Bundle.getMessage("AssignmentPanelOutputName") + " " 316 + Bundle.getMessage("NodeBoxLabel") + " " + selNodeNum + " "; 317 } 318 // initialize a printer writer 319 OriginalHardcopyWriter writer = null; 320 try { 321 writer = new OriginalHardcopyWriter(curFrame, head, 10, .8, .5, .5, .5, false); 322 } catch (OriginalHardcopyWriter.PrintCanceledException ex) { 323 //log.debug("Print cancelled"); 324 return; 325 } 326 writer.increaseLineSpacing(20); 327 // print the assignments 328 ((AssignmentTableModel) assignmentListModel).printTable(writer, colWidth); 329 } 330 331 /** 332 * Set up table for displaying bit assignments 333 */ 334 public class AssignmentTableModel extends AbstractTableModel { 335 336 private String free = Bundle.getMessage("AssignmentFree"); 337 private int curRow = -1; 338 private String curRowSysName = ""; 339 340 @Override 341 public String getColumnName(int c) { 342 return assignmentTableColumnNames[c]; 343 } 344 345 @Override 346 public Class<?> getColumnClass(int c) { 347 return String.class; 348 } 349 350 @Override 351 public boolean isCellEditable(int r, int c) { 352 return false; 353 } 354 355 @Override 356 public int getColumnCount() { 357 return MAX_COLS; 358 } 359 360 @Override 361 public int getRowCount() { 362 return numBits; 363 } 364 365 @Override 366 public Object getValueAt(int r, int c) { 367 if (c == BIT_COLUMN) { 368 return Integer.toString(r + 1); 369 } else if (c == ADDRESS_COLUMN) { 370 return Integer.toString((selNodeNum * 1000) + r + 1); 371 } else if (c == SYSNAME_COLUMN) { 372 String sName = null; 373 if (curRow != r) { 374 375 if (inputSelected) { 376 sName = _memo.isInputBitFree(selNodeNum, (r + 1)); 377 } else { 378 sName = _memo.isOutputBitFree(selNodeNum, (r + 1)); 379 } 380 curRow = r; 381 curRowSysName = sName; 382 } else { 383 sName = curRowSysName; 384 } 385 if (sName == null) { 386 return (free); 387 } else { 388 return sName; 389 } 390 } else if (c == USERNAME_COLUMN) { 391 String sName = null; 392 if (curRow != r) { 393 394 if (inputSelected) { 395 sName = _memo.isInputBitFree(selNodeNum, (r + 1)); 396 } else { 397 sName = _memo.isOutputBitFree(selNodeNum, (r + 1)); 398 } 399 400 curRow = r; 401 curRowSysName = sName; 402 } else { 403 sName = curRowSysName; 404 } 405 if (sName == null) { 406 return (""); 407 } else { 408 return (_memo.getUserNameFromSystemName(sName)); 409 } 410 } else if (c == COMMENT_COLUMN) { 411 String sName = null; 412 if (curRow != r) { 413 if (inputSelected) { 414 sName = _memo.isInputBitFree(selNodeNum, (r + 1)); 415 } else { 416 sName = _memo.isOutputBitFree(selNodeNum, (r + 1)); 417 } 418 curRow = r; 419 curRowSysName = sName; 420 } else { 421 sName = curRowSysName; 422 } 423 424 if (sName == null) { 425 return (""); 426 } 427 428 if (inputSelected) { 429 jmri.Sensor s = null; 430 s = jmri.InstanceManager.sensorManagerInstance().getBySystemName(sName); 431 if (s != null) { 432 return s.getComment(); 433 } 434 } else { 435 jmri.Turnout t = null; 436 t = jmri.InstanceManager.turnoutManagerInstance().getBySystemName(sName); 437 if (t != null) { 438 return t.getComment(); 439 } 440 } 441 442 } 443 444 return ""; // fall through 445 } 446 447 @Override 448 public void setValueAt(Object type, int r, int c) { 449 // nothing is stored here 450 } 451 452 public static final int BIT_COLUMN = 0; 453 public static final int ADDRESS_COLUMN = 1; 454 public static final int SYSNAME_COLUMN = 2; 455 public static final int USERNAME_COLUMN = 3; 456 public static final int COMMENT_COLUMN = 4; 457 public static final int MAX_COLS = COMMENT_COLUMN + 1; 458 459 /** 460 * Method to print or print preview the assignment table. Printed in 461 * proportionately sized columns across the page with headings and 462 * vertical lines between each column. Data is word wrapped within a 463 * column. Can only handle 4 columns of data as strings. Adapted from 464 * routines in BeanTableDataModel.java by Bob Jacobsen and Dennis Miller 465 * @param w hard copy writer instance. 466 * @param colWidth column width array. 467 */ 468 public void printTable(OriginalHardcopyWriter w, int colWidth[]) { 469 // determine the column sizes - proportionately sized, with space between for lines 470 int[] columnSize = new int[MAX_COLS]; 471 int charPerLine = w.getCharactersPerLine(); 472 int tableLineWidth = 0; // table line width in characters 473 int totalColWidth = 0; 474 for (int j = 0; j < MAX_COLS; j++) { 475 totalColWidth += colWidth[j]; 476 } 477 float ratio = ((float) charPerLine) / ((float) totalColWidth); 478 for (int j = 0; j < MAX_COLS; j++) { 479 columnSize[j] = ((int) (colWidth[j] * ratio)) - 1; 480 tableLineWidth += (columnSize[j] + 1); 481 } 482 483 // Draw horizontal dividing line 484 w.write(w.getCurrentLineNumber(), 0, w.getCurrentLineNumber(), 485 tableLineWidth); 486 487 // print the column header labels 488 String[] columnStrings = new String[MAX_COLS]; 489 // Put each column header in the array 490 for (int i = 0; i < MAX_COLS; i++) { 491 columnStrings[i] = this.getColumnName(i); 492 } 493 //w.setFontStyle(Font.BOLD); 494 printColumns(w, columnStrings, columnSize); 495 w.setFontStyle(Font.PLAIN); 496 // draw horizontal line 497 w.write(w.getCurrentLineNumber(), 0, w.getCurrentLineNumber(), 498 tableLineWidth); 499 500 // now print each row of data 501 String[] spaces = new String[MAX_COLS]; 502 // create base strings the width of each of the columns 503 for (int k = 0; k < MAX_COLS; k++) { 504 spaces[k] = ""; 505 for (int i = 0; i < columnSize[k]; i++) { 506 spaces[k] = spaces[k] + " "; 507 } 508 } 509 for (int i = 0; i < this.getRowCount(); i++) { 510 for (int j = 0; j < MAX_COLS; j++) { 511 //check for special, null contents 512 if (this.getValueAt(i, j) == null) { 513 columnStrings[j] = spaces[j]; 514 } else { 515 columnStrings[j] = (String) this.getValueAt(i, j); 516 } 517 } 518 printColumns(w, columnStrings, columnSize); 519 // draw horizontal line 520 w.write(w.getCurrentLineNumber(), 0, w.getCurrentLineNumber(), 521 tableLineWidth); 522 } 523 w.close(); 524 } 525 526 protected void printColumns(OriginalHardcopyWriter w, String columnStrings[], int columnSize[]) { 527 String columnString = ""; 528 StringBuilder lineString = new StringBuilder(""); 529 String[] spaces = new String[MAX_COLS]; 530 // create base strings the width of each of the columns 531 for (int k = 0; k < MAX_COLS; k++) { 532 spaces[k] = ""; 533 for (int i = 0; i < columnSize[k]; i++) { 534 spaces[k] = spaces[k] + " "; 535 } 536 } 537 // loop through each column 538 boolean complete = false; 539 while (!complete) { 540 complete = true; 541 for (int i = 0; i < MAX_COLS; i++) { 542 // if the column string is too wide cut it at word boundary (valid delimiters are space, - and _) 543 // use the initial part of the text,pad it with spaces and place the remainder back in the array 544 // for further processing on next line 545 // if column string isn't too wide, pad it to column width with spaces if needed 546 if (columnStrings[i].length() > columnSize[i]) { 547 // this column string will not fit on one line 548 boolean noWord = true; 549 for (int k = columnSize[i]; k >= 1; k--) { 550 if (columnStrings[i].substring(k - 1, k).equals(" ") 551 || columnStrings[i].substring(k - 1, k).equals("-") 552 || columnStrings[i].substring(k - 1, k).equals("_")) { 553 columnString = columnStrings[i].substring(0, k) 554 + spaces[i].substring(columnStrings[i].substring(0, k).length()); 555 columnStrings[i] = columnStrings[i].substring(k); 556 noWord = false; 557 complete = false; 558 break; 559 } 560 } 561 if (noWord) { 562 columnString = columnStrings[i].substring(0, columnSize[i]); 563 columnStrings[i] = columnStrings[i].substring(columnSize[i]); 564 complete = false; 565 } 566 } else { 567 // this column string will fit on one line 568 columnString = columnStrings[i] + spaces[i].substring(columnStrings[i].length()); 569 columnStrings[i] = ""; 570 } 571 lineString.append(columnString).append(" "); 572 } 573 try { 574 w.write(lineString.toString()); 575 //write vertical dividing lines 576 int iLine = w.getCurrentLineNumber(); 577 for (int i = 0, k = 0; i < w.getCharactersPerLine(); k++) { 578 w.write(iLine, i, iLine + 1, i); 579 if (k < MAX_COLS) { 580 i = i + columnSize[k] + 1; 581 } else { 582 i = w.getCharactersPerLine(); 583 } 584 } 585 w.write("\n"); 586 lineString = new StringBuilder(""); 587 } catch (IOException e) { 588 log.warn("error during printing", e); 589 } 590 } 591 } 592 } 593 private String[] assignmentTableColumnNames = {Bundle.getMessage("HeadingBit"), 594 Bundle.getMessage("HeadingAddress"), 595 Bundle.getMessage("HeadingSystemName"), 596 Bundle.getMessage("HeadingUserName"), 597 Bundle.getMessage("HeadingComment")}; 598 599 private final static Logger log = LoggerFactory.getLogger(NodeIOListFrame.class); 600 601} 602