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