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