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