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