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