001package jmri.jmrix.can.cbus.swing.modules.sprogdcc;
002
003import java.awt.*;
004import java.awt.event.ActionEvent;
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 jmri.jmrix.can.cbus.swing.modules.*;
012import static jmri.jmrix.can.cbus.node.CbusNodeConstants.*;
013
014import org.slf4j.Logger;
015import org.slf4j.LoggerFactory;
016
017/**
018 * Node Variable edit frame for a SPROG DCC [Pi-]SPROG 3 [v2|Plus] module
019 *
020 * @author Andrew Crosland Copyright (C) 2021
021 */
022public class Sprog3PlusEditNVPane extends AbstractEditNVPane {
023    
024    private CmdStaFlags [] csFlags = new CmdStaFlags[4];
025    
026    private final UpdateNV cmdStaNoUpdateFn = new UpdateCmdStaNo();
027    private final UpdateNV canIdUpdateFn = new UpdateCanId();
028    private final UpdateNV nodeNumberUpdateFn = new UpdateNodeNumber();
029    private final UpdateNV currentLimitUpdateFn = new UpdateCurrentLimit();
030    private final UpdateNV accyPktUpdateFn = new UpdateAccyCount();
031    private final UpdateNV nnMapUpdateFn = new UpdateNnMap();
032    private final UpdateNV preambleUpdateFn = new UpdatePreamble();
033    private final UpdateNV powerModeUpdateFn = new UpdatePowerMode();
034    private final UpdateNV meterUpdateFn = new UpdateMeter();
035    private final UpdateNV flagUpdateFn = new UpdateFlags();
036    
037    private TitledSpinner cmdStaNoSpinner;
038    private JComboBox<String> powerModeList ;
039    private TitledSpinner mainSpinner;
040    private TitledSpinner progSpinner;
041    private TitledSpinner accyPktSpinner;
042    private JRadioButton meter;
043    private TitledSpinner nnMapDccSpinner;
044    private JRadioButton setup;
045    private TitledSpinner canIdSpinner;
046    private TitledSpinner nodeNumberSpinner;
047    private TitledSpinner preambleSpinner;
048    private JRadioButton disable ;
049            
050    protected String flagTitleStrings[] = new String[] {
051        Bundle.getMessage("UserFlags"),
052        Bundle.getMessage("OperationsFlags"),
053        Bundle.getMessage("DebugFlags"),
054        Bundle.getMessage("UserFlags2")
055    };
056
057    protected String flagStrings[][] = new String[][] {
058        // User
059        {Bundle.getMessage("Reserved"),
060            Bundle.getMessage("PermitSteal"),
061            Bundle.getMessage("PermitShare"),
062            Bundle.getMessage("Reserved"),
063            Bundle.getMessage("MapEvents"),
064            Bundle.getMessage("StopOnTimeout"),
065            Bundle.getMessage("StartOfDay"),
066            Bundle.getMessage("AutoPower")},
067        // Ops
068        {Bundle.getMessage("Reserved"),
069            Bundle.getMessage("Reserved"),
070            Bundle.getMessage("Reserved"),
071            Bundle.getMessage("ZtcMode"),
072            Bundle.getMessage("AllStopTrackOff"),
073            Bundle.getMessage("BluelineMode"),
074            Bundle.getMessage("AckSensitivity"),
075            Bundle.getMessage("Reserved")},
076        // Debug
077        {Bundle.getMessage("Reserved"),
078            Bundle.getMessage("Reserved"),
079            Bundle.getMessage("Reserved"),
080            Bundle.getMessage("Reserved"),
081            Bundle.getMessage("Reserved"),
082            Bundle.getMessage("Reserved"),
083            Bundle.getMessage("Reserved"),
084            Bundle.getMessage("Reserved")},
085        // User 2
086        {Bundle.getMessage("MapEventsOffset"),
087            Bundle.getMessage("Reserved"),
088            Bundle.getMessage("Reserved"),
089            Bundle.getMessage("Reserved"),
090            Bundle.getMessage("Reserved"),
091            Bundle.getMessage("Reserved"),
092            Bundle.getMessage("Reserved"),
093            Bundle.getMessage("Reserved")
094        }};
095
096    protected String flagTtStrings[][] = new String[][] {
097        // User
098        {Bundle.getMessage("ReservedTt"),
099            Bundle.getMessage("PermitStealTt"),
100            Bundle.getMessage("PermitShareTt"),
101            Bundle.getMessage("ReservedTt"),
102            Bundle.getMessage("MapEventsTt"),
103            Bundle.getMessage("StopOnTimeoutTt"),
104            Bundle.getMessage("StartOfDayTt"),
105            Bundle.getMessage("AutoPowerTt")},
106        // Ops
107        {Bundle.getMessage("ReservedTt"),
108            Bundle.getMessage("ReservedTt"),
109            Bundle.getMessage("ReservedTt"),
110            Bundle.getMessage("ZtcModeTt"),
111            Bundle.getMessage("AllStopTrackOffTt"),
112            Bundle.getMessage("BluelineModeTt"),
113            Bundle.getMessage("AckSensitivityTt"),
114            Bundle.getMessage("ReservedTt")},
115        // Debug
116        {Bundle.getMessage("ReservedTt"),
117            Bundle.getMessage("ReservedTt"),
118            Bundle.getMessage("ReservedTt"),
119            Bundle.getMessage("ReservedTt"),
120            Bundle.getMessage("ReservedTt"),
121            Bundle.getMessage("ReservedTt"),
122            Bundle.getMessage("ReservedTt"),
123            Bundle.getMessage("ReservedTt")},
124        // User 2
125        {Bundle.getMessage("MapEventsOffsetTt"),
126            Bundle.getMessage("ReservedTt"),
127            Bundle.getMessage("ReservedTt"),
128            Bundle.getMessage("ReservedTt"),
129            Bundle.getMessage("ReservedTt"),
130            Bundle.getMessage("ReservedTt"),
131            Bundle.getMessage("ReservedTt"),
132            Bundle.getMessage("ReservedTt")
133        }};
134
135    protected Sprog3PlusEditNVPane(CbusNodeNVTableDataModel dataModel, CbusNode node) {
136        super(dataModel, node);
137    }
138    
139    /** {@inheritDoc} */
140    @Override
141    public AbstractEditNVPane getContent() {
142        
143        JTabbedPane tabbedPane = new JTabbedPane();
144        
145        JPanel cmdStaPane = new CmdStaPane();
146        JPanel dccPane = new DccPane();
147        JPanel cbusPane = new CbusPane();
148        tabbedPane.addTab(Bundle.getMessage("CmdSta"), cmdStaPane);
149        tabbedPane.addTab("DCC", dccPane);
150        tabbedPane.addTab("CBUS Diagnostics", cbusPane);
151        
152        JScrollPane scroll = new JScrollPane(tabbedPane);
153        add(scroll);
154        
155        return this;
156    }
157
158    /** {@inheritDoc} */
159    @Override
160    public void tableChanged(TableModelEvent e) {
161        if (e.getType() == TableModelEvent.UPDATE) {
162            int row = e.getFirstRow();
163            int nv = row + 1;
164            int value = getSelectValue8(nv);
165            log.debug("sprog3plus gui table changed NV: {} Value: {}", nv, value);
166            
167            switch (nv) {
168                case Sprog3PlusPaneProvider.CMD_STATION_NUMBER:
169                    cmdStaNoSpinner.setValue(value);
170                    break;
171                    
172                case Sprog3PlusPaneProvider.USER_FLAGS:
173                    csFlags[0].setFlags(value);
174                    break;
175                    
176                case Sprog3PlusPaneProvider.OPERATIONS_FLAGS:
177                    csFlags[1].setFlags(value);
178                    break;
179                    
180                case Sprog3PlusPaneProvider.DEBUG_FLAGS:
181                    csFlags[2].setFlags(value);
182                    break;
183                            
184                case Sprog3PlusPaneProvider.USER_FLAGS_2:
185                    csFlags[3].setFlags(value);
186                    break;
187                            
188                case Sprog3PlusPaneProvider.PROG_TRACK_POWER_MODE:
189                    // Do nothing if nothing has changed, else causes an endless
190                    // round of gui update, table update, ...
191                    if (value != powerModeList.getSelectedIndex()) {
192                        powerModeList.setSelectedIndex(value);
193                    }
194                    break;
195                    
196                case Sprog3PlusPaneProvider.PROG_TRACK_CURRENT_LIMIT:
197                    double progLimit = (double)value/100;
198                    progSpinner.setValue(progLimit);
199                    break;
200                
201                case Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT_LIMIT:
202                    double mainLimit = (double)value/100;
203                    mainSpinner.setValue(mainLimit);
204                    break;
205                    
206                case Sprog3PlusPaneProvider.ACCY_PACKET_REPEAT_COUNT:
207                    accyPktSpinner.setValue(value);
208                    break;
209                    
210                case Sprog3PlusPaneProvider.MULTIMETER_MODE:
211                    meter.setSelected(value != 0);
212                    break;
213                    
214                case Sprog3PlusPaneProvider.NN_MAP_DCC_HI:
215                case Sprog3PlusPaneProvider.NN_MAP_DCC_LO:
216                    nnMapDccSpinner.setValue(getSelectValue16(Sprog3PlusPaneProvider.NN_MAP_DCC_HI,
217                            Sprog3PlusPaneProvider.NN_MAP_DCC_LO, 0, 65535));
218                    break;
219                    
220                case Sprog3PlusPaneProvider.SETUP:
221                    setup.setSelected(value != 0);
222                    break;
223                    
224                case Sprog3PlusPaneProvider.CANID:
225                    canIdSpinner.setValue(value);
226                    break;
227                    
228                case Sprog3PlusPaneProvider.NN_HI:
229                case Sprog3PlusPaneProvider.NN_LO:
230                    nodeNumberSpinner.setValue(getSelectValue16(Sprog3PlusPaneProvider.NN_HI, 
231                            Sprog3PlusPaneProvider.NN_LO,
232                            Sprog3PlusPaneProvider.MIN_NN,
233                            Sprog3PlusPaneProvider.MAX_NN));
234                    break;
235                    
236                case Sprog3PlusPaneProvider.DCC_PREAMBLE:
237                    preambleSpinner.setValue(value);
238                    break;
239                    
240                case Sprog3PlusPaneProvider.CAN_DISABLE:
241                    disable.setEnabled(value != 0);
242                    break;
243
244                case Sprog3PlusPaneProvider.INPUT_VOLTAGE:
245                case Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT:
246                case Sprog3PlusPaneProvider.PROG_TRACK_CURRENT:
247                case Sprog3PlusPaneProvider.MAIN_HIGH_WATER_MARK:
248                case Sprog3PlusPaneProvider.PROG_HIGH_WATER_MARK:
249                    // These read-only NVs are not preented in the edit GUI as they can be displayed on meters
250                    break;
251                    
252                default:
253                    // Not used, or row was -1
254//                    log.debug("Update unknown NV {}", nv);
255                    
256            }
257        }
258    }
259    
260    /**
261     * Update the command station number
262     */
263    protected class UpdateCmdStaNo implements UpdateNV {
264        
265        /** {@inheritDoc} */
266        @Override
267        public void setNewVal(int index) {
268            int cmdStaNo = cmdStaNoSpinner.getIntegerValue();
269            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
270            _dataModel.setValueAt(cmdStaNo, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
271        }
272    }
273        
274    /**
275     * Update the Flags
276     */
277    protected class UpdateFlags implements UpdateNV {
278        
279        /** {@inheritDoc} */
280        @Override
281        public void setNewVal(int index) {
282            int flags = csFlags[index].getFlags();
283            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
284            _dataModel.setValueAt(flags, csFlags[index].getNv() - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
285        }
286    }
287        
288    /**
289     * Update the CAN ID
290     * 
291     * For debug only, CAN ID is not normally set this way
292     */
293    protected class UpdateCanId implements UpdateNV {
294        
295        /** {@inheritDoc} */
296        @Override
297        public void setNewVal(int index) {
298            int canId = canIdSpinner.getIntegerValue();
299            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
300            _dataModel.setValueAt(canId, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
301        }
302    }
303        
304    /**
305     * Update the node number
306     * 
307     * For debug only, CAN ID is not normally set this way
308     */
309    protected class UpdateNodeNumber implements UpdateNV {
310        
311        /** {@inheritDoc} */
312        @Override
313        public void setNewVal(int index) {
314            int nn = nodeNumberSpinner.getIntegerValue();
315            int nnHi = nn/256;
316            int nnLo = nn%256;
317            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
318            _dataModel.setValueAt(nnHi, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
319            _dataModel.setValueAt(nnLo, index, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
320        }
321    }
322    
323    /**
324     * Update the multi meter events setting
325     */
326    protected class UpdateMeter implements UpdateNV {
327        
328        /** {@inheritDoc} */
329        @Override
330        public void setNewVal(int index) {
331            int mode = meter.isSelected() ? 1 : 0;
332            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
333            _dataModel.setValueAt(mode, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
334        }
335    }
336    
337    /**
338     * Update a current Limit
339     */
340    protected class UpdateCurrentLimit implements UpdateNV {
341        
342        /** {@inheritDoc} */
343        @Override
344        public void setNewVal(int index) {
345            int limit;
346            double fLimit;
347            if (index == Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT_LIMIT) {
348                fLimit = mainSpinner.getDoubleValue();
349            } else {
350                fLimit = progSpinner.getDoubleValue();
351            }
352            // Limit to 10mA precision
353            limit = (int)(fLimit*100 + 0.5);
354            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
355            _dataModel.setValueAt(limit, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
356        }
357    }
358    
359    /**
360     * Update the number of times a DCC accessory packet is repeated
361     */
362    protected class UpdateAccyCount implements UpdateNV {
363        
364        /** {@inheritDoc} */
365        @Override
366        public void setNewVal(int index) {
367            int cnt = accyPktSpinner.getIntegerValue();
368            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
369            _dataModel.setValueAt(cnt, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
370        }
371    }
372
373    /**
374     * Update the Node Number of events to be mapped to DCC accessory commands
375     */
376    protected class UpdateNnMap implements UpdateNV {
377        
378        /** {@inheritDoc} */
379        @Override
380        public void setNewVal(int index) {
381            int mapNn = nnMapDccSpinner.getIntegerValue();
382            int mapNnHi = mapNn/256;
383            int mapNnLo = mapNn%256;
384            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
385            _dataModel.setValueAt(mapNnHi, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
386            _dataModel.setValueAt(mapNnLo, index, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
387        }
388    }
389
390    /**
391     * Update the number of DCC packet preamble bits
392     */
393    protected class UpdatePreamble implements UpdateNV {
394        
395        /** {@inheritDoc} */
396        @Override
397        public void setNewVal(int index) {
398            int pre = preambleSpinner.getIntegerValue();
399            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
400            _dataModel.setValueAt(pre, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
401        }
402    }
403    
404    /**
405     * Update the command station power mode
406     */
407    protected class UpdatePowerMode implements UpdateNV {
408        
409        /** {@inheritDoc} */
410        @Override
411        public void setNewVal(int index) {
412            log.debug("UpdatePowerMode.setNewVal()");
413            int mode = powerModeList.getSelectedIndex();
414            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
415            _dataModel.setValueAt(mode, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
416        }
417    }
418    
419    public class CmdStaPane extends JPanel {
420
421        /**
422         * Panel to display command station NVs
423         */
424        public CmdStaPane() {
425            super();
426
427            JPanel gridPane = new JPanel(new GridBagLayout());
428            GridBagConstraints c = new GridBagConstraints();
429            c.fill = GridBagConstraints.HORIZONTAL;
430
431            int flagPanels = 3;
432            if (_node.getNodeParamManager().isFwEqualOrNewer(2, 'e', 2)) {
433                flagPanels = 4;
434            }
435            JPanel [] flagPane = new JPanel[flagPanels];
436            
437            int [] flagNvs = {Sprog3PlusPaneProvider.USER_FLAGS,
438                Sprog3PlusPaneProvider.OPERATIONS_FLAGS,
439                Sprog3PlusPaneProvider.DEBUG_FLAGS,
440                Sprog3PlusPaneProvider.USER_FLAGS_2};
441            
442            for (int i = 0; i < flagPanels; i++) {
443                csFlags[i] = new CmdStaFlags(i, flagNvs[i], flagTitleStrings[i], flagStrings[i], flagTtStrings[i], flagUpdateFn);
444                csFlags[i].setFlags(getSelectValue8(flagNvs[i]));
445                flagPane[i] = csFlags[i].getContents();
446            }
447            
448            String powerModeStrings [] = new String[] {Bundle.getMessage("ProgOffMode"),
449                Bundle.getMessage("ProgOnMode"),
450                Bundle.getMessage("ProgArMode")
451            };
452            
453            c.weightx = 1;
454            c.weighty = 1;
455            c.gridx = 0;
456            c.gridy = 0;
457
458            // x = 1
459            cmdStaNoSpinner = new TitledSpinner(Bundle.getMessage("CmdStaNo"), Sprog3PlusPaneProvider.CMD_STATION_NUMBER, cmdStaNoUpdateFn);
460            cmdStaNoSpinner.setToolTip(Bundle.getMessage("CmdStaNoTt"));
461            cmdStaNoSpinner.init(0, 0, 255, 1);
462            gridPane.add(cmdStaNoSpinner, c);
463            c.gridy++;
464            
465            c.gridwidth = flagPanels;
466            powerModeList = new JComboBox<>(powerModeStrings);
467            powerModeList.setSelectedIndex(getSelectValue8(Sprog3PlusPaneProvider.PROG_TRACK_POWER_MODE));
468            powerModeList.addActionListener((ActionEvent e) -> {
469                pwrModeActionListener(e);
470            });
471            gridPane.add(powerModeList, c);
472            c.gridwidth = 1;
473            c.gridy++;
474            
475            meter = new JRadioButton(Bundle.getMessage("Multimeter"));
476            meter.setSelected(false);
477            meter.setToolTipText(Bundle.getMessage("MultimeterTt"));
478            meter.addActionListener((ActionEvent e) -> {
479                meterActionListener(e);
480            });
481            gridPane.add(meter, c);
482            c.gridy++;
483            
484            mainSpinner = new TitledSpinner(Bundle.getMessage("MainLimit"), Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT_LIMIT, currentLimitUpdateFn);
485            mainSpinner.setToolTip(Bundle.getMessage("MainLimitTt"));
486            mainSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT_LIMIT, 100)/100.0, 1.0, 2.5, 0.01);
487            gridPane.add(mainSpinner, c);
488            c.gridx++;
489            
490            progSpinner = new TitledSpinner(Bundle.getMessage("ProgLimit"), Sprog3PlusPaneProvider.PROG_TRACK_CURRENT_LIMIT, currentLimitUpdateFn);
491            progSpinner.setToolTip(Bundle.getMessage("ProgLimitTt"));
492            progSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.PROG_TRACK_CURRENT_LIMIT, 100)/100.0, 1.0, 2.5, 0.01);
493            gridPane.add(progSpinner, c);
494            
495            c.gridy++;
496            c.gridx = 0;
497            
498            for (int i = 0; i < flagPanels; i++) {
499                gridPane.add(flagPane[i], c);
500                c.gridx++;
501            }
502            
503            add(gridPane);
504        }
505        
506        /**
507         * Action listener for the command station power mode
508         * 
509         * @param e the action event
510         */
511        protected void pwrModeActionListener(ActionEvent e) {
512            log.debug("pwrModeActionListener()");
513            powerModeUpdateFn.setNewVal(Sprog3PlusPaneProvider.PROG_TRACK_POWER_MODE);
514        }
515        
516        /**
517         * Action listener for multimeter nmode selection
518         * 
519         * @param e the action event
520         */
521        protected void meterActionListener(ActionEvent e) {
522            meterUpdateFn.setNewVal(Sprog3PlusPaneProvider.MULTIMETER_MODE);
523        }
524    }
525    
526    /**
527     * Panel to display DCC related NVs
528     */
529    public class DccPane extends JPanel {
530        public DccPane() {
531            super();
532
533            JPanel gridPane = new JPanel(new GridBagLayout());
534            GridBagConstraints c = new GridBagConstraints();
535            c.fill = GridBagConstraints.HORIZONTAL;
536
537            c.weightx = 1;
538            c.weighty = 1;
539            c.gridx = 0;
540            c.gridy = 0;
541            
542            accyPktSpinner = new TitledSpinner(Bundle.getMessage("AccyPktCnt"), Sprog3PlusPaneProvider.ACCY_PACKET_REPEAT_COUNT, accyPktUpdateFn);
543            accyPktSpinner.setToolTip(Bundle.getMessage("AccyPktCntTt"));
544            accyPktSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.ACCY_PACKET_REPEAT_COUNT, 1), 1, 7, 1);
545            gridPane.add(accyPktSpinner, c);
546            c.gridy++;
547            
548            nnMapDccSpinner = new TitledSpinner(Bundle.getMessage("NnMapDcc"), Sprog3PlusPaneProvider.NN_MAP_DCC_HI, nnMapUpdateFn);
549            nnMapDccSpinner.setToolTip(Bundle.getMessage("NnMapDccTt"));
550            int nn = getSelectValue16(Sprog3PlusPaneProvider.NN_MAP_DCC_HI, Sprog3PlusPaneProvider.NN_MAP_DCC_LO, 0, 65535);
551            nnMapDccSpinner.init(nn, 0, 65535, 1);
552            gridPane.add(nnMapDccSpinner, c);
553            c.gridy++;
554            
555            gridPane.add(nnMapDccSpinner, c);
556            c.gridy++;
557
558            preambleSpinner = new TitledSpinner(Bundle.getMessage("DccPreambles"), Sprog3PlusPaneProvider.DCC_PREAMBLE, preambleUpdateFn);
559            preambleSpinner.setToolTip(Bundle.getMessage("DccPreamblesTt"));
560            preambleSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.DCC_PREAMBLE, 14), 14, 32, 1);
561            gridPane.add(preambleSpinner, c);
562                    
563            add(gridPane);
564        }
565    }
566    
567    /**
568     * Panel to display CBUS operation related NVs
569     */
570    public class CbusPane extends JPanel {
571        public CbusPane() {
572            super();
573
574            JPanel gridPane = new JPanel(new GridBagLayout());
575            GridBagConstraints c = new GridBagConstraints();
576            c.fill = GridBagConstraints.HORIZONTAL;
577
578            c.weightx = 1;
579            c.weighty = 1;
580            c.gridx = 0;
581            c.gridy = 0;
582
583            canIdSpinner = new TitledSpinner(Bundle.getMessage("CanId"), Sprog3PlusPaneProvider.CANID, canIdUpdateFn);
584            canIdSpinner.setToolTip(Bundle.getMessage("CanIdTt"));
585            canIdSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.CANID, Sprog3PlusPaneProvider.MIN_CANID, Sprog3PlusPaneProvider.MAX_CANID), 100, 127, 1);
586            gridPane.add(canIdSpinner, c);
587            c.gridy++;
588
589            nodeNumberSpinner = new TitledSpinner(Bundle.getMessage("NodeNumber"), Sprog3PlusPaneProvider.NN_HI, nodeNumberUpdateFn);
590            nodeNumberSpinner.setToolTip(Bundle.getMessage("NodeNumberTt"));
591            int nn = getSelectValue16(Sprog3PlusPaneProvider.NN_HI, Sprog3PlusPaneProvider.NN_LO, Sprog3PlusPaneProvider.MIN_NN, Sprog3PlusPaneProvider.MAX_NN);
592            nodeNumberSpinner.init(nn, 65520, 65534, 1);
593            gridPane.add(nodeNumberSpinner, c);
594            c.gridy++;
595            
596            setup = new JRadioButton("SetupMode");
597            setup.setSelected(false);
598            setup.setToolTipText(Bundle.getMessage("SetupModeTt"));
599            gridPane.add(setup, c);
600            c.gridy++;
601            
602            disable = new JRadioButton("DisableCan");
603            disable.setSelected(false);
604            disable.setToolTipText(Bundle.getMessage("DisableCanTt"));
605            gridPane.add(disable, c);
606            c.gridy++;
607            
608            add(gridPane);
609        }
610    }
611    
612    private final static Logger log = LoggerFactory.getLogger(Sprog3PlusEditNVPane.class);
613
614}