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