001package jmri.jmrit.consisttool;
002
003import java.awt.FlowLayout;
004import java.awt.event.ActionEvent;
005import java.awt.event.KeyEvent;
006import java.awt.event.KeyListener;
007import java.beans.PropertyChangeEvent;
008import java.io.IOException;
009import java.util.List;
010import java.util.ArrayList;
011import javax.swing.*;
012
013import jmri.Consist;
014import jmri.ConsistListListener;
015import jmri.ConsistListener;
016import jmri.ConsistManager;
017import jmri.LocoAddress;
018import jmri.DccLocoAddress;
019import jmri.InstanceManager;
020import jmri.jmrit.DccLocoAddressSelector;
021import jmri.jmrit.roster.swing.GlobalRosterEntryComboBox;
022import jmri.jmrit.roster.swing.RosterEntryComboBox;
023import jmri.jmrit.roster.Roster;
024import jmri.jmrit.roster.RosterEntry;
025import jmri.jmrit.symbolicprog.CvTableModel;
026import jmri.jmrit.symbolicprog.CvValue;
027import jmri.jmrit.throttle.ThrottleFrame;
028import jmri.jmrit.throttle.ThrottleFrameManager;
029import jmri.util.JmriJFrame;
030import jmri.util.gui.GuiLafPreferencesManager;
031import jmri.util.swing.JmriJOptionPane;
032
033import org.jdom2.JDOMException;
034
035/**
036 * Frame object for manipulating consists.
037 *
038 * @author Paul Bender Copyright (C) 2003-2008
039 */
040public class ConsistToolFrame extends JmriJFrame implements ConsistListener, ConsistListListener {
041
042    // GUI member declarations
043    JLabel textAdrLabel = new JLabel();
044    DccLocoAddressSelector adrSelector = new DccLocoAddressSelector();
045    ConsistComboBox consistComboBox = new ConsistComboBox();
046    JRadioButton isAdvancedConsist = new JRadioButton(Bundle.getMessage("AdvancedConsistButtonText"));
047    JRadioButton isCSConsist = new JRadioButton(Bundle.getMessage("CommandStationConsistButtonText"));
048    JButton deleteButton = new JButton();
049    JButton throttleButton = new JButton();
050    JButton reverseButton = new JButton();
051    JButton restoreButton = new JButton();
052    JLabel textLocoLabel = new JLabel();
053    DccLocoAddressSelector locoSelector = new DccLocoAddressSelector();
054    RosterEntryComboBox locoRosterBox;
055    JButton addLocoButton = new JButton();
056    JButton resetLocoButton = new JButton();
057    JCheckBox locoDirectionNormal = new JCheckBox(Bundle.getMessage("DirectionNormalText"));
058    ConsistDataModel consistModel = new ConsistDataModel();
059    JTable consistTable = new JTable(consistModel);
060    ConsistManager consistManager = null;
061    JLabel _status = new JLabel(Bundle.getMessage("DefaultStatusText"));
062    private int _Consist_Type = Consist.ADVANCED_CONSIST;
063    private ConsistFile consistFile = null;
064
065    public ConsistToolFrame() {
066        super();
067        init();
068    }
069
070    private void init() {
071        consistManager = InstanceManager.getDefault(jmri.ConsistManager.class);
072
073        consistFile = new ConsistFile();
074        try {
075            consistFile.readFile();
076        } catch (IOException | JDOMException e) {
077            log.warn("error reading consist file: {}", e.getMessage());
078        }
079
080        // register to be notified if the consist list changes.
081        consistManager.addConsistListListener(this);
082
083        // request an update from the layout.
084        consistManager.requestUpdateFromLayout();
085
086        // configure items for GUI
087        textAdrLabel.setText(Bundle.getMessage("AddressLabelText"));
088        textAdrLabel.setVisible(true);
089
090        adrSelector.setVisible(true);
091        adrSelector.setToolTipText(Bundle.getMessage("AddressSelectorToolTip"));
092        textAdrLabel.setLabelFor(adrSelector);
093
094        initializeConsistBox();
095
096        consistComboBox.addActionListener((ActionEvent e) -> consistSelected());
097
098        if (consistManager.isAdvancedConsistPossible()) {
099            isAdvancedConsist.setSelected(true);
100            isAdvancedConsist.setVisible(true);
101            isAdvancedConsist.setEnabled(false);
102            isAdvancedConsist.addActionListener((ActionEvent e) -> {
103                isAdvancedConsist.setSelected(true);
104                isCSConsist.setSelected(false);
105                _Consist_Type = Consist.ADVANCED_CONSIST;
106                adrSelector.setEnabled(true);
107            });
108            isCSConsist.setSelected(false);
109        } else {
110            isAdvancedConsist.setSelected(false);
111            isAdvancedConsist.setVisible(false);
112            isCSConsist.setSelected(true);
113            _Consist_Type = Consist.CS_CONSIST;
114            adrSelector.setEnabled((consistManager.csConsistNeedsSeperateAddress()));
115        }
116
117        isCSConsist.setVisible(true);
118        isCSConsist.setEnabled(false);
119        isCSConsist.addActionListener((ActionEvent e) -> {
120            isAdvancedConsist.setSelected(false);
121            isCSConsist.setSelected(true);
122            _Consist_Type = Consist.CS_CONSIST;
123            adrSelector.setEnabled((consistManager.csConsistNeedsSeperateAddress()));
124        });
125
126        if (consistManager.isCommandStationConsistPossible()) {
127            isAdvancedConsist.setEnabled(true);
128            isCSConsist.setEnabled(true);
129        }
130
131        // link the protocol selectors if required by ConsistManager
132        if (consistManager.isSingleFormConsistRequired()) {
133            locoSelector.followAnotherSelector(adrSelector);
134        }
135        
136        deleteButton.setText(Bundle.getMessage("ButtonDelete"));
137        deleteButton.setVisible(true);
138        deleteButton.setToolTipText(Bundle.getMessage("DeleteButtonToolTip"));
139        deleteButton.addActionListener(this::deleteButtonActionPerformed);
140
141        throttleButton.setText(Bundle.getMessage("ThrottleButtonText"));
142        throttleButton.setVisible(true);
143        throttleButton.setToolTipText(Bundle.getMessage("ThrottleButtonToolTip"));
144        throttleButton.addActionListener(this::throttleButtonActionPerformed);
145
146        reverseButton.setText(Bundle.getMessage("ReverseButtonText"));
147        reverseButton.setVisible(true);
148        reverseButton.setToolTipText(Bundle.getMessage("ReverseButtonToolTip"));
149        reverseButton.addActionListener(this::reverseButtonActionPerformed);
150
151        restoreButton.setText(Bundle.getMessage("RestoreButtonText"));
152        restoreButton.setVisible(true);
153        restoreButton.setToolTipText(Bundle.getMessage("RestoreButtonToolTip"));
154        restoreButton.addActionListener(this::restoreButtonActionPerformed);
155
156        // Set up the controls for the First Locomotive in the consist.
157        textLocoLabel.setText(Bundle.getMessage("LocoLabelText"));
158        textLocoLabel.setVisible(true);
159
160        locoSelector.setToolTipText(Bundle.getMessage("LocoSelectorToolTip"));
161        locoSelector.setVisible(true);
162        textLocoLabel.setLabelFor(locoSelector);
163
164        locoSelector.addKeyListener(new KeyListener() {
165            @Override
166            public void keyPressed(KeyEvent e) {
167                if ( !consistManager.isSingleFormConsistRequired()) {
168                    // if combo boxes are not locked together, 
169                    // and if user start typing, set the selected index of the locoRosterbox to nothing
170                    // to get the user to make a decision
171                    locoRosterBox.setSelectedIndex(0);
172                }
173            }
174
175            @Override
176            public void keyTyped(KeyEvent e) {
177                // only handling key presses
178            }
179
180            @Override
181            public void keyReleased(KeyEvent e) {
182                // only handling key presses
183            }
184        });
185
186        locoRosterBox = new GlobalRosterEntryComboBox();
187        locoRosterBox.setNonSelectedItem("");
188        locoRosterBox.setSelectedIndex(0);
189
190        locoRosterBox.addPropertyChangeListener("selectedRosterEntries", (PropertyChangeEvent pce) -> locoSelected());
191
192        locoRosterBox.setVisible(true);
193
194        locoDirectionNormal.setToolTipText(Bundle.getMessage("DirectionNormalToolTip"));
195
196        locoDirectionNormal.setSelected(true);
197        locoDirectionNormal.setVisible(true);
198        locoDirectionNormal.setEnabled(false);
199
200        addLocoButton.setText(Bundle.getMessage("ButtonAddText"));
201        addLocoButton.setVisible(true);
202        addLocoButton.setToolTipText(Bundle.getMessage("AddButtonToolTip"));
203        addLocoButton.addActionListener(this::addLocoButtonActionPerformed);
204
205        resetLocoButton.setText(Bundle.getMessage("ButtonReset"));
206        resetLocoButton.setVisible(true);
207        resetLocoButton.setToolTipText(Bundle.getMessage("ResetButtonToolTip"));
208        resetLocoButton.addActionListener(this::resetLocoButtonActionPerformed);
209
210        // general GUI config
211        setTitle(Bundle.getMessage("ConsistToolTitle"));
212        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
213
214        JMenuBar menuBar = new JMenuBar();
215        setJMenuBar(menuBar);
216
217        // add a "File" menu
218        JMenu fileMenu = new JMenu(Bundle.getMessage("MenuFile"));
219        menuBar.add(fileMenu);
220
221        // Add a save item
222        fileMenu.add(new AbstractAction(Bundle.getMessage("ScanConsists")) {
223            @Override
224            public void actionPerformed(ActionEvent e) {
225                scanRoster();
226                initializeConsistBox();
227                consistModel.fireTableDataChanged();
228                resetLocoButtonActionPerformed(e);
229            }
230        });
231
232        // install items in GUI
233        // The address and related buttons are installed in a single pane
234        JPanel addressPanel = new JPanel();
235        addressPanel.setLayout(new FlowLayout());
236
237        addressPanel.add(textAdrLabel);
238        addressPanel.add(adrSelector.getCombinedJPanel());
239        addressPanel.add(consistComboBox);
240        addressPanel.add(isAdvancedConsist);
241        addressPanel.add(isCSConsist);
242
243        getContentPane().add(addressPanel);
244
245        // The address and related buttons for each Locomotive
246        // are installed in a single pane
247        // New Locomotive
248        JPanel locoPanel = new JPanel();
249        locoPanel.setLayout(new FlowLayout());
250
251        locoPanel.add(textLocoLabel);
252
253        locoPanel.add(locoSelector.getCombinedJPanel());
254
255        locoPanel.add(locoRosterBox);
256        locoPanel.add(locoDirectionNormal);
257
258        locoPanel.add(addLocoButton);
259        locoPanel.add(resetLocoButton);
260
261        getContentPane().add(locoPanel);
262
263        // setup the consist table
264        consistTable.setRowHeight(InstanceManager.getDefault(GuiLafPreferencesManager.class).getFontSize()*2 + 4);
265        // Set up the jtable in a Scroll Pane..
266        JScrollPane consistPane = new JScrollPane(consistTable);
267        consistPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
268        consistModel.initTable(consistTable);
269        getContentPane().add(consistPane);
270
271        // Set up the Control Button panel
272        JPanel controlPanel = new JPanel();
273        controlPanel.setLayout(new FlowLayout());
274
275        controlPanel.add(deleteButton);
276        controlPanel.add(throttleButton);
277        controlPanel.add(reverseButton);
278        controlPanel.add(restoreButton);
279
280        getContentPane().add(controlPanel);
281
282        // add the status line directly to the bottom of the ContentPane.
283        JPanel statusPanel = new JPanel();
284        statusPanel.setLayout(new FlowLayout());
285        statusPanel.add(_status);
286        getContentPane().add(statusPanel);
287
288        addHelpMenu("package.jmri.jmrit.consisttool.ConsistToolFrame", true);
289        pack();
290
291    }
292
293    private void initializeConsistBox() {
294        ArrayList<LocoAddress> existingConsists = consistManager.getConsistList();
295        if (!existingConsists.isEmpty()) {
296            java.util.Collections.sort(existingConsists, new jmri.util.LocoAddressComparator()); // sort the consist list.
297            if (adrSelector.getAddress() != null) {
298                if (consistModel.getConsist() != null) {
299                    consistModel.getConsist().removeConsistListener(this);
300                    setDefaultStatus();
301                }
302                consistModel.setConsist(adrSelector.getAddress());
303                consistModel.getConsist().addConsistListener(this);
304                adrSelector.setEnabled(false);
305            } else {
306                if (consistModel.getConsist() != null) {
307                    consistModel.getConsist().removeConsistListener(this);
308                    setDefaultStatus();
309                }
310                consistModel.setConsist((Consist) null);
311                adrSelector.setEnabled(true);
312            }
313        } else {
314            if (consistModel.getConsist() != null) {
315                consistModel.getConsist().removeConsistListener(this);
316                setDefaultStatus();
317            }
318            consistModel.setConsist((Consist) null);
319            adrSelector.setEnabled(true);
320        }
321    }
322
323    public void deleteButtonActionPerformed(ActionEvent e) {
324        if (adrSelector.getAddress() == null) {
325            reportNoConsistSeletected();
326            return;
327        }
328        DccLocoAddress address = adrSelector.getAddress();
329        consistManager.getConsist(address);
330        // confirm delete
331        if (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("DeleteWarningDialog", address),
332                Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION,
333                JmriJOptionPane.QUESTION_MESSAGE) != JmriJOptionPane.YES_OPTION ) {
334            return; // do not delete
335        }
336        try {
337            adrSelector.reset();
338            consistManager.delConsist(address);
339        } catch (Exception ex) {
340            log.error("Error delting consist {}", address, ex);
341        }        
342        adrSelector.setEnabled(true);
343        initializeConsistBox();
344        resetLocoButtonActionPerformed(e);
345        canAdd();
346    }
347
348    public void throttleButtonActionPerformed(ActionEvent e) {
349        if (adrSelector.getAddress() == null) {
350            reportNoConsistSeletected();
351            return;
352        }
353        // make sure any new locomotives are added to the consist.
354        addLocoButtonActionPerformed(e);
355        // Create a throttle object with the
356        ThrottleFrame tf
357                = InstanceManager.getDefault(ThrottleFrameManager.class).createThrottleFrame();        
358
359        // Notify the throttle of the selected consist address
360        tf.getAddressPanel().setConsistAddress(adrSelector.getAddress());
361        tf.toFront();
362    }
363
364    public void reverseButtonActionPerformed(ActionEvent e) {
365        if (adrSelector.getAddress() == null) {
366            reportNoConsistSeletected();
367            return;
368        }
369        // make sure any new locomotives are added to the consist.
370        addLocoButtonActionPerformed(e);
371
372        /*
373         * get the array list of the locomotives in the consist
374         */
375        DccLocoAddress address = adrSelector.getAddress();
376        Consist tempConsist = consistManager.getConsist(address);
377        tempConsist.reverse();
378        consistManager.notifyConsistListChanged();
379    }
380
381    public void restoreButtonActionPerformed(ActionEvent e) {
382        if (adrSelector.getAddress() == null) {
383            reportNoConsistSeletected();
384            return;
385        }
386        // make sure any new locomotives are added to the consist.
387        addLocoButtonActionPerformed(e);
388
389        /*
390         * get the array list of the locomotives in the consist
391         */
392        DccLocoAddress address = adrSelector.getAddress();
393        Consist tempConsist = consistManager.getConsist(address);
394        tempConsist.restore();
395        consistManager.notifyConsistListChanged();
396    }
397
398    public void consistSelected() {
399        log.debug("Consist Selected");
400        if (consistComboBox.getSelectedIndex() == -1 && adrSelector.getAddress() != null) {
401            log.debug("No Consist Selected");
402            adrSelector.setEnabled(false);
403            recallConsist();
404        } else if (consistComboBox.getSelectedIndex() == -1
405                || consistComboBox.getSelectedItem().equals("") 
406                || consistComboBox.getSelectedItem().equals(Bundle.getMessage("NoConsistSelected"))) {
407            log.debug("Null Consist Selected");
408            adrSelector.reset();
409            adrSelector.setEnabled(true);
410            recallConsist();
411        } else if (((DccLocoAddress) consistComboBox.getSelectedItem()) != adrSelector.getAddress()) {
412            log.debug("Consist {} consistComboBox", consistComboBox.getSelectedItem());
413            adrSelector.setEnabled(false);
414            adrSelector.setAddress((DccLocoAddress) consistComboBox.getSelectedItem());
415            recallConsist();
416        }
417    }
418
419    // Recall the consist
420    private void recallConsist() {
421        if (adrSelector.getAddress() == null) {
422            // Clear any consist information that was present
423            locoSelector.reset();
424            locoRosterBox.setSelectedIndex(0);
425            if (consistModel.getConsist() != null) {
426                consistModel.getConsist().removeConsistListener(this);
427                setDefaultStatus();
428            }
429            consistModel.setConsist((Consist) null);
430
431            canAdd();
432
433            return;
434        }
435        DccLocoAddress address = adrSelector.getAddress();
436        if (consistModel.getConsist() != null) {
437            consistModel.getConsist().removeConsistListener(this);
438            _status.setText(Bundle.getMessage("DefaultStatusText"));
439            setDefaultStatus();
440        }
441        Consist selectedConsist = consistManager.getConsist(address);
442        consistModel.setConsist(selectedConsist);
443        selectedConsist.addConsistListener(this);
444
445        // reset the editable locomotive information.
446        locoSelector.reset();
447        locoRosterBox.setSelectedIndex(0);
448        locoDirectionNormal.setSelected(true);
449
450        // if there aren't any locomotives in the consist, don't let
451        // the user change the direction
452        locoDirectionNormal.setEnabled(consistModel.getRowCount()!=0);
453
454        log.debug("Recall Consist {}", address);
455
456        // What type of consist is this?
457        if (selectedConsist.getConsistType() == Consist.ADVANCED_CONSIST) {
458            log.debug("Consist type is Advanced Consist ");
459            isAdvancedConsist.setSelected(true);
460            isCSConsist.setSelected(false);
461            _Consist_Type = Consist.ADVANCED_CONSIST;
462        } else {
463            // This must be a CS Consist.
464            log.debug("Consist type is Command Station Consist ");
465            isAdvancedConsist.setSelected(false);
466            isCSConsist.setSelected(true);
467            _Consist_Type = Consist.CS_CONSIST;
468        }
469
470        canAdd();
471    }
472
473    public void resetLocoButtonActionPerformed(ActionEvent e) {
474        locoSelector.reset();
475        locoRosterBox.setSelectedIndex(0);
476        locoDirectionNormal.setSelected(true);
477        // if there aren't any locomotives in the consist, don't let
478        // the user change the direction
479        locoDirectionNormal.setEnabled(consistModel.getRowCount() != 0);
480    }
481
482    // Check to see if a consist address is selected, and if it
483    // is, dissable the "add button" if the maximum consist size is reached
484    public void canAdd() {
485        // If a consist address is selected, dissable the "add button"
486        // if the maximum size is reached
487        if (adrSelector.getAddress() != null) {
488            DccLocoAddress address = adrSelector.getAddress();
489            if (consistModel.getRowCount() == consistManager.getConsist(address).sizeLimit()) {
490                locoSelector.setEnabled(false);
491                locoRosterBox.setEnabled(false);
492                addLocoButton.setEnabled(false);
493                resetLocoButton.setEnabled(false);
494                locoDirectionNormal.setEnabled(false);
495            } else {
496                enableGuiControls();
497            }
498        } else {
499            enableGuiControls();
500        }
501    }
502
503    private void enableGuiControls(){
504        locoSelector.setEnabled(true);
505        locoRosterBox.setEnabled(true);
506        addLocoButton.setEnabled(true);
507        resetLocoButton.setEnabled(true);
508        locoDirectionNormal.setEnabled(false);
509        // if there aren't any locomotives in the consist, don't let
510        // the user change the direction
511        locoDirectionNormal.setEnabled(consistModel.getRowCount() != 0);
512    }
513
514    public void addLocoButtonActionPerformed(ActionEvent e) {
515        if (locoSelector.getAddress() == null) {
516            return;
517        }
518        if (_Consist_Type == Consist.ADVANCED_CONSIST && adrSelector.getAddress() == null) {
519            reportNoConsistSeletected();
520            return;
521        } else if (_Consist_Type == Consist.ADVANCED_CONSIST
522                && adrSelector.getAddress().isLongAddress()) {
523            JmriJOptionPane.showMessageDialog(this,
524                    Bundle.getMessage("RequiresShortConsistError"));
525            return;
526        } else if (_Consist_Type == Consist.CS_CONSIST && adrSelector.getAddress() == null) {
527            if (consistManager.csConsistNeedsSeperateAddress()) {
528                reportNoConsistSeletected();
529                return;
530            } else {
531                // We need to set an identifier so we can recall the
532                // consist.  We're going to use the lead locomotive number
533                // for this.
534                adrSelector.setAddress(locoSelector.getAddress());
535            }
536        }
537        DccLocoAddress address = adrSelector.getAddress();
538        /*
539         * Make sure the marked consist type matches the consist type stored for
540         * this consist
541         */
542        if (_Consist_Type != consistManager.getConsist(address).getConsistType()) {
543            if (log.isDebugEnabled()) {
544                if (_Consist_Type == Consist.ADVANCED_CONSIST) {
545                    log.debug("Setting Consist Type to Advanced Consist");
546                } else if (_Consist_Type == Consist.CS_CONSIST) {
547                    log.debug("Setting Consist Type to Command Station Assisted Consist");
548                }
549            }
550            consistManager.getConsist(address).setConsistType(_Consist_Type);
551        }
552
553        DccLocoAddress locoaddress = locoSelector.getAddress();
554
555        // Make sure the Address in question is allowed for this type of
556        // consist, and add it to the consist if it is
557        if (!consistManager.getConsist(address).isAddressAllowed(locoaddress)) {
558            JmriJOptionPane.showMessageDialog(this,
559                    Bundle.getMessage("AddressNotAllowedError"));
560            return;
561        }
562        if (consistManager.getConsist(address).contains(locoaddress)) {
563            JmriJOptionPane.showMessageDialog(this,
564                    Bundle.getMessage("AddressAlreadyInConsistError"));
565            return;
566        } 
567            
568        Consist tempConsist = consistManager.getConsist(address);
569        tempConsist.add(locoaddress, locoDirectionNormal.isSelected());
570        
571        // Try to get a roster entry
572        RosterEntry re = null;
573        if (locoRosterBox.getSelectedRosterEntries().length == 1) {
574            re = locoRosterBox.getSelectedRosterEntries()[0];
575        } else {
576            List<RosterEntry> res = Roster.getDefault().matchingList(null, null, "" + locoaddress.getNumber(), null, null, null, null);
577            if (!res.isEmpty()) {
578                re = res.get(0);
579            }
580        }
581                        
582        if (re != null) {    
583            tempConsist.setRosterId(locoaddress, re.titleString());
584        }        
585            
586        if (consistComboBox.getSelectedItem() != adrSelector.getAddress()) {
587            initializeConsistBox();
588            consistComboBox.setSelectedItem(adrSelector.getAddress());
589        }
590        consistManager.notifyConsistListChanged();
591        consistModel.fireTableDataChanged();
592        resetLocoButtonActionPerformed(e);        
593    }
594
595    public void locoSelected() {
596        if (locoRosterBox.getSelectedRosterEntries().length == 1) {
597            locoSelector.setAddress(locoRosterBox.getSelectedRosterEntries()[0].getDccLocoAddress());
598        }
599    }
600
601    /**
602     * we're registering as a listener for Consist events, so we need to
603     * implement the interface.
604     * {@inheritDoc}
605     */
606    @Override
607    public void consistReply(LocoAddress locoaddress, int status) {
608        log.debug("Consist Reply received for Locomotive {} with status {}", locoaddress, status);
609        _status.setText(consistManager.decodeErrorCode(status));
610        // For some status codes, we want to trigger specific actions
611        //if((status & jmri.ConsistListener.CONSIST_FULL)!=0) {
612        // canAdd();
613        //} else {
614        canAdd();
615        //}
616        consistModel.fireTableDataChanged();
617        try {
618            consistFile.writeFile(consistManager.getConsistList());
619        } catch (IOException e) {
620            log.warn("error writing consist file: {}", e.getMessage());
621        }
622    }
623
624    @Override
625    public void dispose() {
626        super.dispose();
627        // de-register to be notified if the consist list changes.
628        consistManager.removeConsistListListener(this);
629    }
630
631    // ConsistListListener interface
632    /**
633     * {@inheritDoc}
634     */
635    @Override
636    public void notifyConsistListChanged() {
637        // Save consist file
638        try {
639            consistFile.writeFile(consistManager.getConsistList());
640        } catch (IOException e) {
641            log.warn("error writing consist file: {}", e.getMessage());
642        }  
643        // update the consist list.
644        initializeConsistBox();
645    }
646
647    /**
648     * private method to scan the roster for consists
649     */
650    private void scanRoster(){
651       List<RosterEntry> roster = Roster.getDefault().getAllEntries();
652       for(RosterEntry entry:roster){
653            DccLocoAddress address = entry.getDccLocoAddress();
654            CvTableModel  cvTable = new CvTableModel(_status, null);  // will hold CV objects
655            entry.readFile();  // read, but don't yet process
656
657            entry.loadCvModel(null, cvTable);
658            CvValue cv19Value = cvTable.getCvByNumber("19");
659            if(cv19Value!=null && (cv19Value.getValue() & 0x7F)!=0){
660                boolean direction = ((cv19Value.getValue()&0x80)==0);
661                DccLocoAddress consistAddress = new DccLocoAddress((cv19Value.getValue()&0x7f),false);
662                /*
663                 * Make sure the marked consist type is an advanced consist.
664                 * this consist
665                  */
666                Consist consist = consistManager.getConsist(consistAddress);
667                if (Consist.ADVANCED_CONSIST != consist.getConsistType()) {
668                    consist.setConsistType(Consist.ADVANCED_CONSIST);
669                }
670
671                if (!consist.contains(address)) {
672                   consist.add(address, direction );
673                   consist.setRosterId(address, entry.titleString());
674                }
675            }
676       }
677    }
678
679    private void reportNoConsistSeletected(){
680        JmriJOptionPane.showMessageDialog(this,
681                Bundle.getMessage("NoConsistSelectedError"));
682
683    }
684
685    public void setDefaultStatus() {
686        _status.setText(Bundle.getMessage("DefaultStatusText"));
687    }
688
689    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConsistToolFrame.class);
690
691}