001package jmri.jmrit.operations.trains;
002
003import java.awt.Dimension;
004import java.awt.GridBagLayout;
005import java.awt.event.ActionEvent;
006import java.beans.PropertyChangeEvent;
007import java.io.File;
008import java.util.ArrayList;
009import java.util.List;
010
011import javax.swing.*;
012import javax.swing.filechooser.FileNameExtensionFilter;
013
014import jmri.InstanceManager;
015import jmri.jmrit.operations.*;
016import jmri.jmrit.operations.locations.Location;
017import jmri.jmrit.operations.locations.LocationManager;
018import jmri.jmrit.operations.setup.Control;
019import jmri.jmrit.operations.setup.Setup;
020import jmri.jmrit.operations.trains.excel.SetupExcelProgramSwitchListFrameAction;
021import jmri.jmrit.operations.trains.excel.TrainCustomSwitchList;
022import jmri.util.swing.JmriJOptionPane;
023
024/**
025 * Frame for user selection of switch lists
026 *
027 * @author Dan Boudreau Copyright (C) 2008, 2012, 2013, 2014, 2021
028 */
029public class TrainSwitchListEditFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
030
031    JScrollPane switchPane;
032
033    // load managers
034    LocationManager locationManager = InstanceManager.getDefault(LocationManager.class);
035    List<JCheckBox> locationCheckBoxes = new ArrayList<>();
036    List<JComboBox<String>> locationComboBoxes = new ArrayList<>();
037    JPanel locationPanelCheckBoxes = new JPanel();
038
039    // checkboxes
040    JCheckBox switchListRealTimeCheckBox = new JCheckBox(Bundle.getMessage("SwitchListRealTime"));
041    JCheckBox switchListAllTrainsCheckBox = new JCheckBox(Bundle.getMessage("SwitchListAllTrains"));
042
043    // major buttons
044    JButton clearButton = new JButton(Bundle.getMessage("ClearAll"));
045    JButton setButton = new JButton(Bundle.getMessage("SelectAll"));
046    JButton printButton = new JButton(Bundle.getMessage("PrintSwitchLists"));
047    JButton previewButton = new JButton(Bundle.getMessage("PreviewSwitchLists"));
048    JButton printChangesButton = new JButton(Bundle.getMessage("PrintChanges"));
049    JButton runButton = new JButton(Bundle.getMessage("RunFile"));
050    JButton runChangeButton = new JButton(Bundle.getMessage("RunFileChanges"));
051    JButton openFileButton = new JButton(Bundle.getMessage("OpenFile"));
052    JButton updateButton = new JButton(Bundle.getMessage("Update"));
053    JButton resetButton = new JButton(Bundle.getMessage("ResetSwitchLists"));
054    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
055
056    JComboBox<String> switchListPageComboBox = Setup.getSwitchListPageFormatComboBox();
057
058    // panels
059    JPanel customPanel;
060
061    public TrainSwitchListEditFrame() {
062        super(Bundle.getMessage("TitleSwitchLists"));
063    }
064
065    @Override
066    public void initComponents() {
067        // listen for any changes in the number of locations
068        locationManager.addPropertyChangeListener(this);
069
070        // the following code sets the frame's initial state
071        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
072
073        // tool tips
074        switchListRealTimeCheckBox.setToolTipText(Bundle.getMessage("RealTimeTip"));
075        switchListAllTrainsCheckBox.setToolTipText(Bundle.getMessage("AllTrainsTip"));
076        switchListPageComboBox.setToolTipText(Bundle.getMessage("PageTrainTip"));
077        printChangesButton.setToolTipText(Bundle.getMessage("PrintChangesTip"));
078        resetButton.setToolTipText(Bundle.getMessage("ResetSwitchListTip"));
079
080        switchPane = new JScrollPane(locationPanelCheckBoxes);
081        switchPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
082        switchPane.setBorder(BorderFactory.createTitledBorder(""));
083
084        // Layout the panel by rows
085        locationPanelCheckBoxes.setLayout(new GridBagLayout());
086        updateLocationCheckboxes();
087        enableSaveButton(false);
088
089        // Clear and set buttons
090        JPanel pButtons = new JPanel();
091        pButtons.setLayout(new GridBagLayout());
092        pButtons.setBorder(BorderFactory.createTitledBorder(""));
093        addItem(pButtons, clearButton, 0, 1);
094        addItem(pButtons, setButton, 1, 1);
095
096        // options
097        JPanel pSwitchListOptions = new JPanel();
098        pSwitchListOptions.setLayout(new GridBagLayout());
099        pSwitchListOptions
100                .setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutSwitchListOptions")));
101
102        JPanel pSwitchListPageFormat = new JPanel();
103        pSwitchListPageFormat
104                .setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutSwitchListPageFormat")));
105        pSwitchListPageFormat.add(switchListPageComboBox);
106
107        addItem(pSwitchListOptions, switchListAllTrainsCheckBox, 1, 0);
108        addItem(pSwitchListOptions, pSwitchListPageFormat, 2, 0);
109        addItem(pSwitchListOptions, switchListRealTimeCheckBox, 3, 0);
110        addItem(pSwitchListOptions, saveButton, 4, 0);
111
112        // buttons
113        JPanel controlPanel = new JPanel();
114        controlPanel.setLayout(new GridBagLayout());
115        controlPanel.setBorder(BorderFactory.createTitledBorder(""));
116
117        // row 3
118        addItem(controlPanel, previewButton, 0, 2);
119        addItem(controlPanel, printButton, 1, 2);
120        addItem(controlPanel, printChangesButton, 2, 2);
121        // row 4
122        addItem(controlPanel, updateButton, 0, 3);
123        addItem(controlPanel, resetButton, 1, 3);
124
125        // row 5
126        customPanel = new JPanel();
127        customPanel.setLayout(new GridBagLayout());
128        customPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutCustomSwitchLists")));
129
130        addItem(customPanel, runButton, 1, 5);
131        addItem(customPanel, runChangeButton, 2, 5);
132        addItem(customPanel, openFileButton, 3, 5);
133
134        getContentPane().add(switchPane);
135        getContentPane().add(pButtons);
136        getContentPane().add(pSwitchListOptions);
137        getContentPane().add(controlPanel);
138        getContentPane().add(customPanel);
139
140        customPanel.setVisible(Setup.isGenerateCsvSwitchListEnabled());
141
142        // Set the state
143        switchListRealTimeCheckBox.setSelected(Setup.isSwitchListRealTime());
144        switchListAllTrainsCheckBox.setSelected(Setup.isSwitchListAllTrainsEnabled());
145        switchListPageComboBox.setSelectedItem(Setup.getSwitchListPageFormat());
146
147        updateButton.setVisible(!switchListRealTimeCheckBox.isSelected());
148        resetButton.setVisible(!switchListRealTimeCheckBox.isSelected());
149        saveButton.setEnabled(false);
150
151        addButtonAction(clearButton);
152        addButtonAction(setButton);
153        addButtonAction(printButton);
154        addButtonAction(previewButton);
155        addButtonAction(printChangesButton);
156        addButtonAction(runButton);
157        addButtonAction(runChangeButton);
158        addButtonAction(openFileButton);
159        addButtonAction(updateButton);
160        addButtonAction(resetButton);
161        addButtonAction(saveButton);
162
163        addCheckBoxAction(switchListRealTimeCheckBox);
164        addCheckBoxAction(switchListAllTrainsCheckBox);
165
166        addComboBoxAction(switchListPageComboBox);
167
168        Setup.getDefault().addPropertyChangeListener(this);
169
170        // build menu
171        JMenuBar menuBar = new JMenuBar();
172        JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools"));
173        toolMenu.add(new SetupExcelProgramSwitchListFrameAction());
174        menuBar.add(toolMenu);
175        setJMenuBar(menuBar);
176
177        // add help menu to window
178        addHelpMenu("package.jmri.jmrit.operations.Operations_SwitchList", true); // NOI18N
179        // set frame size and train for display
180        initMinimumSize(new Dimension(Control.panelWidth500, Control.panelHeight500));
181    }
182
183    private static final boolean IS_CHANGED = true;
184    private static final boolean IS_PRINT = true; // print or preview
185    private static final boolean IS_PREVIEW = true;
186
187    // Buttons
188    @Override
189    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
190        if (ae.getSource() == clearButton) {
191            selectCheckboxes(false);
192        }
193        if (ae.getSource() == setButton) {
194            selectCheckboxes(true);
195        }
196        if (ae.getSource() == previewButton) {
197            buildSwitchList(!IS_CHANGED, IS_PRINT, IS_PREVIEW);
198        }
199        if (ae.getSource() == printButton) {
200            buildSwitchList(!IS_CHANGED, IS_PRINT, !IS_PREVIEW);
201        }
202        if (ae.getSource() == printChangesButton) {
203            buildSwitchList(IS_CHANGED, IS_PRINT, !IS_PREVIEW);
204        }
205        if (ae.getSource() == updateButton) {
206            buildSwitchList(!IS_CHANGED, !IS_PRINT, IS_PREVIEW);
207        }
208        if (ae.getSource() == runButton) {
209            runCustomSwitchLists(!IS_CHANGED);
210        }
211        if (ae.getSource() == runChangeButton) {
212            runCustomSwitchLists(IS_CHANGED);
213        }
214        if (ae.getSource() == openFileButton) {
215            buildSwitchList(IS_CHANGED, !IS_PRINT, IS_PREVIEW);
216            openCsvSwitchList();
217        }
218        if (ae.getSource() == resetButton) {
219            reset();
220        }
221        if (ae.getSource() == saveButton) {
222            save();
223            if (Setup.isCloseWindowOnSaveEnabled()) {
224                dispose();
225            }
226        }
227    }
228
229    @Override
230    public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
231        if (ae.getSource() == switchListRealTimeCheckBox) {
232            updateButton.setVisible(!switchListRealTimeCheckBox.isSelected());
233            resetButton.setVisible(!switchListRealTimeCheckBox.isSelected());
234        }
235        // enable the save button whenever a checkbox is changed
236        enableSaveButton(true);
237    }
238
239    // Remove all terminated or reset trains from the switch lists for selected
240    // locations
241    private void reset() {
242        // Confirm that user really wants to delete all terminated and reset trains from
243        // the switch lists
244        if (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("DoYouReallyWantDeleteSwitchListData"),
245                Bundle.getMessage("ResetSwitchLists"), JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
246            return;
247        }
248
249        // this for loop prevents ConcurrentModificationException when printing and
250        // status changes
251        for (JCheckBox checkbox : new ArrayList<>(locationCheckBoxes)) {
252            String locationName = checkbox.getName();
253            Location location = locationManager.getLocationByName(locationName);
254            if (location.isSwitchListEnabled()) {
255                // new switch lists will now be created for the location
256                location.setSwitchListState(Location.SW_CREATE);
257                location.setStatus(Location.MODIFIED);
258            }
259        }
260        // set trains switch lists unknown, any built trains should remain on the switch
261        // lists
262        InstanceManager.getDefault(TrainManager.class).setTrainsSwitchListStatus(Train.UNKNOWN);
263    }
264
265    // save printer selection
266    private void save() {
267        // this for loop prevents ConcurrentModificationException when printing and
268        // status changes
269        for (int i = 0; i < locationCheckBoxes.size(); i++) {
270            String locationName = locationCheckBoxes.get(i).getName();
271            Location location = locationManager.getLocationByName(locationName);
272            JComboBox<String> comboBox = locationComboBoxes.get(i);
273            String printerName = (String) comboBox.getSelectedItem();
274            if (printerName == null || printerName.equals(TrainPrintUtilities.getDefaultPrinterName())) {
275                location.setDefaultPrinterName(Location.NONE);
276            } else {
277                log.debug("Location {} has selected printer {}", location.getName(), printerName);
278                location.setDefaultPrinterName(printerName);
279            }
280        }
281        // reset if changing to consolidation mode
282        if (Setup.isSwitchListRealTime() && !switchListRealTimeCheckBox.isSelected()) {
283            reset();
284        }
285        Setup.setSwitchListRealTime(switchListRealTimeCheckBox.isSelected());
286        Setup.setSwitchListAllTrainsEnabled(switchListAllTrainsCheckBox.isSelected());
287        Setup.setSwitchListPageFormat((String) switchListPageComboBox.getSelectedItem());
288        // save location file
289        OperationsXml.save();
290        enableSaveButton(false);
291        if (Setup.isCloseWindowOnSaveEnabled()) {
292            dispose();
293        }
294    }
295
296    /**
297     *
298     * @param isPreview true if print preview
299     * @param isChanged true if only print changes was requested
300     * @param isPrint   true if printing or preview
301     */
302    private void buildSwitchList(boolean isChanged, boolean isPrint, boolean isPreview) {
303        TrainSwitchLists trainSwitchLists = new TrainSwitchLists();
304        TrainCsvSwitchLists trainCsvSwitchLists = new TrainCsvSwitchLists();
305        // this for loop prevents ConcurrentModificationException when printing and
306        // status changes
307        for (JCheckBox checkbox : new ArrayList<>(locationCheckBoxes)) {
308            String locationName = checkbox.getName();
309            Location location = locationManager.getLocationByName(locationName);
310            if (location.isSwitchListEnabled() && (!isChanged || location.getStatus().equals(Location.MODIFIED))) {
311                // update switch lists
312                trainCsvSwitchLists.buildSwitchList(location);
313                trainSwitchLists.buildSwitchList(location);
314                // print or only print changes
315                if (isPrint) {
316                    trainSwitchLists.printSwitchList(location, isPreview);
317                }
318            }
319        }
320        // set trains switch lists printed
321        InstanceManager.getDefault(TrainManager.class).setTrainsSwitchListStatus(Train.PRINTED);
322    }
323
324    private void selectCheckboxes(boolean enable) {
325        for (JCheckBox checkbox : new ArrayList<>(locationCheckBoxes)) {
326            String locationName = checkbox.getName();
327            Location location = locationManager.getLocationByName(locationName);
328            location.setSwitchListEnabled(enable);
329        }
330        // enable the save button whenever a checkbox is changed
331        saveButton.setEnabled(true);
332    }
333
334    // TODO there's a ConcurrentModificationException when the printer status
335    // changes
336    // when printing. This routine rebuilds the locationCheckBoxes during the
337    // update.
338    // A better solution would only update the status for a location.
339    // name change or number of locations has changed
340    private void updateLocationCheckboxes() {
341        List<Location> locations = locationManager.getLocationsByNameList();
342        synchronized (this) {
343            for (Location location : locations) {
344                location.removePropertyChangeListener(this);
345            }
346        }
347
348        locationCheckBoxes.clear();
349        locationComboBoxes.clear(); // remove printer selection
350        locationPanelCheckBoxes.removeAll();
351
352        // create header
353        addItem(locationPanelCheckBoxes, new JLabel(Bundle.getMessage("Location")), 0, 0);
354        addItem(locationPanelCheckBoxes, new JLabel("        "), 1, 0);
355        addItem(locationPanelCheckBoxes, new JLabel(Bundle.getMessage("Status")), 2, 0);
356        addItem(locationPanelCheckBoxes, new JLabel("        "), 3, 0);
357        addItem(locationPanelCheckBoxes, new JLabel(Bundle.getMessage("Comment")), 4, 0);
358        addItem(locationPanelCheckBoxes, new JLabel("        "), 5, 0);
359        addItem(locationPanelCheckBoxes, new JLabel(Bundle.getMessage("Printer")), 6, 0);
360
361        int y = 1; // vertical position in panel
362
363        // note that getUniqueLocationsByNameList() method updates the status of
364        // locations with "similar" names.
365        for (Location location : locationManager.getUniqueLocationsByNameList()) {
366            JCheckBox checkBox = new JCheckBox();
367            locationCheckBoxes.add(checkBox);
368            checkBox.setSelected(location.isSwitchListEnabled());
369            checkBox.setText(location.getSplitName());
370            checkBox.setName(location.getName());
371            addLocationCheckBoxAction(checkBox);
372            addItemLeft(locationPanelCheckBoxes, checkBox, 0, y);
373
374            JLabel status = new JLabel(location.getStatus());
375            addItem(locationPanelCheckBoxes, status, 2, y);
376
377            JButton button = new JButton(Bundle.getMessage("Add"));
378            if (!location.getSwitchListCommentWithColor().isEmpty()) {
379                button.setText(Bundle.getMessage("ButtonEdit"));
380            }
381            button.setName(location.getName());
382            addCommentButtonAction(button);
383            addItem(locationPanelCheckBoxes, button, 4, y);
384
385            JComboBox<String> comboBox = TrainPrintUtilities.getPrinterJComboBox();
386            locationComboBoxes.add(comboBox);
387            comboBox.setSelectedItem(location.getDefaultPrinterName());
388            addComboBoxAction(comboBox);
389            addItem(locationPanelCheckBoxes, comboBox, 6, y++);
390        }
391
392        // restore listeners
393        synchronized (this) {
394            for (Location location : locations) {
395                location.addPropertyChangeListener(this);
396            }
397        }
398
399        locationPanelCheckBoxes.revalidate();
400        pack();
401        repaint();
402    }
403
404    /**
405     * Creates custom switch lists using an external program like MS Excel. Switch
406     * lists are created for locations that have switch lists enabled.
407     * 
408     * @param isChanged when true, only create custom switch list for enabled
409     *                  locations that have changes. When isChanged is false, create
410     *                  custom switch lists for all enabled locations.
411     */
412    private void runCustomSwitchLists(boolean isChanged) {
413        if (!Setup.isGenerateCsvSwitchListEnabled()) {
414            return;
415        }
416        log.debug("run custom switch lists");
417        TrainSwitchLists trainSwitchLists = new TrainSwitchLists();
418        TrainCsvSwitchLists trainCsvSwitchLists = new TrainCsvSwitchLists();
419        // this for loop prevents ConcurrentModificationException when printing and
420        // status changes
421        for (JCheckBox checkbox : new ArrayList<>(locationCheckBoxes)) {
422            String locationName = checkbox.getName();
423            Location location = locationManager.getLocationByName(locationName);
424            if (location.isSwitchListEnabled() && (!isChanged || location.getStatus().equals(Location.MODIFIED))) {
425                File csvFile = trainCsvSwitchLists.buildSwitchList(location);
426                // also build the regular switch lists so they can be used
427                trainSwitchLists.buildSwitchList(location);
428                if (csvFile == null || !csvFile.exists()) {
429                    log.error("CSV switch list file was not created for location {}", locationName);
430                    return;
431                }
432                InstanceManager.getDefault(TrainCustomSwitchList.class).addCsvFile(csvFile);
433            }
434        }
435        // Processes the CSV Manifest files using an external custom program.
436        if (!InstanceManager.getDefault(TrainCustomSwitchList.class).excelFileExists()) {
437            log.warn("Manifest creator file not found!, directory path: {}, file name: {}",
438                    InstanceManager.getDefault(TrainCustomSwitchList.class).getDirectoryPathName(),
439                    InstanceManager.getDefault(TrainCustomSwitchList.class).getFileName());
440            JmriJOptionPane.showMessageDialog(this,
441                    Bundle.getMessage("LoadDirectoryNameFileName",
442                            InstanceManager.getDefault(TrainCustomSwitchList.class).getDirectoryPathName(),
443                                    InstanceManager.getDefault(TrainCustomSwitchList.class).getFileName()),
444                    Bundle.getMessage("ManifestCreatorNotFound"), JmriJOptionPane.ERROR_MESSAGE);
445            return;
446        }
447        // Now run the user specified custom Switch List processor program
448        InstanceManager.getDefault(TrainCustomSwitchList.class).process();
449        // set trains switch lists printed
450        InstanceManager.getDefault(TrainManager.class).setTrainsSwitchListStatus(Train.PRINTED);
451    }
452
453    private void openCsvSwitchList() {
454        File file = selectFile();
455        if (file != null) {
456            TrainUtilities.openDesktop(file);
457        }
458    }
459
460    /**
461     * We always use the same file chooser in this class, so that the user's
462     * last-accessed directory remains available.
463     */
464    JFileChooser fc;
465
466    private File selectFile() {
467        if (fc == null) {
468            fc = new jmri.util.swing.JmriJFileChooser(
469                    InstanceManager.getDefault(TrainManagerXml.class).getDefaultCsvSwitchListDirectoryName());
470            fc.setFileFilter(new FileNameExtensionFilter("Comma Separated Values", "csv")); // NOI18N
471            fc.setDialogTitle(Bundle.getMessage("TitleSwitchLists"));
472        }
473        // when reusing the chooser, make sure new files are included
474        fc.rescanCurrentDirectory();
475        int retVal = fc.showOpenDialog(this);
476        // handle selection or cancel
477        if (retVal == JFileChooser.APPROVE_OPTION) {
478            return fc.getSelectedFile();
479        }
480        return null;
481    }
482
483    private void enableSaveButton(boolean enable) {
484        saveButton.setEnabled(enable);
485        // these get the inverse
486        previewButton.setEnabled(!enable);
487        printButton
488                .setEnabled(!enable && (!Control.disablePrintingIfCustom || !Setup.isGenerateCsvSwitchListEnabled()));
489        resetButton.setEnabled(!enable);
490        runButton.setEnabled(!enable);
491        openFileButton.setEnabled(!enable);
492        // disable the following, and turn then back on if needed
493        printChangesButton.setEnabled(false);
494        runChangeButton.setEnabled(false);
495        updateButton.setEnabled(false);
496        if (!enable) {
497            enableChangeButtons();
498        }
499    }
500
501    private void enableChangeButtons() {
502        printChangesButton.setEnabled(false);
503        runChangeButton.setEnabled(false);
504        updateButton.setEnabled(false);
505        for (Location location : locationManager.getLocationsByNameList()) {
506            if (location.getStatus().equals(Location.MODIFIED) && location.isSwitchListEnabled()) {
507                printChangesButton
508                        .setEnabled((!Control.disablePrintingIfCustom || !Setup.isGenerateCsvSwitchListEnabled()));
509                runChangeButton.setEnabled(true);
510                updateButton.setEnabled(true);
511            }
512        }
513    }
514
515    // The print switch list for a location has changed
516    private void changeLocationCheckboxes(PropertyChangeEvent e) {
517        Location l = (Location) e.getSource();
518        for (JCheckBox checkbox : new ArrayList<>(locationCheckBoxes)) {
519            if (checkbox.getName().equals(l.getName())) {
520                checkbox.setSelected(l.isSwitchListEnabled());
521                break;
522            }
523        }
524    }
525
526    private void addLocationCheckBoxAction(JCheckBox b) {
527        b.addActionListener(new java.awt.event.ActionListener() {
528            @Override
529            public void actionPerformed(ActionEvent e) {
530                locationCheckBoxActionPerformed(e);
531            }
532        });
533    }
534
535    public void locationCheckBoxActionPerformed(ActionEvent ae) {
536        JCheckBox b = (JCheckBox) ae.getSource();
537        log.debug("checkbox change {}", b.getName());
538        Location l = locationManager.getLocationByName(b.getName());
539        l.setSwitchListEnabled(b.isSelected());
540        // enable the save button whenever a checkbox is changed
541        saveButton.setEnabled(true);
542    }
543
544    private void addCommentButtonAction(JButton b) {
545        b.addActionListener(new java.awt.event.ActionListener() {
546            @Override
547            public void actionPerformed(java.awt.event.ActionEvent e) {
548                commentButtonActionPerformed(e);
549            }
550        });
551    }
552
553    public void commentButtonActionPerformed(ActionEvent ae) {
554        JButton b = (JButton) ae.getSource();
555        log.debug("button action {}", b.getName());
556        Location l = locationManager.getLocationByName(b.getName());
557        new TrainSwitchListCommentFrame(l);
558    }
559
560    @Override
561    protected void comboBoxActionPerformed(ActionEvent ae) {
562        log.debug("combo box action");
563        enableSaveButton(true);
564    }
565
566    @Override
567    public void dispose() {
568        locationManager.removePropertyChangeListener(this);
569        Setup.getDefault().removePropertyChangeListener(this);
570        for (Location location : locationManager.getLocationsByNameList()) {
571            location.removePropertyChangeListener(this);
572        }
573        super.dispose();
574    }
575
576    @Override
577    public void propertyChange(PropertyChangeEvent e) {
578        if (Control.SHOW_PROPERTY) {
579            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(),
580                    e.getNewValue());
581        }
582        if (e.getPropertyName().equals(Location.SWITCHLIST_CHANGED_PROPERTY)) {
583            changeLocationCheckboxes(e);
584            enableChangeButtons();
585        }
586        if (e.getPropertyName().equals(LocationManager.LISTLENGTH_CHANGED_PROPERTY) ||
587                e.getPropertyName().equals(Location.NAME_CHANGED_PROPERTY) ||
588                e.getPropertyName().equals(Location.STATUS_CHANGED_PROPERTY) ||
589                e.getPropertyName().equals(Location.SWITCHLIST_COMMENT_CHANGED_PROPERTY)) {
590            updateLocationCheckboxes();
591            enableChangeButtons();
592        }
593        if (e.getPropertyName().equals(Setup.SWITCH_LIST_CSV_PROPERTY_CHANGE)) {
594            enableSaveButton(false);
595            customPanel.setVisible(Setup.isGenerateCsvSwitchListEnabled());
596        }
597    }
598
599    public static class TrainSwitchListCommentFrame extends OperationsFrame {
600
601        // text area
602        JTextArea commentTextArea = new JTextArea(10, 90);
603        JScrollPane commentScroller = new JScrollPane(commentTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
604                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
605        Dimension minScrollerDim = new Dimension(1200, 500);
606
607        // text color chooser
608        JColorChooser commentColorChooser = new JColorChooser();
609
610        JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
611        JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel"));
612
613        Location _location;
614
615        private TrainSwitchListCommentFrame(Location location) {
616            super();
617            initComponents(location);
618        }
619
620        private void initComponents(Location location) {
621            _location = location;
622            // the following code sets the frame's initial state
623            getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
624
625            JPanel pC = new JPanel();
626            pC.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Comment")));
627            pC.setLayout(new GridBagLayout());
628            commentScroller.setMinimumSize(minScrollerDim);
629            addItem(pC, commentScroller, 1, 0);
630            addItem(pC, OperationsPanel.getColorChooserPanel(location.getSwitchListCommentWithColor(), commentColorChooser), 2, 0);
631            JScrollPane panelPane = new JScrollPane(pC);
632
633            commentTextArea.setText(TrainCommon.getTextColorString(location.getSwitchListCommentWithColor()));
634
635            JPanel pB = new JPanel();
636            pB.setLayout(new GridBagLayout());
637            addItem(pB, cancelButton, 0, 0);
638            addItem(pB, saveButton, 1, 0);
639
640            getContentPane().add(panelPane);
641            getContentPane().add(pB);
642
643            addButtonAction(saveButton);
644            addButtonAction(cancelButton);
645
646            setTitle(location.getName());
647            initMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight200));
648        }
649
650        // Buttons
651        @Override
652        public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
653            if (ae.getSource() == saveButton) {
654                _location.setSwitchListComment(
655                        TrainCommon.formatColorString(commentTextArea.getText(), commentColorChooser.getColor()));
656                // save location file
657                OperationsXml.save();
658                if (Setup.isCloseWindowOnSaveEnabled()) {
659                    super.dispose();
660                }
661            }
662            if (ae.getSource() == cancelButton) {
663                super.dispose();
664            }
665        }
666    }
667
668    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrainSwitchListEditFrame.class);
669}