001package jmri.jmrit.operations.trains.gui;
002
003import java.awt.Color;
004import java.awt.Dimension;
005import java.util.List;
006import java.util.ResourceBundle;
007
008import javax.swing.*;
009
010import jmri.InstanceManager;
011import jmri.jmrit.operations.OperationsFrame;
012import jmri.jmrit.operations.OperationsXml;
013import jmri.jmrit.operations.automation.gui.AutomationsTableFrameAction;
014import jmri.jmrit.operations.locations.Location;
015import jmri.jmrit.operations.locations.LocationManager;
016import jmri.jmrit.operations.setup.Control;
017import jmri.jmrit.operations.setup.Setup;
018import jmri.jmrit.operations.setup.backup.AutoSave;
019import jmri.jmrit.operations.setup.gui.*;
020import jmri.jmrit.operations.trains.Train;
021import jmri.jmrit.operations.trains.TrainManager;
022import jmri.jmrit.operations.trains.excel.SetupExcelProgramFrameAction;
023import jmri.jmrit.operations.trains.excel.TrainCustomManifest;
024import jmri.jmrit.operations.trains.schedules.*;
025import jmri.jmrit.operations.trains.tools.*;
026import jmri.swing.JTablePersistenceManager;
027import jmri.util.swing.JmriJOptionPane;
028
029/**
030 * Frame for adding and editing the train roster for operations.
031 *
032 * @author Bob Jacobsen Copyright (C) 2001
033 * @author Daniel Boudreau Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013,
034 *         2014
035 */
036public class TrainsTableFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
037
038    public static final String MOVE = Bundle.getMessage("Move");
039    public static final String TERMINATE = Bundle.getMessage("Terminate");
040    public static final String RESET = Bundle.getMessage("Reset");
041    public static final String CONDUCTOR = Bundle.getMessage("Conductor");
042
043    TrainManager trainManager = InstanceManager.getDefault(TrainManager.class);
044    LocationManager locationManager = InstanceManager.getDefault(LocationManager.class);
045
046    public TrainsTableModel trainsModel;
047    JTable trainsTable;
048    JScrollPane trainsPane;
049
050    // labels
051    JLabel numTrains = new JLabel();
052    JLabel textTrains = new JLabel(Bundle.getMessage("trains"));
053    JLabel textSep1 = new JLabel("      ");
054
055    // radio buttons
056    JRadioButton showTime = new JRadioButton(Bundle.getMessage("Time"));
057    JRadioButton showId = new JRadioButton(Bundle.getMessage("Id"));
058
059    JRadioButton moveRB = new JRadioButton(MOVE);
060    JRadioButton terminateRB = new JRadioButton(TERMINATE);
061    JRadioButton resetRB = new JRadioButton(RESET);
062    JRadioButton conductorRB = new JRadioButton(CONDUCTOR);
063
064    // major buttons
065    JButton addButton = new JButton(Bundle.getMessage("AddTrain"));
066    JButton buildButton = new JButton(Bundle.getMessage("Build"));
067    JButton printButton = new JButton(Bundle.getMessage("Print"));
068    JButton openFileButton = new JButton(Bundle.getMessage("OpenFile"));
069    JButton runFileButton = new JButton(Bundle.getMessage("RunFile"));
070    JButton switchListsButton = new JButton(Bundle.getMessage("SwitchLists"));
071    JButton terminateButton = new JButton(Bundle.getMessage("Terminate"));
072    JButton resetButton = new JButton(Bundle.getMessage("Reset"));
073    JButton saveButton = new JButton(Bundle.getMessage("SaveBuilds"));
074
075    // check boxes
076    JCheckBox buildMsgBox = new JCheckBox(Bundle.getMessage("BuildMessages"));
077    JCheckBox buildReportBox = new JCheckBox(Bundle.getMessage("BuildReport"));
078    JCheckBox printPreviewBox = new JCheckBox(Bundle.getMessage("Preview"));
079    JCheckBox openFileBox = new JCheckBox(Bundle.getMessage("OpenFile"));
080    JCheckBox runFileBox = new JCheckBox(Bundle.getMessage("RunFile"));
081    public JCheckBox showAllBox = new JCheckBox(Bundle.getMessage("ShowAllTrains"));
082
083    public TrainsTableFrame() {
084        super();
085
086        updateTitle();
087
088        // create ShutDownTasks
089        createShutDownTask();
090        // always check for dirty operations files
091        setModifiedFlag(true);
092
093        // general GUI configuration
094        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
095
096        // Set up the jtable in a Scroll Pane..
097        trainsModel = new TrainsTableModel();
098        trainsTable = new JTable(trainsModel);
099        trainsPane = new JScrollPane(trainsTable);
100        trainsModel.initTable(trainsTable, this);
101
102        // Set up the control panel
103        // row 1
104        JPanel cp1 = new JPanel();
105        cp1.setLayout(new BoxLayout(cp1, BoxLayout.X_AXIS));
106
107        JPanel show = new JPanel();
108        show.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("ShowClickToSort")));
109        show.add(showTime);
110        show.add(showId);
111
112        JPanel build = new JPanel();
113        build.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Build")));
114        build.add(showAllBox);
115
116        JPanel function = new JPanel();
117        function.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Function")));
118        function.add(printPreviewBox);
119        function.add(openFileBox);
120        function.add(runFileBox);
121
122        JPanel options = new JPanel();
123        options.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Options")));
124        options.add(buildMsgBox);
125        options.add(buildReportBox);
126
127        JPanel action = new JPanel();
128        action.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Action")));
129        action.add(moveRB);
130        action.add(conductorRB);
131        action.add(terminateRB);
132        action.add(resetRB);
133
134        cp1.add(show);
135        cp1.add(build);
136        cp1.add(function);
137        cp1.add(options);
138        cp1.add(action);
139
140        // tool tips, see setPrintButtonText() for more tool tips
141        addButton.setToolTipText(Bundle.getMessage("AddTrainTip"));
142        buildButton.setToolTipText(Bundle.getMessage("BuildSelectedTip"));
143        switchListsButton.setToolTipText(Bundle.getMessage("PreviewPrintSwitchListsTip"));
144        terminateButton.setToolTipText(Bundle.getMessage("TerminateSelectedTip"));
145        resetButton.setToolTipText(Bundle.getMessage("ResetTrainsTip"));
146        saveButton.setToolTipText(Bundle.getMessage("SaveBuildsTip"));
147        openFileButton.setToolTipText(Bundle.getMessage("OpenFileButtonTip"));
148        runFileButton.setToolTipText(Bundle.getMessage("RunFileButtonTip"));
149        buildMsgBox.setToolTipText(Bundle.getMessage("BuildMessagesTip"));
150        printPreviewBox.setToolTipText(Bundle.getMessage("PreviewTip"));
151        openFileBox.setToolTipText(Bundle.getMessage("OpenFileTip"));
152        runFileBox.setToolTipText(Bundle.getMessage("RunFileTip"));
153        showAllBox.setToolTipText(Bundle.getMessage("ShowAllTrainsTip"));
154
155        moveRB.setToolTipText(Bundle.getMessage("MoveTip"));
156        terminateRB.setToolTipText(Bundle.getMessage("TerminateTip"));
157        resetRB.setToolTipText(Bundle.getMessage("ResetTip"));
158        conductorRB.setToolTipText(Bundle.getMessage("ConductorTip"));
159
160        // row 2
161        JPanel addTrain = new JPanel();
162        addTrain.setBorder(BorderFactory.createTitledBorder(""));
163        addTrain.add(numTrains);
164        addTrain.add(textTrains);
165        addTrain.add(textSep1);
166        addTrain.add(addButton);
167
168        numTrains.setText(Integer.toString(trainManager.getNumEntries()));
169
170        JPanel select = new JPanel();
171        select.setBorder(BorderFactory.createTitledBorder(""));
172        select.add(buildButton);
173        select.add(printButton);
174        select.add(openFileButton);
175        select.add(runFileButton);
176        select.add(switchListsButton);
177        select.add(terminateButton);
178        select.add(resetButton);
179
180        JPanel save = new JPanel();
181        save.setBorder(BorderFactory.createTitledBorder(""));
182        save.add(saveButton);
183
184        JPanel cp2 = new JPanel();
185        cp2.setLayout(new BoxLayout(cp2, BoxLayout.X_AXIS));
186        cp2.add(addTrain);
187        cp2.add(select);
188        cp2.add(save);
189
190        // place controls in scroll pane
191        JPanel controlPanel = new JPanel();
192        controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS));
193        controlPanel.add(cp1);
194        controlPanel.add(cp2);
195
196        JScrollPane controlPane = new JScrollPane(controlPanel);
197
198        getContentPane().add(trainsPane);
199        getContentPane().add(controlPane);
200
201        // setup buttons
202        addButtonAction(addButton);
203        addButtonAction(buildButton);
204        addButtonAction(printButton);
205        addButtonAction(openFileButton);
206        addButtonAction(runFileButton);
207        addButtonAction(switchListsButton);
208        addButtonAction(terminateButton);
209        addButtonAction(resetButton);
210        addButtonAction(saveButton);
211
212        ButtonGroup showGroup = new ButtonGroup();
213        showGroup.add(showTime);
214        showGroup.add(showId);
215        showTime.setSelected(true);
216
217        ButtonGroup actionGroup = new ButtonGroup();
218        actionGroup.add(moveRB);
219        actionGroup.add(conductorRB);
220        actionGroup.add(terminateRB);
221        actionGroup.add(resetRB);
222
223        addRadioButtonAction(showTime);
224        addRadioButtonAction(showId);
225
226        addRadioButtonAction(moveRB);
227        addRadioButtonAction(terminateRB);
228        addRadioButtonAction(resetRB);
229        addRadioButtonAction(conductorRB);
230
231        buildMsgBox.setSelected(trainManager.isBuildMessagesEnabled());
232        buildReportBox.setSelected(trainManager.isBuildReportEnabled());
233        printPreviewBox.setSelected(trainManager.isPrintPreviewEnabled());
234        openFileBox.setSelected(trainManager.isOpenFileEnabled());
235        runFileBox.setSelected(trainManager.isRunFileEnabled());
236        showAllBox.setSelected(trainsModel.isShowAll());
237
238        // show open files only if create csv is enabled
239        updateRunAndOpenButtons();
240
241        addCheckBoxAction(buildMsgBox);
242        addCheckBoxAction(buildReportBox);
243        addCheckBoxAction(printPreviewBox);
244        addCheckBoxAction(showAllBox);
245        addCheckBoxAction(openFileBox);
246        addCheckBoxAction(runFileBox);
247
248        // Set the button text to Print or Preview
249        setPrintButtonText();
250        // Set the train action button text to Move or Terminate
251        setTrainActionButton();
252
253        // build menu
254        JMenuBar menuBar = new JMenuBar();
255        JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools"));
256        toolMenu.add(new OptionAction());
257        toolMenu.add(new PrintOptionAction());
258        toolMenu.add(new BuildReportOptionAction());
259        toolMenu.addSeparator();
260        toolMenu.add(new TrainsScheduleAction());
261        toolMenu.addSeparator();
262        toolMenu.add(new TrainsByCarTypeAction());
263        toolMenu.add(new TrainByCarTypeAction(null));
264        toolMenu.addSeparator();
265        toolMenu.add(new ChangeDepartureTimesAction());
266        toolMenu.add(new TrainsTableSetColorAction());
267        toolMenu.add(new TrainCopyAction());
268        toolMenu.addSeparator();
269        toolMenu.add(new TrainsScriptAction(this));
270        toolMenu.add(new AutomationsTableFrameAction());
271        toolMenu.add(new SetupExcelProgramFrameAction());
272        toolMenu.addSeparator();
273        toolMenu.add(new ExportTrainRosterAction());
274        toolMenu.add(new ExportTimetableAction());
275        toolMenu.add(new ExportTrainLineupsAction());
276        toolMenu.addSeparator();
277        toolMenu.add(new PrintTrainsAction(false, this));
278        toolMenu.add(new PrintTrainsAction(true, this));
279        toolMenu.add(new PrintSavedTrainManifestAction(false, null));
280        toolMenu.add(new PrintSavedTrainManifestAction(true, null));
281
282        menuBar.add(toolMenu);
283        menuBar.add(new jmri.jmrit.operations.OperationsMenu());
284        setJMenuBar(menuBar);
285
286        // add help menu to window
287        addHelpMenu("package.jmri.jmrit.operations.Operations_Trains", true); // NOI18N
288
289        initMinimumSize(new Dimension(Control.panelWidth700, Control.panelHeight250));
290
291        addHorizontalScrollBarKludgeFix(controlPane, controlPanel);
292
293        // listen for train schedule changes
294        InstanceManager.getDefault(TrainScheduleManager.class).addPropertyChangeListener(this);
295        // listen for changes in the number of trains
296        trainManager.addPropertyChangeListener(this);
297        Setup.getDefault().addPropertyChangeListener(this);
298        // listen for location switch list changes
299        addPropertyChangeLocations();
300
301        // now load train icons on panels
302        trainManager.loadTrainIcons();
303
304        // auto save
305        AutoSave.start();
306    }
307
308    @Override
309    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
310        log.debug("radio button activated");
311        // clear any sorts by column
312        clearTableSort(trainsTable);
313        if (ae.getSource() == showId) {
314            trainsModel.setSort(trainsModel.SORTBYID);
315        }
316        if (ae.getSource() == showTime) {
317            trainsModel.setSort(trainsModel.SORTBYTIME);
318        }
319        if (ae.getSource() == moveRB) {
320            trainManager.setTrainsFrameTrainAction(MOVE);
321        }
322        if (ae.getSource() == terminateRB) {
323            trainManager.setTrainsFrameTrainAction(TERMINATE);
324        }
325        if (ae.getSource() == resetRB) {
326            trainManager.setTrainsFrameTrainAction(RESET);
327        }
328        if (ae.getSource() == conductorRB) {
329            trainManager.setTrainsFrameTrainAction(CONDUCTOR);
330        }
331    }
332
333    TrainSwitchListEditFrame tslef;
334
335    // add, build, print, switch lists, terminate, and save buttons
336    @Override
337    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
338        // log.debug("train button activated");
339        if (ae.getSource() == addButton) {
340            new TrainEditFrame(null);
341        }
342        if (ae.getSource() == buildButton) {
343            runFileButton.setEnabled(false);
344            // uses a thread which allows table updates during build
345            trainManager.buildSelectedTrains(getSortByList());
346        }
347        if (ae.getSource() == printButton) {
348            trainManager.printSelectedTrains(getSortByList());
349        }
350        if (ae.getSource() == openFileButton) {
351            openFile();
352        }
353        if (ae.getSource() == runFileButton) {
354            runExcel();
355        }
356        if (ae.getSource() == switchListsButton) {
357            if (tslef != null) {
358                tslef.dispose();
359            }
360            tslef = new TrainSwitchListEditFrame();
361            tslef.initComponents();
362        }
363        if (ae.getSource() == terminateButton) {
364            trainManager.terminateSelectedTrains(getSortByList());
365        }
366        if (ae.getSource() == resetButton) {
367            trainManager.resetTrains();
368        }
369        if (ae.getSource() == saveButton) {
370            storeValues();
371        }
372    }
373
374    private void openFile() {
375        // open the csv files
376        List<Train> trains = getSortByList();
377        for (Train train : trains) {
378            if (train.isBuildEnabled()) {
379                if (!train.isBuilt() && trainManager.isBuildMessagesEnabled()) {
380                    int response = JmriJOptionPane.showConfirmDialog(this,
381                            Bundle.getMessage("NeedToBuildBeforeOpenFile",
382                                    train.getName()),
383                            Bundle.getMessage("ErrorTitle"), JmriJOptionPane.OK_CANCEL_OPTION);
384                    if (response != JmriJOptionPane.OK_OPTION) {
385                        break;
386                    }
387                } else if (train.isBuilt()) {
388                    train.openFile();
389                }
390            }
391        }
392    }
393
394    private void runExcel() {
395        // Run on thread since addCsvFile(file) can wait for excel program to complete
396        Thread runExcel = jmri.util.ThreadingUtil.newThread(() -> {
397            // Processes the CSV Manifest files using an external custom program.
398            TrainCustomManifest tcm = InstanceManager.getDefault(TrainCustomManifest.class);
399            if (!tcm.doesExcelFileExist()) {
400                log.warn("Manifest creator file not found!, directory path: {}, file name: {}",
401                        tcm.getDirectoryPathName(),
402                        tcm.getFileName());
403                JmriJOptionPane.showMessageDialog(this,
404                        Bundle.getMessage("LoadDirectoryNameFileName",
405                                tcm.getDirectoryPathName(), tcm.getFileName()),
406                        Bundle.getMessage("ManifestCreatorNotFound"), JmriJOptionPane.ERROR_MESSAGE);
407                return;
408            }
409            List<Train> trains = getSortByList();
410            for (Train train : trains) {
411                if (train.isBuildEnabled()) {
412                    if (!train.isBuilt() && trainManager.isBuildMessagesEnabled()) {
413                        int response = JmriJOptionPane.showConfirmDialog(this,
414                                Bundle.getMessage("NeedToBuildBeforeRunFile",
415                                        train.getName()),
416                                Bundle.getMessage("ErrorTitle"), JmriJOptionPane.OK_CANCEL_OPTION);
417                        if (response != JmriJOptionPane.OK_OPTION) {
418                            break;
419                        }
420                    } else if (train.isBuilt()) {
421                        // Add csv manifest file to our collection to be processed.
422                        tcm.addCsvFile(train.createCsvManifestFile());
423                        train.setPrinted(true);
424                    }
425                }
426            }
427            // Now run the user specified custom Manifest processor program
428            tcm.process();
429        });
430        runExcel.setName("Run Excel program"); // NOI18N
431        runExcel.start();
432    }
433
434    SortOrder _status = SortOrder.ASCENDING;
435
436    public String getSortBy() {
437        // set the defaults
438        String sortBy = TrainsTableModel.TIMECOLUMNNAME;
439        _status = SortOrder.ASCENDING;
440        // now look to see if a sort is active
441        for (RowSorter.SortKey key : trainsTable.getRowSorter().getSortKeys()) {
442            String name = trainsModel.getColumnName(key.getColumn());
443            SortOrder status = key.getSortOrder();
444            // log.debug("Column {} status {}", name, status);
445            if (!status.equals(SortOrder.UNSORTED) && !name.isEmpty()) {
446                sortBy = name;
447                _status = status;
448                break;
449            }
450        }
451        return sortBy;
452    }
453
454    public List<Train> getSortByList() {
455        return getSortByList(getSortBy());
456    }
457
458    public List<Train> getSortByList(String sortBy) {
459        List<Train> sysList;
460
461        if (sortBy.equals(TrainsTableModel.IDCOLUMNNAME)) {
462            sysList = trainManager.getTrainsByIdList();
463        } else if (sortBy.equals(TrainsTableModel.TIMECOLUMNNAME)) {
464            sysList = trainManager.getTrainsByTimeList();
465        } else if (sortBy.equals(TrainsTableModel.DEPARTSCOLUMNNAME)) {
466            sysList = trainManager.getTrainsByDepartureList();
467        } else if (sortBy.equals(TrainsTableModel.TERMINATESCOLUMNNAME)) {
468            sysList = trainManager.getTrainsByTerminatesList();
469        } else if (sortBy.equals(TrainsTableModel.ROUTECOLUMNNAME)) {
470            sysList = trainManager.getTrainsByRouteList();
471        } else if (sortBy.equals(TrainsTableModel.STATUSCOLUMNNAME)) {
472            sysList = trainManager.getTrainsByStatusList();
473        } else if (sortBy.equals(TrainsTableModel.DESCRIPTIONCOLUMNNAME)) {
474            sysList = trainManager.getTrainsByDescriptionList();
475        } else {
476            sysList = trainManager.getTrainsByNameList();
477        }
478        return sysList;
479    }
480
481    // Modifies button text and tool tips
482    private void setPrintButtonText() {
483        if (printPreviewBox.isSelected()) {
484            printButton.setText(Bundle.getMessage("Preview"));
485            printButton.setToolTipText(Bundle.getMessage("PreviewSelectedTip"));
486            buildReportBox.setToolTipText(Bundle.getMessage("BuildReportPreviewTip"));
487        } else {
488            printButton.setText(Bundle.getMessage("Print"));
489            printButton.setToolTipText(Bundle.getMessage("PrintSelectedTip"));
490            buildReportBox.setToolTipText(Bundle.getMessage("BuildReportPrintTip"));
491        }
492    }
493
494    private void setTrainActionButton() {
495        moveRB.setSelected(trainManager.getTrainsFrameTrainAction().equals(TrainsTableFrame.MOVE));
496        terminateRB.setSelected(trainManager.getTrainsFrameTrainAction().equals(TrainsTableFrame.TERMINATE));
497        resetRB.setSelected(trainManager.getTrainsFrameTrainAction().equals(TrainsTableFrame.RESET));
498        conductorRB.setSelected(trainManager.getTrainsFrameTrainAction().equals(TrainsTableFrame.CONDUCTOR));
499    }
500
501    @Override
502    public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
503        if (ae.getSource() == buildMsgBox) {
504            trainManager.setBuildMessagesEnabled(buildMsgBox.isSelected());
505        }
506        if (ae.getSource() == buildReportBox) {
507            trainManager.setBuildReportEnabled(buildReportBox.isSelected());
508        }
509        if (ae.getSource() == printPreviewBox) {
510            trainManager.setPrintPreviewEnabled(printPreviewBox.isSelected());
511            setPrintButtonText(); // set the button text for Print or Preview
512        }
513        if (ae.getSource() == openFileBox) {
514            trainManager.setOpenFileEnabled(openFileBox.isSelected());
515            runFileBox.setSelected(false);
516            trainManager.setRunFileEnabled(false);
517        }
518        if (ae.getSource() == runFileBox) {
519            trainManager.setRunFileEnabled(runFileBox.isSelected());
520            openFileBox.setSelected(false);
521            trainManager.setOpenFileEnabled(false);
522        }
523        if (ae.getSource() == showAllBox) {
524            trainsModel.setShowAll(showAllBox.isSelected());
525        }
526    }
527
528    private void updateTitle() {
529        String title = Bundle.getMessage("TitleTrainsTable");
530        TrainSchedule sch = InstanceManager.getDefault(TrainScheduleManager.class).getActiveSchedule();
531        if (sch != null) {
532            title = title + " " + sch.getName();
533        }
534        setTitle(title);
535    }
536
537    private void updateSwitchListButton() {
538        List<Location> locations = locationManager.getList();
539        for (Location location : locations) {
540            if (location != null && location.isSwitchListEnabled() && location.getStatus().equals(Location.MODIFIED)) {
541                switchListsButton.setBackground(Color.RED);
542                return;
543            }
544        }
545        switchListsButton.setBackground(Color.GREEN);
546    }
547
548    // show open files only if create csv is enabled
549    private void updateRunAndOpenButtons() {
550        openFileBox.setVisible(Setup.isGenerateCsvManifestEnabled());
551        openFileButton.setVisible(Setup.isGenerateCsvManifestEnabled());
552        runFileBox.setVisible(Setup.isGenerateCsvManifestEnabled());
553        runFileButton.setVisible(Setup.isGenerateCsvManifestEnabled());
554    }
555
556    private synchronized void addPropertyChangeLocations() {
557        List<Location> locations = locationManager.getList();
558        for (Location location : locations) {
559            location.addPropertyChangeListener(this);
560        }
561    }
562
563    private synchronized void removePropertyChangeLocations() {
564        List<Location> locations = locationManager.getList();
565        for (Location location : locations) {
566            location.removePropertyChangeListener(this);
567        }
568    }
569
570    @Override
571    public void dispose() {
572        trainsModel.dispose();
573        trainManager.runShutDownScripts();
574        trainManager.removePropertyChangeListener(this);
575        InstanceManager.getDefault(TrainScheduleManager.class).removePropertyChangeListener(this);
576        Setup.getDefault().removePropertyChangeListener(this);
577        removePropertyChangeLocations();
578        setModifiedFlag(false);
579        InstanceManager.getOptionalDefault(JTablePersistenceManager.class).ifPresent(tpm -> {
580            tpm.stopPersisting(trainsTable);
581        });
582        super.dispose();
583    }
584
585    @Override
586    protected void handleModified() {
587        if (!getModifiedFlag()) {
588            return;
589        }
590        if (Setup.isAutoSaveEnabled()) {
591            storeValues();
592            return;
593        }
594        if (OperationsXml.areFilesDirty()) {
595            int result = JmriJOptionPane.showOptionDialog(this, Bundle.getMessage("PromptQuitWindowNotWritten"),
596                    Bundle.getMessage("PromptSaveQuit"), JmriJOptionPane.YES_NO_OPTION,
597                    JmriJOptionPane.WARNING_MESSAGE, null,
598                    new String[] { ResourceBundle.getBundle("jmri.util.UtilBundle").getString("WarnYesSave"), // NOI18N
599                            ResourceBundle.getBundle("jmri.util.UtilBundle").getString("WarnNoClose") }, // NOI18N
600                    ResourceBundle.getBundle("jmri.util.UtilBundle").getString("WarnYesSave"));
601            if (result == JmriJOptionPane.YES_OPTION) {
602                // user wants to save
603                storeValues();
604            }
605        }
606    }
607
608    @Override
609    protected void storeValues() {
610        super.storeValues();
611    }
612
613    @Override
614    public void propertyChange(java.beans.PropertyChangeEvent e) {
615        if (Control.SHOW_PROPERTY) {
616            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(),
617                    e.getNewValue());
618        }
619        if (e.getPropertyName().equals(TrainScheduleManager.SCHEDULE_ID_CHANGED_PROPERTY)) {
620            updateTitle();
621        }
622        if (e.getPropertyName().equals(Location.STATUS_CHANGED_PROPERTY) ||
623                e.getPropertyName().equals(Location.SWITCHLIST_CHANGED_PROPERTY)) {
624            log.debug("update switch list button location ({})", e.getSource());
625            updateSwitchListButton();
626        }
627        if (e.getPropertyName().equals(Setup.MANIFEST_CSV_PROPERTY_CHANGE)) {
628            updateRunAndOpenButtons();
629        }
630        if (e.getPropertyName().equals(TrainManager.LISTLENGTH_CHANGED_PROPERTY)) {
631            numTrains.setText(Integer.toString(trainManager.getNumEntries()));
632        }
633        if (e.getPropertyName().equals(TrainManager.TRAINS_BUILT_CHANGED_PROPERTY)) {
634            runFileButton.setEnabled(true);
635        }
636    }
637
638    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrainsTableFrame.class);
639}