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