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