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