001package jmri.jmrit.operations.setup;
002
003import java.awt.GridBagLayout;
004import java.beans.PropertyChangeListener;
005import java.io.IOException;
006import java.util.List;
007
008import javax.swing.*;
009
010import jmri.InstanceManager;
011import jmri.jmrit.display.LocoIcon;
012import jmri.jmrit.operations.OperationsXml;
013import jmri.jmrit.operations.rollingstock.cars.CarTypes;
014import jmri.jmrit.operations.routes.*;
015import jmri.util.swing.*;
016import jmri.web.server.WebServerPreferences;
017
018/**
019 * Frame for user edit of operation parameters
020 *
021 * @author Dan Boudreau Copyright (C) 2008, 2010, 2011, 2012
022 */
023public class OperationsSettingsPanel extends OperationsPreferencesPanel implements PropertyChangeListener {
024
025    // labels
026    private final JLabel textIconNorth = new JLabel(Bundle.getMessage("IconNorth"));
027    private final JLabel textIconSouth = new JLabel(Bundle.getMessage("IconSouth"));
028    private final JLabel textIconEast = new JLabel(Bundle.getMessage("IconEast"));
029    private final JLabel textIconWest = new JLabel(Bundle.getMessage("IconWest"));
030    private final JLabel textIconLocal = new JLabel(Bundle.getMessage("IconLocal"));
031    private final JLabel textIconTerminate = new JLabel(Bundle.getMessage("IconTerminate"));
032
033    // major buttons
034    private final JButton backupButton = new JButton(Bundle.getMessage("Backup"));
035    private final JButton restoreButton = new JButton(Bundle.getMessage("Restore"));
036    private final JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
037
038    // radio buttons
039    private final JRadioButton scaleZ = new JRadioButton("Z"); // NOI18N
040    private final JRadioButton scaleN = new JRadioButton("N"); // NOI18N
041    private final JRadioButton scaleTT = new JRadioButton("TT"); // NOI18N
042    private final JRadioButton scaleHOn3 = new JRadioButton("HOn3"); // NOI18N
043    private final JRadioButton scaleOO = new JRadioButton("OO"); // NOI18N
044    private final JRadioButton scaleHO = new JRadioButton("HO"); // NOI18N
045    private final JRadioButton scaleSn3 = new JRadioButton("Sn3"); // NOI18N
046    private final JRadioButton scaleS = new JRadioButton("S"); // NOI18N
047    private final JRadioButton scaleOn3 = new JRadioButton("On3"); // NOI18N
048    private final JRadioButton scaleO = new JRadioButton("O"); // NOI18N
049    private final JRadioButton scaleG = new JRadioButton("G"); // NOI18N
050
051    private final JRadioButton typeDesc = new JRadioButton(Bundle.getMessage("Descriptive"));
052    private final JRadioButton typeAAR = new JRadioButton(Bundle.getMessage("AAR"));
053
054    private final JRadioButton feetUnit = new JRadioButton(Bundle.getMessage("Feet"));
055    private final JRadioButton meterUnit = new JRadioButton(Bundle.getMessage("Meter"));
056
057    // check boxes
058    final JCheckBox eastCheckBox = new JCheckBox(Bundle.getMessage("eastwest"));
059    final JCheckBox northCheckBox = new JCheckBox(Bundle.getMessage("northsouth"));
060    private final JCheckBox mainMenuCheckBox = new JCheckBox(Bundle.getMessage("MainMenu"));
061    private final JCheckBox closeOnSaveCheckBox = new JCheckBox(Bundle.getMessage("CloseOnSave"));
062    private final JCheckBox autoSaveCheckBox = new JCheckBox(Bundle.getMessage("AutoSave"));
063    private final JCheckBox autoBackupCheckBox = new JCheckBox(Bundle.getMessage("AutoBackup"));
064    private final JCheckBox iconCheckBox = new JCheckBox(Bundle.getMessage("trainIcon"));
065    private final JCheckBox appendCheckBox = new JCheckBox(Bundle.getMessage("trainIconAppend"));
066
067    // text field
068    JTextField panelTextField = new JTextField(30);
069    JTextField railroadNameTextField = new JTextField(35);
070    JTextField maxLengthTextField = new JTextField(5);
071    JTextField maxEngineSizeTextField = new JTextField(3);
072    JTextField hptTextField = new JTextField(3);
073    JTextField switchTimeTextField = new JTextField(3);
074    JTextField travelTimeTextField = new JTextField(3);
075    JTextField yearTextField = new JTextField(4);
076
077    // combo boxes
078    private final JComboBox<String> northComboBox = new JComboBox<>();
079    private final JComboBox<String> southComboBox = new JComboBox<>();
080    private final JComboBox<String> eastComboBox = new JComboBox<>();
081    private final JComboBox<String> westComboBox = new JComboBox<>();
082    private final JComboBox<String> localComboBox = new JComboBox<>();
083    private final JComboBox<String> terminateComboBox = new JComboBox<>();
084
085    // text area
086    private final JTextArea commentTextArea = new JTextArea(2, 80);
087
088    public OperationsSettingsPanel() {
089        super();
090
091        // the following code sets the frame's initial state
092        // create manager to load operation settings
093        InstanceManager.getDefault(OperationsSetupXml.class);
094
095        // load fields
096        maxLengthTextField.setText(Integer.toString(Setup.getMaxTrainLength()));
097        maxEngineSizeTextField.setText(Integer.toString(Setup.getMaxNumberEngines()));
098        hptTextField.setText(Integer.toString(Setup.getHorsePowerPerTon()));
099        switchTimeTextField.setText(Integer.toString(Setup.getSwitchTime()));
100        travelTimeTextField.setText(Integer.toString(Setup.getTravelTime()));
101        panelTextField.setText(Setup.getPanelName());
102        yearTextField.setText(Setup.getYearModeled());
103        commentTextArea.setText(Setup.getComment());
104
105        // load checkboxes
106        mainMenuCheckBox.setSelected(Setup.isMainMenuEnabled());
107        closeOnSaveCheckBox.setSelected(Setup.isCloseWindowOnSaveEnabled());
108        autoSaveCheckBox.setSelected(Setup.isAutoSaveEnabled());
109        autoBackupCheckBox.setSelected(Setup.isAutoBackupEnabled());
110        iconCheckBox.setSelected(Setup.isTrainIconCordEnabled());
111        appendCheckBox.setSelected(Setup.isTrainIconAppendEnabled());
112
113        // add tool tips
114        backupButton.setToolTipText(Bundle.getMessage("BackupToolTip"));
115        restoreButton.setToolTipText(Bundle.getMessage("RestoreToolTip"));
116        saveButton.setToolTipText(Bundle.getMessage("SaveToolTip"));
117        panelTextField.setToolTipText(Bundle.getMessage("EnterPanelName"));
118        yearTextField.setToolTipText(Bundle.getMessage("EnterYearModeled"));
119        autoSaveCheckBox.setToolTipText(Bundle.getMessage("AutoSaveTip"));
120        autoBackupCheckBox.setToolTipText(Bundle.getMessage("AutoBackUpTip"));
121        maxLengthTextField.setToolTipText(Bundle.getMessage("MaxLengthTip"));
122        maxEngineSizeTextField.setToolTipText(Bundle.getMessage("MaxEngineTip"));
123        hptTextField.setToolTipText(Bundle.getMessage("HPperTonTip"));
124        switchTimeTextField.setToolTipText(Bundle.getMessage("SwitchTimeTip"));
125        travelTimeTextField.setToolTipText(Bundle.getMessage("TravelTimeTip"));
126        railroadNameTextField.setToolTipText(Bundle.getMessage("RailroadNameTip"));
127        commentTextArea.setToolTipText(Bundle.getMessage("CommentTip"));
128
129        // Layout the panel by rows
130        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
131        JPanel panel = new JPanel();
132        JScrollPane panelPane = new JScrollPane(panel);
133        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
134        panelPane.setBorder(BorderFactory.createTitledBorder(""));
135
136        // row 1a
137        JPanel p1 = new JPanel();
138        p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
139
140        JPanel pRailroadName = new JPanel();
141        pRailroadName.setLayout(new GridBagLayout());
142        pRailroadName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("RailroadName")));
143        addItem(pRailroadName, railroadNameTextField, 0, 0);
144        p1.add(pRailroadName);
145
146        // row 1b
147        JPanel pTrainDir = new JPanel();
148        pTrainDir.setLayout(new GridBagLayout());
149        pTrainDir.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("direction")));
150        addItemLeft(pTrainDir, northCheckBox, 1, 2);
151        addItemLeft(pTrainDir, eastCheckBox, 2, 2);
152        p1.add(pTrainDir);
153
154        setDirectionCheckBox(Setup.getTrainDirection());
155
156        // row 3a
157        JPanel p3 = new JPanel();
158        p3.setLayout(new BoxLayout(p3, BoxLayout.X_AXIS));
159
160        JPanel pTrainLength = new JPanel();
161        pTrainLength.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("MaxLength")));
162        addItem(pTrainLength, maxLengthTextField, 0, 0);
163        p3.add(pTrainLength);
164
165        // row 3b
166        JPanel pMaxEngine = new JPanel();
167        pMaxEngine.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("MaxEngine")));
168        addItem(pMaxEngine, maxEngineSizeTextField, 0, 0);
169        p3.add(pMaxEngine);
170
171        // row 3c
172        JPanel pHPT = new JPanel();
173        pHPT.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("HPT")));
174        addItem(pHPT, hptTextField, 0, 0);
175        p3.add(pHPT);
176
177        JPanel pSwitchTime = new JPanel();
178        pSwitchTime.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("MoveTime")));
179        addItem(pSwitchTime, switchTimeTextField, 0, 0);
180        p3.add(pSwitchTime);
181
182        // row 3d
183        JPanel pTravelTime = new JPanel();
184        pTravelTime.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TravelTime")));
185        addItem(pTravelTime, travelTimeTextField, 0, 0);
186        p3.add(pTravelTime);
187
188        // row 2
189        JPanel pScale = new JPanel();
190        pScale.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Scale")));
191
192        ButtonGroup scaleGroup = new ButtonGroup();
193        scaleGroup.add(scaleZ);
194        scaleGroup.add(scaleN);
195        scaleGroup.add(scaleTT);
196        scaleGroup.add(scaleHOn3);
197        scaleGroup.add(scaleOO);
198        scaleGroup.add(scaleHO);
199        scaleGroup.add(scaleSn3);
200        scaleGroup.add(scaleS);
201        scaleGroup.add(scaleOn3);
202        scaleGroup.add(scaleO);
203        scaleGroup.add(scaleG);
204
205        pScale.add(scaleZ);
206        pScale.add(scaleN);
207        pScale.add(scaleTT);
208        pScale.add(scaleHOn3);
209        pScale.add(scaleOO);
210        pScale.add(scaleHO);
211        pScale.add(scaleSn3);
212        pScale.add(scaleS);
213        pScale.add(scaleOn3);
214        pScale.add(scaleO);
215        pScale.add(scaleG);
216        setScale();
217
218        // row 4a
219        JPanel p9 = new JPanel();
220        p9.setLayout(new BoxLayout(p9, BoxLayout.X_AXIS));
221
222        JPanel pCarTypeButtons = new JPanel();
223        pCarTypeButtons.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("CarTypes")));
224        ButtonGroup carTypeGroup = new ButtonGroup();
225        carTypeGroup.add(typeDesc);
226        carTypeGroup.add(typeAAR);
227        pCarTypeButtons.add(typeDesc);
228        pCarTypeButtons.add(typeAAR);
229        p9.add(pCarTypeButtons);
230        setCarTypes();
231
232        // row 4b
233        JPanel pLengthUnit = new JPanel();
234        pLengthUnit.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutLength")));
235        ButtonGroup lengthUnitGroup = new ButtonGroup();
236        lengthUnitGroup.add(feetUnit);
237        lengthUnitGroup.add(meterUnit);
238        pLengthUnit.add(feetUnit);
239        pLengthUnit.add(meterUnit);
240        p9.add(pLengthUnit);
241        setLengthUnit();
242
243        // row 4c
244        JPanel pYearModeled = new JPanel();
245        pYearModeled.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutYearModeled")));
246        pYearModeled.add(yearTextField);
247
248        p9.add(pYearModeled);
249
250        // Option panel
251        JPanel options = new JPanel();
252        options.setLayout(new GridBagLayout());
253        options.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutOptions")));
254        addItem(options, mainMenuCheckBox, 0, 0);
255        addItem(options, closeOnSaveCheckBox, 1, 0);
256        addItem(options, autoSaveCheckBox, 2, 0);
257        addItem(options, autoBackupCheckBox, 3, 0);
258
259        // p9.add(options);
260        // 1st scroll panel
261        panel.add(p1);
262        panel.add(pScale);
263        panel.add(p3);
264        panel.add(p9);
265
266        // Icon panel
267        JPanel pIcon = new JPanel();
268        pIcon.setLayout(new BoxLayout(pIcon, BoxLayout.Y_AXIS));
269        JScrollPane pIconPane = new JScrollPane(pIcon);
270        pIconPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutPanelOptions")));
271
272        // row 1 Icon panel
273        JPanel p1Icon = new JPanel();
274        p1Icon.setLayout(new BoxLayout(p1Icon, BoxLayout.X_AXIS));
275
276        JPanel pPanelName = new JPanel();
277        pPanelName.setLayout(new GridBagLayout());
278        pPanelName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutPanelName")));
279        addItem(pPanelName, panelTextField, 0, 0);
280        p1Icon.add(pPanelName);
281
282        JPanel pIconControl = new JPanel();
283        pIconControl.setLayout(new GridBagLayout());
284        pIconControl.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutIconOptions")));
285        addItem(pIconControl, appendCheckBox, 0, 0);
286        addItem(pIconControl, iconCheckBox, 1, 0);
287        p1Icon.add(pIconControl);
288
289        pIcon.add(p1Icon);
290
291        JPanel pIconColors = new JPanel();
292        pIconColors.setLayout(new GridBagLayout());
293        pIconColors.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutIconColors")));
294
295        textIconNorth.setLabelFor(northComboBox);
296        addItem(pIconColors, textIconNorth, 0, 4);
297        addItemLeft(pIconColors, northComboBox, 1, 4);
298        textIconSouth.setLabelFor(southComboBox);
299        addItem(pIconColors, textIconSouth, 0, 5);
300        addItemLeft(pIconColors, southComboBox, 1, 5);
301        textIconEast.setLabelFor(eastComboBox);
302        addItem(pIconColors, textIconEast, 0, 8);
303        addItemLeft(pIconColors, eastComboBox, 1, 8);
304        textIconWest.setLabelFor(westComboBox);
305        addItem(pIconColors, textIconWest, 0, 9);
306        addItemLeft(pIconColors, westComboBox, 1, 9);
307        textIconLocal.setLabelFor(localComboBox);
308        addItem(pIconColors, textIconLocal, 0, 10);
309        addItemLeft(pIconColors, localComboBox, 1, 10);
310        textIconTerminate.setLabelFor(terminateComboBox);
311        addItem(pIconColors, textIconTerminate, 0, 11);
312        addItemLeft(pIconColors, terminateComboBox, 1, 11);
313
314        pIcon.add(pIconColors);
315
316        loadIconComboBox(northComboBox);
317        loadIconComboBox(southComboBox);
318        loadIconComboBox(eastComboBox);
319        loadIconComboBox(westComboBox);
320        loadIconComboBox(localComboBox);
321        loadIconComboBox(terminateComboBox);
322        northComboBox.setSelectedItem(Setup.getTrainIconColorNorth());
323        southComboBox.setSelectedItem(Setup.getTrainIconColorSouth());
324        eastComboBox.setSelectedItem(Setup.getTrainIconColorEast());
325        westComboBox.setSelectedItem(Setup.getTrainIconColorWest());
326        localComboBox.setSelectedItem(Setup.getTrainIconColorLocal());
327        terminateComboBox.setSelectedItem(Setup.getTrainIconColorTerminate());
328
329        // comment
330        JPanel pC = new JPanel();
331        pC.setLayout(new GridBagLayout());
332        pC.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Comment")));
333        JScrollPane commentScroller = new JScrollPane(commentTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
334                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
335        addItem(pC, commentScroller, 0, 0);
336
337        pIcon.add(pC);
338
339        // row 15
340        JPanel pControl = new JPanel();
341        pControl.setLayout(new GridBagLayout());
342        addItem(pControl, restoreButton, 0, 9);
343        addItem(pControl, backupButton, 1, 9);
344        addItem(pControl, saveButton, 3, 9);
345
346        add(panelPane);
347        add(options);
348        add(pIconPane);
349        add(pControl);
350
351        // set up buttons
352        addButtonAction(backupButton);
353        addButtonAction(restoreButton);
354        addButtonAction(saveButton);
355        addCheckBoxAction(eastCheckBox);
356        addCheckBoxAction(northCheckBox);
357
358        // now provide the railroad name
359        railroadNameTextField.setText(Setup.getRailroadName());
360    }
361
362    // Save, Delete, Add buttons
363    @Override
364    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
365        if (ae.getSource() == backupButton) {
366            // Backup and Restore dialogs are now modal. so no need to check for an existing
367            // instance
368            BackupDialog bd = new BackupDialog();
369            bd.pack();
370            bd.setLocationRelativeTo(null);
371            bd.setVisible(true);
372        }
373        if (ae.getSource() == restoreButton) {
374            RestoreDialog rd = new RestoreDialog();
375            rd.pack();
376            rd.setLocationRelativeTo(null);
377            rd.setVisible(true);
378        }
379        if (ae.getSource() == saveButton) {
380            save();
381        }
382    }
383
384    private void save() {
385        // check input fields
386        int maxTrainLength;
387        try {
388            maxTrainLength = Integer.parseInt(maxLengthTextField.getText());
389        } catch (NumberFormatException e) {
390            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MaxLength"), Bundle.getMessage("CanNotAcceptNumber"),
391                    JmriJOptionPane.ERROR_MESSAGE);
392            return;
393        }
394        // warn about train length being too short
395        if (maxTrainLength != Setup.getMaxTrainLength()) {
396            if (maxTrainLength < 500 && Setup.getLengthUnit().equals(Setup.FEET) ||
397                    maxTrainLength < 160 && Setup.getLengthUnit().equals(Setup.METER)) {
398                JmriJOptionPane.showMessageDialog(this,
399                        Bundle.getMessage("LimitTrainLength",
400                                maxTrainLength, Setup.getLengthUnit().toLowerCase()),
401                        Bundle.getMessage("WarningTooShort"), JmriJOptionPane.WARNING_MESSAGE);
402            }
403        }
404
405        try {
406            Integer.parseInt(maxEngineSizeTextField.getText());
407        } catch (NumberFormatException e) {
408            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MaxEngine"), Bundle.getMessage("CanNotAcceptNumber"),
409                    JmriJOptionPane.ERROR_MESSAGE);
410            return;
411        }
412
413        try {
414            Integer.parseInt(hptTextField.getText());
415        } catch (NumberFormatException e) {
416            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("HPT"), Bundle.getMessage("CanNotAcceptNumber"),
417                    JmriJOptionPane.ERROR_MESSAGE);
418            return;
419        }
420
421        try {
422            Integer.parseInt(switchTimeTextField.getText());
423        } catch (NumberFormatException e) {
424            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MoveTime"), Bundle.getMessage("CanNotAcceptNumber"),
425                    JmriJOptionPane.ERROR_MESSAGE);
426            return;
427        }
428
429        try {
430            Integer.parseInt(travelTimeTextField.getText());
431        } catch (NumberFormatException e) {
432            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TravelTime"),
433                    Bundle.getMessage("CanNotAcceptNumber"), JmriJOptionPane.ERROR_MESSAGE);
434            return;
435        }
436
437        try {
438            if (!yearTextField.getText().trim().isEmpty()) {
439                Integer.parseInt(yearTextField.getText().trim());
440            }
441        } catch (NumberFormatException e) {
442            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("BorderLayoutYearModeled"),
443                    Bundle.getMessage("CanNotAcceptNumber"), JmriJOptionPane.ERROR_MESSAGE);
444            return;
445        }
446
447        // if max train length has changed, check routes
448        checkRoutes();
449
450        // set car types
451        if (typeDesc.isSelected() && !Setup.getCarTypes().equals(Setup.DESCRIPTIVE) ||
452                typeAAR.isSelected() && !Setup.getCarTypes().equals(Setup.AAR)) {
453
454            // backup files before changing car type descriptions
455            AutoBackup backup = new AutoBackup();
456            try {
457                backup.autoBackup();
458            } catch (IOException ex) {
459                UnexpectedExceptionContext context = new UnexpectedExceptionContext(ex,
460                        "Auto backup before changing Car types"); // NOI18N
461                ExceptionDisplayFrame.displayExceptionDisplayFrame(this, context);
462            }
463
464            if (typeDesc.isSelected()) {
465                InstanceManager.getDefault(CarTypes.class).changeDefaultNames(Setup.DESCRIPTIVE);
466                Setup.setCarTypes(Setup.DESCRIPTIVE);
467            } else {
468                InstanceManager.getDefault(CarTypes.class).changeDefaultNames(Setup.AAR);
469                Setup.setCarTypes(Setup.AAR);
470            }
471
472            // save all the modified files
473            OperationsXml.save();
474        }
475        // main menu enabled?
476        Setup.setMainMenuEnabled(mainMenuCheckBox.isSelected());
477        Setup.setCloseWindowOnSaveEnabled(closeOnSaveCheckBox.isSelected());
478        Setup.setAutoSaveEnabled(autoSaveCheckBox.isSelected());
479        Setup.setAutoBackupEnabled(autoBackupCheckBox.isSelected());
480
481        // add panel name to setup
482        Setup.setPanelName(panelTextField.getText());
483
484        // train Icon X&Y
485        Setup.setTrainIconCordEnabled(iconCheckBox.isSelected());
486        Setup.setTrainIconAppendEnabled(appendCheckBox.isSelected());
487
488        // save train icon colors
489        Setup.setTrainIconColorNorth((String) northComboBox.getSelectedItem());
490        Setup.setTrainIconColorSouth((String) southComboBox.getSelectedItem());
491        Setup.setTrainIconColorEast((String) eastComboBox.getSelectedItem());
492        Setup.setTrainIconColorWest((String) westComboBox.getSelectedItem());
493        Setup.setTrainIconColorLocal((String) localComboBox.getSelectedItem());
494        Setup.setTrainIconColorTerminate((String) terminateComboBox.getSelectedItem());
495        // set train direction
496        int direction = 0;
497        if (eastCheckBox.isSelected()) {
498            direction = Setup.EAST + Setup.WEST;
499        }
500        if (northCheckBox.isSelected()) {
501            direction += Setup.NORTH + Setup.SOUTH;
502        }
503        Setup.setTrainDirection(direction);
504        Setup.setMaxNumberEngines(Integer.parseInt(maxEngineSizeTextField.getText()));
505        Setup.setHorsePowerPerTon(Integer.parseInt(hptTextField.getText()));
506        // set switch time
507        Setup.setSwitchTime(Integer.parseInt(switchTimeTextField.getText()));
508        // set travel time
509        Setup.setTravelTime(Integer.parseInt(travelTimeTextField.getText()));
510        // set scale
511        Setup.setScale(getSelectedScale());
512
513        if (!railroadNameTextField.getText()
514                .equals(InstanceManager.getDefault(WebServerPreferences.class).getRailroadName())) {
515            Setup.setRailroadName(railroadNameTextField.getText());
516            int results = JmriJOptionPane.showConfirmDialog(this,
517                    Bundle.getMessage("ChangeRailroadName",
518                            InstanceManager.getDefault(WebServerPreferences.class).getRailroadName(),
519                                    Setup.getRailroadName()),
520                    Bundle.getMessage("ChangeJMRIRailroadName"), JmriJOptionPane.YES_NO_OPTION);
521            if (results == JmriJOptionPane.YES_OPTION) {
522                InstanceManager.getDefault(WebServerPreferences.class).setRailroadName(Setup.getRailroadName());
523                InstanceManager.getDefault(WebServerPreferences.class).save();
524            }
525        }
526        // Set Unit of Length
527        if (feetUnit.isSelected()) {
528            Setup.setLengthUnit(Setup.FEET);
529        }
530        if (meterUnit.isSelected()) {
531            Setup.setLengthUnit(Setup.METER);
532        }
533        Setup.setYearModeled(yearTextField.getText().trim());
534        // set max train length
535        Setup.setMaxTrainLength(Integer.parseInt(maxLengthTextField.getText()));
536        Setup.setComment(commentTextArea.getText());
537
538        InstanceManager.getDefault(OperationsSetupXml.class).writeOperationsFile();
539        var topLevelAncestor = getTopLevelAncestor();
540        if (Setup.isCloseWindowOnSaveEnabled() && topLevelAncestor instanceof OperationsSettingsFrame) {
541            ((OperationsSettingsFrame) topLevelAncestor).dispose();
542        }
543    }
544
545    // if max train length has changed, check routes
546    private void checkRoutes() {
547        int maxLength = Integer.parseInt(maxLengthTextField.getText());
548        if (maxLength > Setup.getMaxTrainLength()) {
549            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("RouteLengthNotModified"),
550                    Bundle.getMessage("MaxTrainLengthIncreased",
551                            maxLength, Setup.getLengthUnit().toLowerCase()),
552                    JmriJOptionPane.INFORMATION_MESSAGE);
553        }
554        if (maxLength < Setup.getMaxTrainLength()) {
555            StringBuilder sb = new StringBuilder();
556            List<Route> routes = InstanceManager.getDefault(RouteManager.class).getRoutesByNameList();
557            int count = 0;
558            for (Route route : routes) {
559                for (RouteLocation rl : route.getLocationsBySequenceList()) {
560                    if (rl.getMaxTrainLength() > maxLength) {
561                        String s = Bundle.getMessage("RouteMaxLengthExceeds",
562                                route.getName(), rl.getName(), rl.getMaxTrainLength(), maxLength);
563                        log.info(s);
564                        sb.append(s).append(NEW_LINE);
565                        count++;
566                        break;
567                    }
568                }
569                // maximum of 20 route warnings
570                if (count > 20) {
571                    sb.append(Bundle.getMessage("More")).append(NEW_LINE);
572                    break;
573                }
574            }
575            if (sb.length() > 0) {
576                JmriJOptionPane.showMessageDialog(this, sb.toString(), Bundle.getMessage("YouNeedToAdjustRoutes"),
577                        JmriJOptionPane.WARNING_MESSAGE);
578                if (JmriJOptionPane.showConfirmDialog(this,
579                        Bundle.getMessage("ChangeMaximumTrainDepartureLength",
580                                maxLength),
581                        Bundle.getMessage("ModifyAllRoutes"), JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) {
582                    routes.stream().forEach((route) -> {
583                        route.getLocationsBySequenceList().stream().filter((rl) -> (rl.getMaxTrainLength() > maxLength))
584                                .map((rl) -> {
585                                    log.debug("Setting route ({}) routeLocation ({}) max traim length to {}",
586                                            route.getName(), rl.getName(), maxLength); // NOI18N
587                                    return rl;
588                                }).forEach((rl) -> {
589                                    rl.setMaxTrainLength(maxLength);
590                                });
591                    });
592                    // save the route changes
593                    InstanceManager.getDefault(RouteManagerXml.class).writeOperationsFile();
594                }
595            }
596        }
597    }
598
599    @Override
600    public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
601        if (ae.getSource() == northCheckBox) {
602            if (!northCheckBox.isSelected()) {
603                eastCheckBox.setSelected(true);
604            }
605        }
606        if (ae.getSource() == eastCheckBox) {
607            if (!eastCheckBox.isSelected()) {
608                northCheckBox.setSelected(true);
609            }
610        }
611        int direction = 0;
612        if (eastCheckBox.isSelected()) {
613            direction += Setup.EAST;
614        }
615        if (northCheckBox.isSelected()) {
616            direction += Setup.NORTH;
617        }
618        setDirectionCheckBox(direction);
619    }
620
621    private void setScale() {
622        switch (Setup.getScale()) {
623            case Setup.Z_SCALE:
624                scaleZ.setSelected(true);
625                break;
626            case Setup.N_SCALE:
627                scaleN.setSelected(true);
628                break;
629            case Setup.TT_SCALE:
630                scaleTT.setSelected(true);
631                break;
632            case Setup.HOn3_SCALE:
633                scaleHOn3.setSelected(true);
634                break;
635            case Setup.OO_SCALE:
636                scaleOO.setSelected(true);
637                break;
638            case Setup.HO_SCALE:
639                scaleHO.setSelected(true);
640                break;
641            case Setup.Sn3_SCALE:
642                scaleSn3.setSelected(true);
643                break;
644            case Setup.S_SCALE:
645                scaleS.setSelected(true);
646                break;
647            case Setup.On3_SCALE:
648                scaleOn3.setSelected(true);
649                break;
650            case Setup.O_SCALE:
651                scaleO.setSelected(true);
652                break;
653            case Setup.G_SCALE:
654                scaleG.setSelected(true);
655                break;
656            default:
657                log.error("Unknown scale");
658        }
659    }
660
661    private int getSelectedScale() {
662        int scale = 0;
663        if (scaleZ.isSelected()) {
664            scale = Setup.Z_SCALE;
665        }
666        if (scaleN.isSelected()) {
667            scale = Setup.N_SCALE;
668        }
669        if (scaleTT.isSelected()) {
670            scale = Setup.TT_SCALE;
671        }
672        if (scaleOO.isSelected()) {
673            scale = Setup.OO_SCALE;
674        }
675        if (scaleHOn3.isSelected()) {
676            scale = Setup.HOn3_SCALE;
677        }
678        if (scaleHO.isSelected()) {
679            scale = Setup.HO_SCALE;
680        }
681        if (scaleSn3.isSelected()) {
682            scale = Setup.Sn3_SCALE;
683        }
684        if (scaleS.isSelected()) {
685            scale = Setup.S_SCALE;
686        }
687        if (scaleOn3.isSelected()) {
688            scale = Setup.On3_SCALE;
689        }
690        if (scaleO.isSelected()) {
691            scale = Setup.O_SCALE;
692        }
693        if (scaleG.isSelected()) {
694            scale = Setup.G_SCALE;
695        }
696        return scale;
697    }
698
699    private void setCarTypes() {
700        typeDesc.setSelected(Setup.getCarTypes().equals(Setup.DESCRIPTIVE));
701        typeAAR.setSelected(Setup.getCarTypes().equals(Setup.AAR));
702    }
703
704    private void setDirectionCheckBox(int direction) {
705        eastCheckBox.setSelected((direction & Setup.EAST) == Setup.EAST);
706        textIconEast.setVisible((direction & Setup.EAST) == Setup.EAST);
707        eastComboBox.setVisible((direction & Setup.EAST) == Setup.EAST);
708        textIconWest.setVisible((direction & Setup.EAST) == Setup.EAST);
709        westComboBox.setVisible((direction & Setup.EAST) == Setup.EAST);
710        northCheckBox.setSelected((direction & Setup.NORTH) == Setup.NORTH);
711        textIconNorth.setVisible((direction & Setup.NORTH) == Setup.NORTH);
712        northComboBox.setVisible((direction & Setup.NORTH) == Setup.NORTH);
713        textIconSouth.setVisible((direction & Setup.NORTH) == Setup.NORTH);
714        southComboBox.setVisible((direction & Setup.NORTH) == Setup.NORTH);
715    }
716
717    private void setLengthUnit() {
718        feetUnit.setSelected(Setup.getLengthUnit().equals(Setup.FEET));
719        meterUnit.setSelected(Setup.getLengthUnit().equals(Setup.METER));
720    }
721
722    private void loadIconComboBox(JComboBox<String> comboBox) {
723        for (String color : LocoIcon.getLocoColors()) {
724            comboBox.addItem(color);
725        }
726    }
727
728    @Override
729    public void propertyChange(java.beans.PropertyChangeEvent e) {
730        log.debug("propertyChange ({}), new: ({})", e.getPropertyName(), e.getNewValue());
731    }
732
733    @Override
734    public String getTabbedPreferencesTitle() {
735        return Bundle.getMessage("TitleOperationsSetup");
736    }
737
738    @Override
739    public String getPreferencesTooltip() {
740        return null;
741    }
742
743    @Override
744    public void savePreferences() {
745        this.save();
746    }
747
748    @Override
749    public boolean isDirty() {
750        if (// set car types
751        (typeDesc.isSelected() && !Setup.getCarTypes().equals(Setup.DESCRIPTIVE)) ||
752                (typeAAR.isSelected() && !Setup.getCarTypes().equals(Setup.AAR))
753                // main menu enabled?
754                ||
755                Setup.isMainMenuEnabled() != mainMenuCheckBox.isSelected() ||
756                Setup.isCloseWindowOnSaveEnabled() != closeOnSaveCheckBox.isSelected() ||
757                Setup.isAutoSaveEnabled() != autoSaveCheckBox.isSelected() ||
758                Setup.isAutoBackupEnabled() != autoBackupCheckBox.isSelected()
759                // add panel name to setup
760                ||
761                !Setup.getPanelName().equals(panelTextField.getText())
762                // train Icon X&Y
763                ||
764                Setup.isTrainIconCordEnabled() != iconCheckBox.isSelected() ||
765                Setup.isTrainIconAppendEnabled() != appendCheckBox.isSelected()
766                // train Icon X&Y
767                ||
768                Setup.isTrainIconCordEnabled() != iconCheckBox.isSelected() ||
769                Setup.isTrainIconAppendEnabled() != appendCheckBox.isSelected()
770                // save train icon colors
771                ||
772                !Setup.getTrainIconColorNorth().equals(northComboBox.getSelectedItem()) ||
773                !Setup.getTrainIconColorSouth().equals(southComboBox.getSelectedItem()) ||
774                !Setup.getTrainIconColorEast().equals(eastComboBox.getSelectedItem()) ||
775                !Setup.getTrainIconColorWest().equals(westComboBox.getSelectedItem()) ||
776                !Setup.getTrainIconColorLocal().equals(localComboBox.getSelectedItem()) ||
777                !Setup.getTrainIconColorTerminate().equals(terminateComboBox.getSelectedItem()) ||
778                Setup.getMaxNumberEngines() != Integer.parseInt(maxEngineSizeTextField.getText()) ||
779                Setup.getHorsePowerPerTon() != Integer.parseInt(hptTextField.getText())
780                // switch time
781                ||
782                Setup.getSwitchTime() != Integer.parseInt(switchTimeTextField.getText())
783                // travel time
784                ||
785                Setup.getTravelTime() != Integer.parseInt(travelTimeTextField.getText()) ||
786                !Setup.getYearModeled().equals(yearTextField.getText().trim()) ||
787                Setup.getMaxTrainLength() != Integer.parseInt(maxLengthTextField.getText()) ||
788                !Setup.getComment().equals(this.commentTextArea.getText())) {
789            return true;
790        }
791
792        // set train direction
793        int direction = 0;
794        if (eastCheckBox.isSelected()) {
795            direction = Setup.EAST + Setup.WEST;
796        }
797        if (northCheckBox.isSelected()) {
798            direction += Setup.NORTH + Setup.SOUTH;
799        }
800        // get scale
801        int scale = getSelectedScale();
802        String lengthUnit = "";
803        // Set Unit of Length
804        if (feetUnit.isSelected()) {
805            lengthUnit = Setup.FEET;
806        }
807        if (meterUnit.isSelected()) {
808            lengthUnit = Setup.METER;
809        }
810        return (Setup.getTrainDirection() != direction ||
811                Setup.getScale() != scale ||
812                !Setup.getRailroadName().equals(this.railroadNameTextField.getText()) ||
813                !Setup.getLengthUnit().equals(lengthUnit));
814    }
815
816    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OperationsSettingsPanel.class);
817
818}