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