001package jmri.jmrix.can.cbus.swing.modules.sprogdcc;
002
003import java.awt.GridBagConstraints;
004import java.awt.GridBagLayout;
005
006import javax.swing.*;
007import javax.swing.event.TableModelEvent;
008
009import jmri.jmrix.can.cbus.node.CbusNode;
010import jmri.jmrix.can.cbus.node.CbusNodeNVTableDataModel;
011import static jmri.jmrix.can.cbus.node.CbusNodeNVTableDataModel.NV_SELECT_COLUMN;
012import jmri.jmrix.can.cbus.swing.modules.*;
013
014import org.slf4j.Logger;
015import org.slf4j.LoggerFactory;
016
017/**
018 * Node Variable edit frame for a SPROG DCC CANSERVOIO module
019 *
020 * @author Andrew Crosland Copyright (C) 2021
021 */
022public class CanisbEditNVPane extends AbstractEditNVPane {
023
024    private final UpdateNV canIdUpdateFn = new UpdateCanId();
025    private final UpdateNV nodeNumberUpdateFn = new UpdateNodeNumber();
026    private final UpdateNV arbDelayUpdateFn = new UpdateArbDelay();
027
028    private JRadioButton setup;
029    private TitledSpinner canIdSpinner;
030    private TitledSpinner nodeNumberSpinner;
031    private JRadioButton disable;
032    private TitledSpinner arbDelaySpinner;
033    
034    // Read/Clear error status
035    String[] rcTitle = {Bundle.getMessage("CanErrStatus")+" 1",
036        Bundle.getMessage("CanErrStatus")+" 2",
037        Bundle.getMessage("CanTxFailureCount"),
038        Bundle.getMessage("CanRxOverflowCount"),
039        Bundle.getMessage("CanNomBitRateRxCount"),
040        Bundle.getMessage("CanNomBitRateTxCount"),
041        Bundle.getMessage("CanDiagnostics")+" Hi",
042        Bundle.getMessage("CanDiagnostics")+" Lo",
043        Bundle.getMessage("CanErrFreeCount")
044    };
045    String[] rcTt = {Bundle.getMessage("CanErrStatus1Tt"),
046        Bundle.getMessage("CanErrStatus2Tt"),
047        Bundle.getMessage("CanTxFailureCountTt"),
048        Bundle.getMessage("CanRxOverflowCountTt"),
049        Bundle.getMessage("CanNomBitRateRxCountTt"),
050        Bundle.getMessage("CanNomBitRateTxCountTt"),
051        Bundle.getMessage("CanDiagnosticsHiTt"),
052        Bundle.getMessage("CanDiagnosticsLoTt"),
053        Bundle.getMessage("CanErrFreeCountTt")
054    };
055    int clearableErrors = rcTitle.length;
056    JLabel[] rcText = new JLabel[clearableErrors];
057    JTextField[] rcCount = new JTextField[clearableErrors];
058    JButton[] rcButton = new JButton[clearableErrors];
059    JButton rcAllButton = new JButton();
060    JButton[] rcUpButton = new JButton[clearableErrors];
061    JButton rcAllUpButton = new JButton();
062    // Translate clear button index to NV index
063    int[] rcNvOffset = {CanisbPaneProvider.CAN_ERR_STATUS_1,
064        CanisbPaneProvider.CAN_ERR_STATUS_2,
065        CanisbPaneProvider.TX_FAIL_CNT,
066        CanisbPaneProvider.RX_OVFLW_COUNT,
067        CanisbPaneProvider.CAN_NOM_BIT_RATE_RX_COUNT,
068        CanisbPaneProvider.CAN_NOM_BIT_RATE_TX_COUNT,
069        CanisbPaneProvider.CAN_DIAGNOSTICS_HI,
070        CanisbPaneProvider.CAN_DIAGNOSTICS_LO,
071        CanisbPaneProvider.CAN_ERR_FREE_COUNT_HI
072    };
073    
074    // Read only error status
075    String[] rTitle = {Bundle.getMessage("CanRxErrorCount"),
076        Bundle.getMessage("CanTxErrorCount")
077    };
078    String[] rTt = {Bundle.getMessage("CanRxErrorCountTt"),
079        Bundle.getMessage("CanTxErrorCountTt")
080    };
081    int rErrors = rTitle.length;
082    JLabel[] rText = new JLabel[rErrors];
083    JTextField[] rCount = new JTextField[rErrors];
084    JButton[] rUpButton = new JButton[rErrors];
085
086    String[] commsTitle = {Bundle.getMessage("HostTxCnt"),
087        Bundle.getMessage("HostRxCnt"),
088        Bundle.getMessage("CanTxCnt"),
089        Bundle.getMessage("CanRxCnt")
090    };
091    String[] commsToolTips = {Bundle.getMessage("HostTxCntTt"),
092        Bundle.getMessage("HostRxCntTt"),
093        Bundle.getMessage("CanTxCntTt"),
094        Bundle.getMessage("CanRxCntTt")
095    };
096    int commsItems = commsTitle.length;
097    JLabel[] commsText = new JLabel[commsItems];
098    JTextField[] commsCount = new JTextField[commsItems];
099    JButton[] commsButton = new JButton[commsItems];
100    JButton commsAllButton = new JButton();
101    JButton[] commsUpButton = new JButton[commsItems];
102    JButton commsAllUpButton = new JButton();
103    // Translate comms button index to NV index
104    int[] commsNvOffset = {CanisbPaneProvider.HOST_TX_CNT_T,
105        CanisbPaneProvider.HOST_RX_CNT_T,
106        CanisbPaneProvider.CAN_TX_CNT_T,
107        CanisbPaneProvider.CAN_RX_CNT_T
108    };
109    
110    protected CanisbEditNVPane(CbusNodeNVTableDataModel dataModel, CbusNode node) {
111        super(dataModel, node);
112    }
113
114    /**
115     * {@inheritDoc}
116     */
117    @Override
118    public AbstractEditNVPane getContent() {
119        JTabbedPane tabbedPane = new JTabbedPane();
120
121        JPanel cbusPane = new CbusPane();
122        JPanel diagnosticsPane = new DiagnosticsPane();
123        JPanel commsPane = new CommsPane();
124        tabbedPane.addTab("CBUS", cbusPane);
125        tabbedPane.addTab(Bundle.getMessage("CanDiagnostics"), diagnosticsPane);
126        tabbedPane.addTab(Bundle.getMessage("PacketCounts"), commsPane);
127
128        JScrollPane scroll = new JScrollPane(tabbedPane);
129        add(scroll);
130
131        return this;
132    }
133
134    /**
135     * {@inheritDoc}
136     */
137    @Override
138    public void tableChanged(TableModelEvent e) {
139//        log.debug("canisb table changed");
140        if (e.getType() == TableModelEvent.UPDATE) {
141            int row = e.getFirstRow();
142            int nv = row + 1;
143            int value = getSelectValue8(nv);
144            log.debug("canisb gui table changed NV: {} Value: {}", nv, value);
145            if (value >= -1) {
146                switch (nv) {
147                    case CanisbPaneProvider.SETUP:
148                        setup.setSelected(value != 0);
149                        break;
150
151                    case CanisbPaneProvider.CANID:
152                        canIdSpinner.setValue(getSelectValue8(CanisbPaneProvider.CANID,
153                                CanisbPaneProvider.MIN_CANID, CanisbPaneProvider.MAX_CANID));
154                        break;
155
156                    case CanisbPaneProvider.NN_HI:
157                    case CanisbPaneProvider.NN_LO:
158                        nodeNumberSpinner.setValue(getSelectValue16(CanisbPaneProvider.NN_HI,
159                                CanisbPaneProvider.NN_LO, CanisbPaneProvider.MIN_NN, CanisbPaneProvider.MAX_NN));
160                        break;
161
162                    case CanisbPaneProvider.RX_ERR_CNT:
163                        rCount[0].setText(Integer.toString(value));
164                        break;
165
166                    case CanisbPaneProvider.TX_ERR_CNT:
167                        rCount[1].setText(Integer.toString(value));
168                        break;
169
170                    case CanisbPaneProvider.CAN_ERR_STATUS_1:
171                        rcCount[0].setText(Integer.toString(value));
172                        break;
173
174                    case CanisbPaneProvider.CAN_ERR_STATUS_2:
175                        rcCount[1].setText(Integer.toString(value));
176                        break;
177
178                    case CanisbPaneProvider.TX_FAIL_CNT:
179                        rcCount[2].setText(Integer.toString(value));
180                        break;
181
182                    case CanisbPaneProvider.RX_OVFLW_COUNT:
183                        rcCount[3].setText(Integer.toString(value));
184                        break;
185
186                    case CanisbPaneProvider.CAN_NOM_BIT_RATE_RX_COUNT:
187                        rcCount[4].setText(Integer.toString(value));
188                        break;
189
190                    case CanisbPaneProvider.CAN_NOM_BIT_RATE_TX_COUNT:
191                        rcCount[5].setText(Integer.toString(value));
192                        break;
193
194                    case CanisbPaneProvider.CAN_DIAGNOSTICS_HI:
195                        rcCount[6].setText(Integer.toString(value));
196                        break;
197
198                    case CanisbPaneProvider.CAN_DIAGNOSTICS_LO:
199                        rcCount[7].setText(Integer.toString(value));
200                        break;
201
202                    case CanisbPaneProvider.CAN_ERR_FREE_COUNT_HI:
203                        // Do not update display until LO byte is handled
204                        break;
205
206                    case CanisbPaneProvider.CAN_ERR_FREE_COUNT_LO:
207                        rcCount[8].setText(Integer.toString(value
208                                + (int)_dataModel.getValueAt(CanisbPaneProvider.CAN_ERR_FREE_COUNT_HI - 1, NV_SELECT_COLUMN)*256));
209                        break;
210
211                    case CanisbPaneProvider.HOST_TX_CNT_T:
212                    case CanisbPaneProvider.HOST_TX_CNT_U:
213                    case CanisbPaneProvider.HOST_TX_CNT_H:
214                    case CanisbPaneProvider.HOST_RX_CNT_T:
215                    case CanisbPaneProvider.HOST_RX_CNT_U:
216                    case CanisbPaneProvider.HOST_RX_CNT_H:
217                    case CanisbPaneProvider.CAN_TX_CNT_T:
218                    case CanisbPaneProvider.CAN_TX_CNT_U:
219                    case CanisbPaneProvider.CAN_TX_CNT_H:
220                    case CanisbPaneProvider.CAN_RX_CNT_T:
221                    case CanisbPaneProvider.CAN_RX_CNT_U:
222                    case CanisbPaneProvider.CAN_RX_CNT_H:
223                        // Ignore until Lo byte is seen
224                        break;
225                        
226                    case CanisbPaneProvider.HOST_TX_CNT_L:
227                    case CanisbPaneProvider.HOST_RX_CNT_L:
228                    case CanisbPaneProvider.CAN_TX_CNT_L:
229                    case CanisbPaneProvider.CAN_RX_CNT_L:
230                        // Get index of top byte NV
231                        int top = nv - CanisbPaneProvider.HOST_TX_CNT_T;
232                        top -= top%4;           // 0, 4, 8,...
233                        int topNv = top + CanisbPaneProvider.HOST_TX_CNT_T;
234                        commsCount[top/4].setText(Integer.toString(getSelectValue32(topNv)));
235                        break;
236                        
237                    case CanisbPaneProvider.CAN_TX_ARB_DELAY:
238                        arbDelaySpinner.setValue(getSelectValue8(CanisbPaneProvider.CAN_TX_ARB_DELAY,
239                                0, 15));
240                        break;
241                        
242                    default:
243                    // Not used, or row was -1
244                    //                    log.debug("Update unknown NV {}", nv);
245                }
246            }
247        }
248    }
249
250    /**
251     * Update the CAN ID
252     * <p>
253     * For debug only, CAN ID is not normally set this way
254     */
255    protected class UpdateCanId implements UpdateNV {
256
257        /**
258         * {@inheritDoc}
259         */
260        @Override
261        public void setNewVal(int index) {
262            int canId = canIdSpinner.getIntegerValue();
263            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
264            _dataModel.setValueAt(canId, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
265        }
266    }
267
268    /**
269     * Update the node number
270     * <p>
271     * For debug only, CAN ID is not normally set this way
272     */
273    protected class UpdateNodeNumber implements UpdateNV {
274
275        /**
276         * {@inheritDoc}
277         */
278        @Override
279        public void setNewVal(int index) {
280            int nn = nodeNumberSpinner.getIntegerValue();
281            int nnHi = nn / 256;
282            int nnLo = nn % 256;
283            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
284            _dataModel.setValueAt(nnHi, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
285            _dataModel.setValueAt(nnLo, index, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
286        }
287    }
288
289    /**
290     * Update the number of times a DCC accessory packet is repeated
291     */
292    protected class UpdateArbDelay implements UpdateNV {
293        
294        /** {@inheritDoc} */
295        @Override
296        public void setNewVal(int index) {
297            int cnt = arbDelaySpinner.getIntegerValue();
298            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
299            _dataModel.setValueAt(cnt, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
300        }
301    }
302
303    /**
304     * Clearable errors clear button action
305     * 
306     * Translate the button index to the NV index and clear the NV.
307     * 
308     * Multi byte NV clearing is handled by the hardware node, but we have to
309     * clear them all to ensure the table update mechanism works.
310     * 
311     * @param button the button index
312     */
313    public void rcButtonActionPerformed(int button) {
314        _dataModel.setValueAt(0, rcNvOffset[button] - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
315        if (rcNvOffset[button] == CanisbPaneProvider.CAN_ERR_FREE_COUNT_HI) {
316            _dataModel.setValueAt(0, rcNvOffset[button], CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
317        }
318    }
319
320    /**
321     * Clear all clearable errors
322     */
323    public void allButtonActionPerformed() {
324        for (int i = 0; i < clearableErrors; i++) {
325            rcButtonActionPerformed(i);
326        }
327    }
328    
329    /**
330     * Clearable errors update button action
331     * 
332     * Translate the button index to the NV index and clear the NV.
333     * 
334     * @param button the button index
335     */
336    public void rcUpButtonActionPerformed(int button) {
337        _node.send.nVRD(_node.getNodeNumber(), rcNvOffset[button]);
338        if (rcNvOffset[button] == CanisbPaneProvider.CAN_ERR_FREE_COUNT_HI) {
339            _node.send.nVRD(_node.getNodeNumber()+1, rcNvOffset[button]);
340        }
341    }
342
343    /**
344     * Read only errors update button action
345     * 
346     * Translate the button index to the NV index and clear the NV.
347     * 
348     * @param button the button index
349     */
350    public void rUpButtonActionPerformed(int button) {
351        _node.send.nVRD(_node.getNodeNumber(), rcNvOffset[button]);
352    }
353
354    /**
355     * Update all clearable and read only errors
356     */
357    public void rcAllUpButtonActionPerformed() {
358        for (int i = 0; i < clearableErrors; i++) {
359            rcUpButtonActionPerformed(i);
360        }
361        for (int i = 0; i < rErrors; i++) {
362            rUpButtonActionPerformed(i);
363        }
364    }
365    
366    /**
367     * Communications clear button action
368     * 
369     * Translate the button index to the NV index and clear the NV
370     * 
371     * Multi byte NV clearing is handled by the hardware node, but we have to
372     * clear them all to ensure the table update mechanism works.
373     * 
374     * @param button the button index
375     */
376    public void commsButtonActionPerformed(int button) {
377        _dataModel.setValueAt(0, commsNvOffset[button] - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
378        _dataModel.setValueAt(0, commsNvOffset[button], CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
379        _dataModel.setValueAt(0, commsNvOffset[button] + 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
380        _dataModel.setValueAt(0, commsNvOffset[button] + 2, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
381    }
382
383    /**
384     * Communications update button action
385     */
386    public void commsAllButtonActionPerformed() {
387        for (int i = 0; i < commsItems; i++) {
388            commsButtonActionPerformed(i);
389        }
390    }
391    
392    /**
393     * Communications button update action
394     * 
395     * Translate the button index to the NV index and update the NV
396     * 
397     * THese are all 4-byte NVs
398     * 
399     * @param button the button index
400     */
401    public void commsUpButtonActionPerformed(int button) {
402       _node.send.nVRD(_node.getNodeNumber(), commsNvOffset[button]);
403       _node.send.nVRD(_node.getNodeNumber()+1, commsNvOffset[button]);
404       _node.send.nVRD(_node.getNodeNumber()+2, commsNvOffset[button]);
405       _node.send.nVRD(_node.getNodeNumber()+3, commsNvOffset[button]);
406    }
407
408    /**
409     * Update all comms status
410     */
411    public void commsAllUpButtonActionPerformed() {
412        for (int i = 0; i < commsItems; i++) {
413            commsUpButtonActionPerformed(i);
414        }
415    }
416    
417    /**
418     * Panel to display CBUS operation related NVs
419     */
420    public class CbusPane extends JPanel {
421
422        public CbusPane() {
423            super();
424
425            JPanel gridPane = new JPanel(new GridBagLayout());
426            GridBagConstraints c = new GridBagConstraints();
427            c.fill = GridBagConstraints.HORIZONTAL;
428
429            c.weightx = 1;
430            c.weighty = 1;
431            c.gridx = 0;
432            c.gridy = 0;
433
434            canIdSpinner = new TitledSpinner(Bundle.getMessage("CanId"), CanisbPaneProvider.CANID, canIdUpdateFn);
435            canIdSpinner.setToolTip(Bundle.getMessage("CanIdTt"));
436            canIdSpinner.init(getSelectValue8(CanisbPaneProvider.CANID, 100, 127), CanisbPaneProvider.MIN_CANID, CanisbPaneProvider.MAX_CANID, 1);
437            gridPane.add(canIdSpinner, c);
438            c.gridy++;
439
440            nodeNumberSpinner = new TitledSpinner(Bundle.getMessage("NodeNumber"), CanisbPaneProvider.NN_HI, nodeNumberUpdateFn);
441            nodeNumberSpinner.setToolTip(Bundle.getMessage("NodeNumberTt"));
442            int nn = getSelectValue16(CanisbPaneProvider.NN_HI, CanisbPaneProvider.NN_LO, CanisbPaneProvider.MIN_NN, CanisbPaneProvider.MAX_NN);
443            nodeNumberSpinner.init(nn, CanisbPaneProvider.MIN_NN, CanisbPaneProvider.MAX_NN, 1);
444            gridPane.add(nodeNumberSpinner, c);
445            c.gridy++;
446
447            setup = new JRadioButton("SetupMode");
448            setup.setSelected(false);
449            setup.setToolTipText(Bundle.getMessage("SetupModeTt"));
450            gridPane.add(setup, c);
451            c.gridy++;
452
453            disable = new JRadioButton("DisableCan");
454            disable.setSelected(false);
455            disable.setToolTipText(Bundle.getMessage("DisableCanTt"));
456            gridPane.add(disable, c);
457            c.gridy++;
458
459            arbDelaySpinner = new TitledSpinner(Bundle.getMessage("TxArbDelay"), CanisbPaneProvider.CAN_TX_ARB_DELAY, arbDelayUpdateFn);
460            arbDelaySpinner.setToolTip(Bundle.getMessage("TxArbDelayTt"));
461            arbDelaySpinner.init(getSelectValue8(CanisbPaneProvider.CAN_TX_ARB_DELAY, 0, 15), 0, 15, 1);
462            gridPane.add(arbDelaySpinner, c);
463            c.gridy++;
464            
465            add(gridPane);
466        }
467    }
468
469    /**
470     * Panel to display CBUS operation related NVs
471     */
472    public class DiagnosticsPane extends JPanel {
473
474        public DiagnosticsPane() {
475            super();
476
477            JPanel gridPane = new JPanel(new GridBagLayout());
478            GridBagConstraints c = new GridBagConstraints();
479            c.fill = GridBagConstraints.HORIZONTAL;
480
481            c.weightx = 1;
482            c.weighty = 1;
483            c.gridx = 0;
484            c.gridy = 0;
485
486            JLabel errControl = new JLabel(Bundle.getMessage("CanErrControl"));
487            gridPane.add(errControl, c);
488            c.gridx++;
489            
490            JTextField errControlBits = new JTextField("0", 5);
491            errControlBits.setToolTipText(Bundle.getMessage("CanErrControlTt"));
492            errControlBits.setHorizontalAlignment(SwingConstants.RIGHT);
493            gridPane.add(errControlBits, c);
494
495            c.gridx = 0;
496            c.gridy++;
497            c.gridy++;
498            
499            JLabel statusCol = new JLabel(Bundle.getMessage("CanErrStatus"));
500            gridPane.add(statusCol, c);
501            c.gridx++;
502            c.gridx++;
503
504            rcAllButton = new JButton(Bundle.getMessage("ClearAll"));
505            rcAllButton.addActionListener((java.awt.event.ActionEvent e) -> {
506                allButtonActionPerformed();
507            });
508            gridPane.add(rcAllButton, c);
509            c.gridx++;
510            
511            rcAllUpButton = new JButton(Bundle.getMessage("UpdateAll"));
512            rcAllUpButton.addActionListener((java.awt.event.ActionEvent e) -> {
513                rcAllUpButtonActionPerformed();
514            });
515            gridPane.add(rcAllUpButton, c);
516            c.gridx = 0;
517            c.gridy++;
518
519            for (int i = 0; i < clearableErrors; i++) {
520                rcText[i] = new JLabel();
521                rcText[i].setText(rcTitle[i]);
522                gridPane.add(rcText[i], c);
523                c.gridx++;
524
525                rcCount[i] = new JTextField("0", 5);
526                rcCount[i].setHorizontalAlignment(SwingConstants.RIGHT);
527                rcCount[i].setToolTipText(rcTt[i]);
528                rcCount[i].setEditable(false);
529                gridPane.add(rcCount[i], c);
530                c.gridx++;
531
532                final int button = i;
533                
534                rcButton[i] = new JButton(Bundle.getMessage("Clear"));
535                rcButton[i].addActionListener((java.awt.event.ActionEvent e) -> {
536                    rcButtonActionPerformed(button);
537                });
538                gridPane.add(rcButton[i], c);
539                c.gridx++;
540                
541                rcUpButton[i] = new JButton(Bundle.getMessage("Update"));
542                rcUpButton[i].addActionListener((java.awt.event.ActionEvent e) -> {
543                    rcUpButtonActionPerformed(button);
544                });
545                gridPane.add(rcUpButton[i], c);
546
547                c.gridx = 0;
548                c.gridy++;
549            }
550
551            JLabel roHeader = new JLabel(Bundle.getMessage("ReadOnly"));
552            gridPane.add(roHeader, c);
553            c.gridy++;
554            
555            for (int i = 0; i < rErrors; i++) {
556                rText[i] = new JLabel();
557                rText[i].setText(rTitle[i]);
558                gridPane.add(rText[i], c);
559                c.gridx++;
560
561                rCount[i] = new JTextField("0", 5);
562                rCount[i].setHorizontalAlignment(SwingConstants.RIGHT);
563                rCount[i].setToolTipText(rTt[i]);
564                rCount[i].setEditable(false);
565                gridPane.add(rCount[i], c);
566                c.gridx++;
567                
568                c.gridx++;
569                
570                final int button = i;
571                
572                rUpButton[i] = new JButton(Bundle.getMessage("Update"));
573                rUpButton[i].addActionListener((java.awt.event.ActionEvent e) -> {
574                    rUpButtonActionPerformed(button);
575                });
576                gridPane.add(rUpButton[i], c);
577                c.gridx = 0;
578                c.gridy++;
579            }
580
581            add(gridPane);
582        }
583    }
584
585    /**
586     * Panel to display communuication stats
587     */
588    public class CommsPane extends JPanel {
589
590        public CommsPane() {
591            super();
592
593            JPanel gridPane = new JPanel(new GridBagLayout());
594            GridBagConstraints c = new GridBagConstraints();
595            c.fill = GridBagConstraints.HORIZONTAL;
596
597            c.weightx = 1;
598            c.weighty = 1;
599            c.gridx = 0;
600            c.gridy = 0;
601
602            JLabel statusCol = new JLabel("");
603            gridPane.add(statusCol, c);
604            c.gridx++;
605
606            JLabel col = new JLabel("");
607            gridPane.add(col, c);
608            c.gridx++;
609            
610            commsAllButton = new JButton(Bundle.getMessage("ClearAll"));
611            commsAllButton.addActionListener((java.awt.event.ActionEvent e) -> {
612                commsAllButtonActionPerformed();
613            });
614            gridPane.add(commsAllButton, c);
615            c.gridx++;
616            
617            commsAllUpButton = new JButton(Bundle.getMessage("UpdateAll"));
618            commsAllUpButton.addActionListener((java.awt.event.ActionEvent e) -> {
619                commsAllUpButtonActionPerformed();
620            });
621            gridPane.add(commsAllUpButton, c);
622            c.gridx = 0;
623            c.gridy++;
624
625            for (int i = 0; i < commsItems; i++) {
626                commsText[i] = new JLabel();
627                commsText[i].setText(commsTitle[i]);
628                gridPane.add(commsText[i], c);
629                c.gridx++;
630
631                commsCount[i] = new JTextField("0", 10);
632                commsCount[i].setHorizontalAlignment(SwingConstants.RIGHT);
633                commsCount[i].setToolTipText(commsToolTips[i]);
634                commsCount[i].setEditable(false);
635                gridPane.add(commsCount[i], c);
636                c.gridx++;
637
638                final int button = i;
639                
640                commsButton[i] = new JButton(Bundle.getMessage("Clear"));
641                commsButton[i].addActionListener((java.awt.event.ActionEvent e) -> {
642                    commsButtonActionPerformed(button);
643                });
644                gridPane.add(commsButton[i], c);
645                c.gridx++;
646
647                commsUpButton[i] = new JButton(Bundle.getMessage("Update"));
648                commsUpButton[i].addActionListener((java.awt.event.ActionEvent e) -> {
649                    commsUpButtonActionPerformed(button);
650                });
651                gridPane.add(commsUpButton[i], c);
652                c.gridx = 0;
653                c.gridy++;
654            }
655
656            add(gridPane);
657        }
658    }
659
660    private final static Logger log = LoggerFactory.getLogger(CanisbEditNVPane.class);
661
662}