001package jmri.jmrit.operations.setup.gui;
002
003import java.awt.GridBagLayout;
004
005import javax.swing.*;
006
007import jmri.InstanceManager;
008import jmri.jmrit.operations.OperationsXml;
009import jmri.jmrit.operations.locations.LocationManager;
010import jmri.jmrit.operations.locations.tools.LocationsByQuickServiceFrame;
011import jmri.jmrit.operations.setup.Setup;
012import jmri.jmrit.operations.trains.TrainManager;
013import jmri.util.swing.JmriJOptionPane;
014
015/**
016 * Frame for user edit of setup options
017 *
018 * @author Dan Boudreau Copyright (C) 2010, 2011, 2012, 2013, 2015, 2026
019 */
020public class OptionPanel extends OperationsPreferencesPanel {
021
022    // labels
023    // major buttons
024    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
025
026    // radio buttons
027    JRadioButton buildNormal = new JRadioButton(Bundle.getMessage("Normal"));
028    JRadioButton buildAggressive = new JRadioButton(Bundle.getMessage("Aggressive"));
029    JRadioButton buildOnTime = new JRadioButton(Bundle.getMessage("OnTime"));
030
031    // check boxes
032    JCheckBox routerCheckBox = new JCheckBox(Bundle.getMessage("EnableCarRouting"));
033    JCheckBox routerYardCheckBox = new JCheckBox(Bundle.getMessage("EnableCarRoutingYard"));
034    JCheckBox routerStagingCheckBox = new JCheckBox(Bundle.getMessage("EnableCarRoutingStaging"));
035    JCheckBox routerAllTrainsBox = new JCheckBox(Bundle.getMessage("AllTrains"));
036    JCheckBox routerRestrictBox = new JCheckBox(Bundle.getMessage("EnableTrackDestinationRestrictions"));
037
038    JCheckBox valueCheckBox = new JCheckBox(Bundle.getMessage("EnableValue"));
039    JCheckBox rfidCheckBox = new JCheckBox(Bundle.getMessage("EnableRfid"));
040    JCheckBox carLoggerCheckBox = new JCheckBox(Bundle.getMessage("EnableCarLogging"));
041    JCheckBox engineLoggerCheckBox = new JCheckBox(Bundle.getMessage("EnableEngineLogging"));
042    JCheckBox trainLoggerCheckBox = new JCheckBox(Bundle.getMessage("EnableTrainLogging"));
043
044    JCheckBox localInterchangeCheckBox = new JCheckBox(Bundle.getMessage("AllowLocalInterchange"));
045    JCheckBox localSpurCheckBox = new JCheckBox(Bundle.getMessage("AllowLocalSpur"));
046    JCheckBox localYardCheckBox = new JCheckBox(Bundle.getMessage("AllowLocalYard"));
047
048    JCheckBox trainIntoStagingCheckBox = new JCheckBox(Bundle.getMessage("TrainIntoStaging"));
049    JCheckBox stagingAvailCheckBox = new JCheckBox(Bundle.getMessage("StagingAvailable"));
050    JCheckBox stagingTurnCheckBox = new JCheckBox(Bundle.getMessage("AllowCarsToReturn"));
051    JCheckBox promptFromTrackStagingCheckBox = new JCheckBox(Bundle.getMessage("PromptFromStaging"));
052    JCheckBox promptToTrackStagingCheckBox = new JCheckBox(Bundle.getMessage("PromptToStaging"));
053    JCheckBox tryNormalStagingCheckBox = new JCheckBox(Bundle.getMessage("TryNormalStaging"));
054
055    JCheckBox generateCvsManifestCheckBox = new JCheckBox(Bundle.getMessage("GenerateCsvManifest"));
056    JCheckBox generateCvsSwitchListCheckBox = new JCheckBox(Bundle.getMessage("GenerateCsvSwitchList"));
057
058    JCheckBox enableVsdCheckBox = new JCheckBox(Bundle.getMessage("EnableVSD"));
059    JCheckBox saveTrainManifestCheckBox = new JCheckBox(Bundle.getMessage("SaveManifests"));
060
061    // text field
062    JTextField dwellTimeTextField = new JTextField(10);
063    JTextField rfidTextField = new JTextField(10);
064    JTextField valueTextField = new JTextField(10);
065
066    // combo boxes
067    JComboBox<Integer> numberPassesComboBox = new JComboBox<>();
068
069    public OptionPanel() {
070
071        // load checkboxes
072        localInterchangeCheckBox.setSelected(Setup.isLocalInterchangeMovesEnabled());
073        localSpurCheckBox.setSelected(Setup.isLocalSpurMovesEnabled());
074        localYardCheckBox.setSelected(Setup.isLocalYardMovesEnabled());
075        // staging options
076        trainIntoStagingCheckBox.setSelected(Setup.isStagingTrainCheckEnabled());
077        stagingAvailCheckBox.setSelected(Setup.isStagingTrackImmediatelyAvail());
078        stagingTurnCheckBox.setSelected(Setup.isStagingAllowReturnEnabled());
079        promptToTrackStagingCheckBox.setSelected(Setup.isStagingPromptToEnabled());
080        promptFromTrackStagingCheckBox.setSelected(Setup.isStagingPromptFromEnabled());
081        tryNormalStagingCheckBox.setSelected(Setup.isStagingTryNormalBuildEnabled());
082        // router
083        routerCheckBox.setSelected(Setup.isCarRoutingEnabled());
084        routerYardCheckBox.setSelected(Setup.isCarRoutingViaYardsEnabled());
085        routerStagingCheckBox.setSelected(Setup.isCarRoutingViaStagingEnabled());
086        routerAllTrainsBox.setSelected(!Setup.isOnlyActiveTrainsEnabled());
087        routerRestrictBox.setSelected(Setup.isCheckCarDestinationEnabled());
088        // logging options
089        carLoggerCheckBox.setSelected(Setup.isCarLoggerEnabled());
090        engineLoggerCheckBox.setSelected(Setup.isEngineLoggerEnabled());
091        trainLoggerCheckBox.setSelected(Setup.isTrainLoggerEnabled());
092        // save manifests
093        saveTrainManifestCheckBox.setSelected(Setup.isSaveTrainManifestsEnabled());
094
095        generateCvsManifestCheckBox.setSelected(Setup.isGenerateCsvManifestEnabled());
096        generateCvsSwitchListCheckBox.setSelected(Setup.isGenerateCsvSwitchListEnabled());
097        valueCheckBox.setSelected(Setup.isValueEnabled());
098        rfidCheckBox.setSelected(Setup.isRfidEnabled());
099        enableVsdCheckBox.setSelected(Setup.isVsdPhysicalLocationEnabled());
100
101        // load text fields
102        dwellTimeTextField.setText(Integer.toString(Setup.getDwellTime()));
103        rfidTextField.setText(Setup.getRfidLabel());
104        valueTextField.setText(Setup.getValueLabel());
105
106        // add tool tips
107        saveButton.setToolTipText(Bundle.getMessage("SaveToolTip"));
108        rfidTextField.setToolTipText(Bundle.getMessage("EnterNameRfidTip"));
109        valueTextField.setToolTipText(Bundle.getMessage("EnterNameValueTip"));
110        stagingTurnCheckBox.setToolTipText(Bundle.getMessage("AlsoAvailablePerTrain"));
111
112        // load combobox, allow 2 to 4 passes
113        for (int x = 2; x < 5; x++) {
114            numberPassesComboBox.addItem(x);
115        }
116
117        numberPassesComboBox.setSelectedItem(Setup.getNumberPasses());
118        padComboBox(numberPassesComboBox, 2);
119
120        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
121
122        JPanel panel = new JPanel();
123        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
124        JScrollPane panelPane = new JScrollPane(panel);
125
126        // Build Options panel
127        JPanel pBuild = new JPanel();
128        pBuild.setLayout(new BoxLayout(pBuild, BoxLayout.Y_AXIS));
129        pBuild.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutBuildOptions")));
130
131        JPanel pOpt = new JPanel();
132        pOpt.setLayout(new GridBagLayout());
133
134        addItem(pOpt, buildNormal, 1, 0);
135        addItem(pOpt, buildAggressive, 2, 0);
136        addItem(pOpt, buildOnTime, 3, 0);
137        pBuild.add(pOpt);
138
139        JPanel pPasses = new JPanel();
140        pPasses.setLayout(new GridBagLayout());
141        pPasses.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutNumberPasses")));
142        addItem(pPasses, numberPassesComboBox, 0, 0);
143        pBuild.add(pPasses);
144
145        JPanel pDwellTime = new JPanel();
146        pDwellTime.setLayout(new GridBagLayout());
147        pDwellTime.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutDwellTime")));
148        addItem(pDwellTime, dwellTimeTextField, 0, 0);
149        pBuild.add(pDwellTime);
150
151        // Switcher Service
152        JPanel pSwitcher = new JPanel();
153        pSwitcher.setLayout(new GridBagLayout());
154        pSwitcher.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutSwitcherService")));
155
156        addItemLeft(pSwitcher, localInterchangeCheckBox, 1, 1);
157        addItemLeft(pSwitcher, localSpurCheckBox, 1, 2);
158        addItemLeft(pSwitcher, localYardCheckBox, 1, 3);
159
160        // Staging
161        JPanel pStaging = new JPanel();
162        pStaging.setLayout(new GridBagLayout());
163        pStaging.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutStaging")));
164
165        addItemLeft(pStaging, trainIntoStagingCheckBox, 1, 4);
166        addItemLeft(pStaging, stagingAvailCheckBox, 1, 5);
167        addItemLeft(pStaging, stagingTurnCheckBox, 1, 6);
168        addItemLeft(pStaging, promptFromTrackStagingCheckBox, 1, 7);
169        addItemLeft(pStaging, promptToTrackStagingCheckBox, 1, 8);
170        addItemLeft(pStaging, tryNormalStagingCheckBox, 1, 9);
171
172        // Router panel
173        JPanel pRouter = new JPanel();
174        pRouter.setLayout(new GridBagLayout());
175        pRouter.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutRouterOptions")));
176        addItemLeft(pRouter, routerCheckBox, 1, 0);
177        addItemLeft(pRouter, routerYardCheckBox, 1, 1);
178        addItemLeft(pRouter, routerStagingCheckBox, 1, 2);
179        addItemLeft(pRouter, routerAllTrainsBox, 1, 3);
180        addItemLeft(pRouter, routerRestrictBox, 1, 4);
181
182        // Logger panel
183        JPanel pLogger = new JPanel();
184        pLogger.setLayout(new GridBagLayout());
185        pLogger.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutLoggerOptions")));
186        addItemLeft(pLogger, engineLoggerCheckBox, 1, 0);
187        addItemLeft(pLogger, carLoggerCheckBox, 1, 1);
188        addItemLeft(pLogger, trainLoggerCheckBox, 1, 2);
189
190        // Custom Manifests and Switch Lists
191        JPanel pCustom = new JPanel();
192        pCustom.setLayout(new GridBagLayout());
193        pCustom.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutCustomManifests")));
194        addItemLeft(pCustom, generateCvsManifestCheckBox, 1, 0);
195        addItemLeft(pCustom, generateCvsSwitchListCheckBox, 1, 1);
196
197        // Options
198        JPanel pOption = new JPanel();
199        pOption.setLayout(new GridBagLayout());
200        pOption.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BorderLayoutOptions")));
201        addItemLeft(pOption, saveTrainManifestCheckBox, 1, 1);
202        addItemLeft(pOption, valueCheckBox, 1, 2);
203        addItemLeft(pOption, valueTextField, 2, 2);
204        addItemLeft(pOption, rfidCheckBox, 1, 3);
205        addItemLeft(pOption, rfidTextField, 2, 3);
206        addItemLeft(pOption, enableVsdCheckBox, 1, 4);
207
208        // row 11
209        JPanel pControl = new JPanel();
210        pControl.setLayout(new GridBagLayout());
211        addItem(pControl, saveButton, 3, 9);
212
213        panel.add(pBuild);
214        panel.add(pSwitcher);
215        panel.add(pStaging);
216        panel.add(pRouter);
217        panel.add(pLogger);
218        panel.add(pCustom);
219        panel.add(pOption);
220
221        add(panelPane);
222        add(pControl);
223
224        // setup buttons
225        addButtonAction(saveButton);
226
227        // radio buttons
228        ButtonGroup buildGroup = new ButtonGroup();
229        buildGroup.add(buildNormal);
230        buildGroup.add(buildAggressive);
231        buildGroup.add(buildOnTime);
232
233        addRadioButtonAction(buildNormal);
234        addRadioButtonAction(buildAggressive);
235        addRadioButtonAction(buildOnTime);
236
237        // check boxes
238        addCheckBoxAction(routerCheckBox);
239        addCheckBoxAction(routerRestrictBox);
240        setRouterCheckBoxesEnabled();
241
242        setBuildOption();
243        enableComponents();
244    }
245
246    private void setBuildOption() {
247        buildNormal.setSelected(!Setup.isBuildAggressive());
248        buildAggressive.setSelected(Setup.isBuildAggressive());
249        buildOnTime.setSelected(Setup.isBuildOnTime());
250    }
251
252    private void enableComponents() {
253        // disable staging option if normal mode
254        stagingAvailCheckBox.setEnabled(!buildNormal.isSelected());
255        numberPassesComboBox.setEnabled(!buildNormal.isSelected());
256        dwellTimeTextField.setEnabled(buildOnTime.isSelected());
257        tryNormalStagingCheckBox.setEnabled(!buildNormal.isSelected());
258    }
259
260    @Override
261    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
262        log.debug("radio button selected");
263        // can't change the build option if there are trains built
264        if (InstanceManager.getDefault(TrainManager.class).isAnyTrainBuilt()) {
265            setBuildOption(); // restore the correct setting
266            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("CanNotChangeBuild"),
267                    Bundle.getMessage("MustTerminateOrReset"), JmriJOptionPane.ERROR_MESSAGE);
268        }
269        enableComponents();
270        // Special case where there are train build failures that created work.
271        // Track reserve needs to cleaned up by reseting build failed trains
272        if (buildAggressive.isSelected() != Setup.isBuildAggressive() &&
273                InstanceManager.getDefault(LocationManager.class).hasWork()) {
274            InstanceManager.getDefault(TrainManager.class).resetBuildFailedTrains();
275        }
276    }
277
278    // Save button
279    @Override
280    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
281        if (ae.getSource() == saveButton) {
282            this.savePreferences();
283            var topLevelAncestor = getTopLevelAncestor();
284            if (Setup.isCloseWindowOnSaveEnabled() && topLevelAncestor instanceof OptionFrame) {
285                ((OptionFrame) topLevelAncestor).dispose();
286            }
287        }
288    }
289
290    @Override
291    protected void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
292        if (ae.getSource() == routerCheckBox) {
293            setRouterCheckBoxesEnabled();
294        }
295        if (ae.getSource() == routerRestrictBox && routerRestrictBox.isSelected()) {
296            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("WarnExtremeTrackDest"),
297                    Bundle.getMessage("WarnExtremeTitle"), JmriJOptionPane.WARNING_MESSAGE);
298        }
299    }
300
301    private void setRouterCheckBoxesEnabled() {
302        routerYardCheckBox.setEnabled(routerCheckBox.isSelected());
303        routerStagingCheckBox.setEnabled(routerCheckBox.isSelected());
304        routerAllTrainsBox.setEnabled(routerCheckBox.isSelected());
305        routerRestrictBox.setEnabled(routerCheckBox.isSelected());
306    }
307
308    @Override
309    public String getTabbedPreferencesTitle() {
310        return Bundle.getMessage("TitleOptions");
311    }
312
313    @Override
314    public String getPreferencesTooltip() {
315        return null;
316    }
317
318    @Override
319    public void savePreferences() {
320        // build option
321        boolean isBuildOnTime = Setup.isBuildOnTime();
322        Setup.setBuildAggressive(buildAggressive.isSelected() || buildOnTime.isSelected());
323        Setup.setNumberPasses((Integer) numberPassesComboBox.getSelectedItem());
324        Setup.setBuildOnTime(buildOnTime.isSelected());
325        try {
326            Setup.setDwellTime(Integer.parseInt(dwellTimeTextField.getText()));
327        } catch (NumberFormatException e) {
328            log.error("Dwell Time {} must be a number", dwellTimeTextField.getText());
329        }
330        // local switcher options
331        Setup.setLocalInterchangeMovesEnabled(localInterchangeCheckBox.isSelected());
332        Setup.setLocalSpurMovesEnabled(localSpurCheckBox.isSelected());
333        Setup.setLocalYardMovesEnabled(localYardCheckBox.isSelected());
334        // Staging options
335        Setup.setStagingTrainCheckEnabled(trainIntoStagingCheckBox.isSelected());
336        Setup.setStagingTrackImmediatelyAvail(stagingAvailCheckBox.isSelected());
337        Setup.setStagingAllowReturnEnabled(stagingTurnCheckBox.isSelected());
338        Setup.setStagingPromptFromEnabled(promptFromTrackStagingCheckBox.isSelected());
339        Setup.setStagingPromptToEnabled(promptToTrackStagingCheckBox.isSelected());
340        Setup.setStagingTryNormalBuildEnabled(tryNormalStagingCheckBox.isSelected());
341        // Car routing enabled?
342        Setup.setCarRoutingEnabled(routerCheckBox.isSelected());
343        Setup.setCarRoutingViaYardsEnabled(routerYardCheckBox.isSelected());
344        Setup.setCarRoutingViaStagingEnabled(routerStagingCheckBox.isSelected());
345        Setup.setOnlyActiveTrainsEnabled(!routerAllTrainsBox.isSelected());
346        Setup.setCheckCarDestinationEnabled(routerRestrictBox.isSelected());
347        // Options
348        Setup.setGenerateCsvManifestEnabled(generateCvsManifestCheckBox.isSelected());
349        Setup.setGenerateCsvSwitchListEnabled(generateCvsSwitchListCheckBox.isSelected());
350        Setup.setSaveTrainManifestsEnabled(saveTrainManifestCheckBox.isSelected());
351        Setup.setValueEnabled(valueCheckBox.isSelected());
352        Setup.setValueLabel(valueTextField.getText());
353        Setup.setRfidEnabled(rfidCheckBox.isSelected());
354        Setup.setRfidLabel(rfidTextField.getText());
355        // Logging enabled?
356        Setup.setEngineLoggerEnabled(engineLoggerCheckBox.isSelected());
357        Setup.setCarLoggerEnabled(carLoggerCheckBox.isSelected());
358        Setup.setTrainLoggerEnabled(trainLoggerCheckBox.isSelected());
359        // VSD
360        Setup.setVsdPhysicalLocationEnabled(enableVsdCheckBox.isSelected());
361        // write the file
362        OperationsXml.save();
363        // bring up the quick service tool
364        if (!isBuildOnTime && buildOnTime.isSelected()) {
365            LocationsByQuickServiceFrame f = new LocationsByQuickServiceFrame();
366            f.initComponents();
367        }
368    }
369
370    @Override
371    public boolean isDirty() {
372        return !( // build option
373        Setup.isBuildAggressive() == buildAggressive.isSelected() &&
374                Setup.getNumberPasses() == (int) numberPassesComboBox.getSelectedItem()
375                // Local moves?
376                &&
377                Setup.isLocalInterchangeMovesEnabled() == localInterchangeCheckBox.isSelected() &&
378                Setup.isLocalSpurMovesEnabled() == localSpurCheckBox.isSelected() &&
379                Setup.isLocalYardMovesEnabled() == localYardCheckBox.isSelected()
380                // Staging options
381                &&
382                Setup.isStagingTrainCheckEnabled() == trainIntoStagingCheckBox.isSelected() &&
383                Setup.isStagingTrackImmediatelyAvail() == stagingAvailCheckBox.isSelected() &&
384                Setup.isStagingAllowReturnEnabled() == stagingTurnCheckBox.isSelected() &&
385                Setup.isStagingPromptFromEnabled() == promptFromTrackStagingCheckBox.isSelected() &&
386                Setup.isStagingPromptToEnabled() == promptToTrackStagingCheckBox.isSelected() &&
387                Setup.isStagingTryNormalBuildEnabled() == tryNormalStagingCheckBox.isSelected()
388                // Car routing enabled?
389                &&
390                Setup.isCarRoutingEnabled() == routerCheckBox.isSelected() &&
391                Setup.isCarRoutingViaYardsEnabled() == routerYardCheckBox.isSelected() &&
392                Setup.isCarRoutingViaStagingEnabled() == routerStagingCheckBox.isSelected() &&
393                Setup.isOnlyActiveTrainsEnabled() == !routerAllTrainsBox.isSelected() &&
394                Setup.isCheckCarDestinationEnabled() == routerRestrictBox.isSelected()
395                // Options
396                &&
397                Setup.isGenerateCsvManifestEnabled() == generateCvsManifestCheckBox.isSelected() &&
398                Setup.isGenerateCsvSwitchListEnabled() == generateCvsSwitchListCheckBox.isSelected() &&
399                Setup.isValueEnabled() == valueCheckBox.isSelected() &&
400                Setup.getValueLabel().equals(valueTextField.getText()) &&
401                Setup.isRfidEnabled() == rfidCheckBox.isSelected() &&
402                Setup.getRfidLabel().equals(rfidTextField.getText()) &&
403                Setup.isSaveTrainManifestsEnabled() == saveTrainManifestCheckBox.isSelected()
404                // Logging enabled?
405                &&
406                Setup.isEngineLoggerEnabled() == engineLoggerCheckBox.isSelected() &&
407                Setup.isCarLoggerEnabled() == carLoggerCheckBox.isSelected() &&
408                Setup.isTrainLoggerEnabled() == trainLoggerCheckBox.isSelected()
409                // VSD
410                &&
411                Setup.isVsdPhysicalLocationEnabled() == enableVsdCheckBox.isSelected());
412    }
413
414    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OptionPanel.class);
415
416}