001package jmri.jmrit.dispatcher; 002 003import java.awt.BorderLayout; 004import java.awt.Component; 005import java.awt.Container; 006import java.awt.Dimension; 007import java.awt.FlowLayout; 008import java.awt.event.ActionEvent; 009import java.awt.event.ActionListener; 010import java.awt.event.ItemEvent; 011import java.util.ArrayList; 012import java.util.HashSet; 013import java.util.List; 014import java.util.Locale; 015import java.util.Set; 016 017import javax.swing.BorderFactory; 018import javax.swing.BoxLayout; 019import javax.swing.ButtonGroup; 020import javax.swing.JButton; 021import javax.swing.JCheckBox; 022import javax.swing.JComboBox; 023import javax.swing.JLabel; 024import javax.swing.JPanel; 025import javax.swing.JRadioButton; 026import javax.swing.JScrollPane; 027import javax.swing.JSeparator; 028import javax.swing.JSpinner; 029import javax.swing.JTable; 030import javax.swing.JTextField; 031import javax.swing.ScrollPaneConstants; 032import javax.swing.SpinnerNumberModel; 033import javax.swing.table.DefaultTableModel; 034import javax.swing.table.TableCellRenderer; 035import javax.swing.table.TableColumnModel; 036 037import jmri.Block; 038import jmri.jmrit.display.layoutEditor.LayoutBlock; 039import jmri.jmrit.display.layoutEditor.LayoutBlockManager; 040import jmri.InstanceManager; 041import jmri.Sensor; 042import jmri.Transit; 043import jmri.TransitManager; 044import jmri.jmrit.dispatcher.ActiveTrain.TrainDetection; 045import jmri.jmrit.dispatcher.ActiveTrain.TrainLengthUnits; 046import jmri.jmrit.dispatcher.DispatcherFrame.TrainsFrom; 047import jmri.jmrit.operations.trains.Train; 048import jmri.jmrit.operations.trains.TrainManager; 049import jmri.jmrit.roster.RosterEntry; 050import jmri.jmrit.roster.swing.RosterEntryComboBox; 051import jmri.swing.NamedBeanComboBox; 052import jmri.util.JmriJFrame; 053import jmri.util.swing.JComboBoxUtil; 054import jmri.util.swing.JmriJOptionPane; 055 056/** 057 * Displays the Activate New Train Frame and processes information entered 058 * there. 059 * <p> 060 * This module works with Dispatcher, which initiates the display of this Frame. 061 * Dispatcher also creates the ActiveTrain. 062 * <p> 063 * This file is part of JMRI. 064 * <p> 065 * JMRI is open source software; you can redistribute it and/or modify it under 066 * the terms of version 2 of the GNU General Public License as published by the 067 * Free Software Foundation. See the "COPYING" file for a copy of this license. 068 * <p> 069 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 070 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 071 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 072 * 073 * @author Dave Duchamp Copyright (C) 2009 074 */ 075public class ActivateTrainFrame extends JmriJFrame { 076 077 public ActivateTrainFrame(DispatcherFrame d) { 078 super(true,true); 079 _dispatcher = d; 080 _tiFile = new TrainInfoFile(); 081 } 082 083 // operational instance variables 084 private DispatcherFrame _dispatcher = null; 085 private TrainInfoFile _tiFile = null; 086 private final TransitManager _TransitManager = InstanceManager.getDefault(jmri.TransitManager.class); 087 private String _trainInfoName = ""; 088 089 // initiate train window variables 090 private Transit selectedTransit = null; 091 //private String selectedTrain = ""; 092 private JmriJFrame initiateFrame = null; 093 private Container initiatePane = null; 094 private final jmri.swing.NamedBeanComboBox<Transit> transitSelectBox = new jmri.swing.NamedBeanComboBox<>(_TransitManager); 095 private final JComboBox<Object> trainSelectBox = new JComboBox<>(); 096 // private final List<RosterEntry> trainBoxList = new ArrayList<>(); 097 private RosterEntryComboBox rosterComboBox = null; 098 private final JLabel trainFieldLabel = new JLabel(Bundle.getMessage("TrainBoxLabel") + ":"); 099 private final JTextField trainNameField = new JTextField(10); 100 private final JLabel dccAddressFieldLabel = new JLabel(" " + Bundle.getMessage("DccAddressFieldLabel") + ":"); 101 private final JSpinner dccAddressSpinner = new JSpinner(new SpinnerNumberModel(3, 1, 9999, 1)); 102 private final JCheckBox inTransitBox = new JCheckBox(Bundle.getMessage("TrainInTransit")); 103 private final JComboBox<String> startingBlockBox = new JComboBox<>(); 104 private final JComboBox<String> viaBlockBox = new JComboBox<>(); 105 private final JLabel viaBlockBoxLabel = new JLabel(Bundle.getMessage("ViaBlockBoxLabel")); 106 private List<Block> startingBlockBoxList = new ArrayList<>(); 107 private final List<Block> viaBlockBoxList = new ArrayList<>(); 108 private List<Integer> startingBlockSeqList = new ArrayList<>(); 109 private final JComboBox<String> destinationBlockBox = new JComboBox<>(); 110 111 private List<Block> destinationBlockBoxList = new ArrayList<>(); 112 private List<Integer> destinationBlockSeqList = new ArrayList<>(); 113 private JButton addNewTrainButton = null; 114 private JButton loadButton = null; 115 private JButton saveButton = null; 116 private JButton saveAsTemplateButton = null; 117 private JButton deleteButton = null; 118 private final JCheckBox autoRunBox = new JCheckBox(Bundle.getMessage("AutoRun")); 119 private final JCheckBox loadAtStartupBox = new JCheckBox(Bundle.getMessage("LoadAtStartup")); 120 121 private final JRadioButton radioTrainsFromRoster = new JRadioButton(Bundle.getMessage("TrainsFromRoster")); 122 private final JRadioButton radioTrainsFromOps = new JRadioButton(Bundle.getMessage("TrainsFromTrains")); 123 private final JRadioButton radioTrainsFromUser = new JRadioButton(Bundle.getMessage("TrainsFromUser")); 124 private final JRadioButton radioTrainsFromSetLater = new JRadioButton(Bundle.getMessage("TrainsFromSetLater")); 125 private final ButtonGroup trainsFromButtonGroup = new ButtonGroup(); 126 127 private final JRadioButton radioTransitsPredefined = new JRadioButton(Bundle.getMessage("TransitsPredefined")); 128 private final JRadioButton radioTransitsAdHoc = new JRadioButton(Bundle.getMessage("TransitsAdHoc")); 129 private final ButtonGroup transitsFromButtonGroup = new ButtonGroup(); 130 //private final JCheckBox adHocCloseLoop = new JCheckBox(Bundle.getMessage("TransitCloseLoop")); 131 132 private final JRadioButton allocateBySafeRadioButton = new JRadioButton(Bundle.getMessage("ToSafeSections")); 133 private final JRadioButton allocateAllTheWayRadioButton = new JRadioButton(Bundle.getMessage("AsFarAsPos")); 134 private final JRadioButton allocateNumberOfBlocks = new JRadioButton(Bundle.getMessage("NumberOfBlocks") + ":"); 135 private final ButtonGroup allocateMethodButtonGroup = new ButtonGroup(); 136 private final JSpinner allocateCustomSpinner = new JSpinner(new SpinnerNumberModel(3, 1, 100, 1)); 137 private final JCheckBox terminateWhenDoneBox = new JCheckBox(Bundle.getMessage("TerminateWhenDone")); 138 private final JPanel terminateWhenDoneDetails = new JPanel(); 139 private final JComboBox<String> nextTrain = new JComboBox<>(); 140 private final JLabel nextTrainLabel = new JLabel(Bundle.getMessage("TerminateWhenDoneNextTrain")); 141 private final JSpinner prioritySpinner = new JSpinner(new SpinnerNumberModel(5, 0, 100, 1)); 142 private final JCheckBox resetWhenDoneBox = new JCheckBox(Bundle.getMessage("ResetWhenDone")); 143 private final JCheckBox reverseAtEndBox = new JCheckBox(Bundle.getMessage("ReverseAtEnd")); 144 145 int[] delayedStartInt = new int[]{ActiveTrain.NODELAY, ActiveTrain.TIMEDDELAY, ActiveTrain.SENSORDELAY}; 146 String[] delayedStartString = new String[]{Bundle.getMessage("DelayedStartNone"), Bundle.getMessage("DelayedStartTimed"), Bundle.getMessage("DelayedStartSensor")}; 147 148 private final JComboBox<String> reverseDelayedRestartType = new JComboBox<>(delayedStartString); 149 private final JLabel delayReverseReStartLabel = new JLabel(Bundle.getMessage("DelayRestart")); 150 private final JLabel delayReverseReStartSensorLabel = new JLabel(Bundle.getMessage("RestartSensor")); 151 private final JCheckBox delayReverseResetSensorBox = new JCheckBox(Bundle.getMessage("ResetRestartSensor")); 152 private final NamedBeanComboBox<Sensor> delayReverseReStartSensor = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance()); 153 private final JSpinner delayReverseMinSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); 154 private final JLabel delayReverseMinLabel = new JLabel(Bundle.getMessage("RestartTimed")); 155 156 private final JCheckBox resetStartSensorBox = new JCheckBox(Bundle.getMessage("ResetStartSensor")); 157 private final JComboBox<String> delayedStartBox = new JComboBox<>(delayedStartString); 158 private final JLabel delayedReStartLabel = new JLabel(Bundle.getMessage("DelayRestart")); 159 private final JLabel delayReStartSensorLabel = new JLabel(Bundle.getMessage("RestartSensor")); 160 private final JCheckBox resetRestartSensorBox = new JCheckBox(Bundle.getMessage("ResetRestartSensor")); 161 private final JComboBox<String> delayedReStartBox = new JComboBox<>(delayedStartString); 162 private final NamedBeanComboBox<Sensor> delaySensor = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance()); 163 private final NamedBeanComboBox<Sensor> delayReStartSensor = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance()); 164 165 private final JSpinner departureHrSpinner = new JSpinner(new SpinnerNumberModel(8, 0, 23, 1)); 166 private final JSpinner departureMinSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 59, 1)); 167 private final JLabel departureTimeLabel = new JLabel(Bundle.getMessage("DepartureTime")); 168 private final JLabel departureSepLabel = new JLabel(":"); 169 170 private final JSpinner delayMinSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); 171 private final JLabel delayMinLabel = new JLabel(Bundle.getMessage("RestartTimed")); 172 173 private final JComboBox<String> trainTypeBox = new JComboBox<>(); 174 // Note: See also items related to automatically running trains near the end of this module 175 176 boolean transitsFromSpecificBlock = false; 177 178 private TrainInfo trainInfo; 179 180 private final String nameOfTemplateFile="TrainInfoDefaultTemplate.xml"; 181 // to be added and removed. 182 private final ActionListener viaBlockBoxListener = e -> handleViaBlockSelectionChanged(); 183 184 /** 185 * Open up a new train window for a given roster entry located in a specific 186 * block. 187 * 188 * @param e the action event triggering the new window 189 * @param re the roster entry to open the new window for 190 * @param b the block where the train is located 191 */ 192 public void initiateTrain(ActionEvent e, RosterEntry re, Block b) { 193 initiateTrain(e); 194 if (trainInfo.getTrainsFrom() == TrainsFrom.TRAINSFROMROSTER && re != null) { 195 setRosterComboBox(rosterComboBox, re.getId()); 196 //Add in some bits of code as some point to filter down the transits that can be used. 197 } 198 if (b != null && selectedTransit != null) { 199 List<Transit> transitList = _TransitManager.getListUsingBlock(b); 200 List<Transit> transitEntryList = _TransitManager.getListEntryBlock(b); 201 for (Transit t : transitEntryList) { 202 if (!transitList.contains(t)) { 203 transitList.add(t); 204 } 205 } 206 transitsFromSpecificBlock = true; 207 initializeFreeTransitsCombo(transitList); 208 List<Block> tmpBlkList = new ArrayList<>(); 209 if (selectedTransit.getEntryBlocksList().contains(b)) { 210 tmpBlkList = selectedTransit.getEntryBlocksList(); 211 inTransitBox.setSelected(false); 212 } else if (selectedTransit.containsBlock(b)) { 213 tmpBlkList = selectedTransit.getInternalBlocksList(); 214 inTransitBox.setSelected(true); 215 } 216 List<Integer> tmpSeqList = selectedTransit.getBlockSeqList(); 217 for (int i = 0; i < tmpBlkList.size(); i++) { 218 if (tmpBlkList.get(i) == b) { 219 setComboBox(startingBlockBox, getBlockName(b) + "-" + tmpSeqList.get(i)); 220 break; 221 } 222 } 223 } 224 } 225 226 /** 227 * Displays a window that allows a new ActiveTrain to be activated. 228 * <p> 229 * Called by Dispatcher in response to the dispatcher clicking the New Train 230 * button. 231 * 232 * @param e the action event triggering the window display 233 */ 234 protected void initiateTrain(ActionEvent e) { 235 // set Dispatcher defaults 236 // create window if needed 237 // if template exists open it 238 try { 239 trainInfo = _tiFile.readTrainInfo(nameOfTemplateFile); 240 if (trainInfo == null) { 241 trainInfo = new TrainInfo(); 242 } 243 } catch (java.io.IOException ioe) { 244 log.error("IO Exception when reading train info file", ioe); 245 return; 246 } catch (org.jdom2.JDOMException jde) { 247 log.error("JDOM Exception when reading train info file", jde); 248 return; 249 } 250 251 if (initiateFrame == null) { 252 initiateFrame = this; 253 initiateFrame.setTitle(Bundle.getMessage("AddTrainTitle")); 254 initiateFrame.addHelpMenu("package.jmri.jmrit.dispatcher.NewTrain", true); 255 initiatePane = initiateFrame.getContentPane(); 256 initiatePane.setLayout(new BoxLayout(initiatePane, BoxLayout.Y_AXIS)); 257 258 // add buttons to load and save train information 259 JPanel hdr = new JPanel(); 260 hdr.add(loadButton = new JButton(Bundle.getMessage("LoadButton"))); 261 loadButton.addActionListener(this::loadTrainInfo); 262 loadButton.setToolTipText(Bundle.getMessage("LoadButtonHint")); 263 hdr.add(saveButton = new JButton(Bundle.getMessage("SaveButton"))); 264 saveButton.addActionListener( ev -> saveTrainInfo()); 265 saveButton.setToolTipText(Bundle.getMessage("SaveButtonHint")); 266 hdr.add(saveAsTemplateButton = new JButton(Bundle.getMessage("SaveAsTemplateButton"))); 267 saveAsTemplateButton.addActionListener( ev -> saveTrainInfoAsTemplate()); 268 saveAsTemplateButton.setToolTipText(Bundle.getMessage("SaveAsTemplateButtonHint")); 269 hdr.add(deleteButton = new JButton(Bundle.getMessage("DeleteButton"))); 270 deleteButton.addActionListener( ev -> deleteTrainInfo()); 271 deleteButton.setToolTipText(Bundle.getMessage("DeleteButtonHint")); 272 273 // add items relating to both manually run and automatic trains. 274 275 // Trains From choices. 276 JPanel p1 = new JPanel(); 277 p1.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainsFrom"))); 278 radioTrainsFromRoster.setActionCommand("TRAINSFROMROSTER"); 279 trainsFromButtonGroup.add(radioTrainsFromRoster); 280 radioTrainsFromOps.setActionCommand("TRAINSFROMOPS"); 281 trainsFromButtonGroup.add(radioTrainsFromOps); 282 radioTrainsFromUser.setActionCommand("TRAINSFROMUSER"); 283 trainsFromButtonGroup.add(radioTrainsFromUser); 284 radioTrainsFromSetLater.setActionCommand("TRAINSFROMSETLATER"); 285 trainsFromButtonGroup.add(radioTrainsFromSetLater); 286 p1.add(radioTrainsFromRoster); 287 radioTrainsFromRoster.setToolTipText(Bundle.getMessage("TrainsFromRosterHint")); 288 p1.add(radioTrainsFromOps); 289 radioTrainsFromOps.setToolTipText(Bundle.getMessage("TrainsFromTrainsHint")); 290 p1.add(radioTrainsFromUser); 291 radioTrainsFromUser.setToolTipText(Bundle.getMessage("TrainsFromUserHint")); 292 p1.add(radioTrainsFromSetLater); 293 radioTrainsFromSetLater.setToolTipText(Bundle.getMessage("TrainsFromSetLaterHint")); 294 295 radioTrainsFromOps.addItemListener( e1 -> { 296 if (e1.getStateChange() == ItemEvent.SELECTED) { 297 setTrainsFromOptions(TrainsFrom.TRAINSFROMOPS); 298 } 299 }); 300 radioTrainsFromRoster.addItemListener( e1 -> { 301 if (e1.getStateChange() == ItemEvent.SELECTED) { 302 setTrainsFromOptions(TrainsFrom.TRAINSFROMROSTER); 303 } 304 }); 305 radioTrainsFromUser.addItemListener( e1 -> { 306 if (e1.getStateChange() == ItemEvent.SELECTED) { 307 setTrainsFromOptions(TrainsFrom.TRAINSFROMUSER); 308 } 309 }); 310 radioTrainsFromSetLater.addItemListener( e1 -> { 311 if (e1.getStateChange() == ItemEvent.SELECTED) { 312 setTrainsFromOptions(TrainsFrom.TRAINSFROMSETLATER); 313 } 314 }); 315 initiatePane.add(p1); 316 317 // Select train 318 JPanel p2 = new JPanel(); 319 320 // Dispatcher train name 321 p2.add(trainFieldLabel); 322 p2.add(trainNameField); 323 trainNameField.setToolTipText(Bundle.getMessage("TrainFieldHint")); 324 325 // Roster combo box 326 rosterComboBox = new RosterEntryComboBox(); 327 initializeFreeRosterEntriesCombo(); 328 rosterComboBox.addActionListener(this::handleRosterSelectionChanged); 329 p2.add(rosterComboBox); 330 331 // Operations combo box 332 p2.add(trainSelectBox); 333 trainSelectBox.addActionListener( e1 -> handleTrainSelectionChanged()); 334 trainSelectBox.setToolTipText(Bundle.getMessage("TrainBoxHint")); 335 336 // DCC address selector 337 p2.add(dccAddressFieldLabel); 338 p2.add(dccAddressSpinner); 339 dccAddressSpinner.setToolTipText(Bundle.getMessage("DccAddressFieldHint")); 340 341 initiatePane.add(p2); 342 343 // Select transit type 344 JPanel p3 = new JPanel(); 345 p3.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TransitsFrom"))); 346 radioTransitsPredefined.setActionCommand("USETRANSITS"); 347 transitsFromButtonGroup.add(radioTransitsPredefined); 348 radioTransitsAdHoc.setActionCommand("USEADHOC"); 349 transitsFromButtonGroup.add(radioTransitsAdHoc); 350 p3.add(radioTransitsPredefined); 351 radioTransitsPredefined.setToolTipText(Bundle.getMessage("TransitsPredefinedHint")); 352 p3.add(radioTransitsAdHoc); 353 radioTransitsAdHoc.setToolTipText(Bundle.getMessage("TransitsAdHocHint")); 354 radioTransitsPredefined.addItemListener( e1 -> { 355 if (e1.getStateChange() == ItemEvent.SELECTED) { 356 transitSelectBox.setEnabled(true); 357 //adHocCloseLoop.setEnabled(false); 358 inTransitBox.setEnabled(true); 359 handleInTransitClick(); 360 viaBlockBox.setVisible(false); 361 viaBlockBoxLabel.setVisible(false); 362 } 363 }); 364 radioTransitsAdHoc.addItemListener( e1 -> { 365 if (e1.getStateChange() == ItemEvent.SELECTED) { 366 checkAdvancedRouting(); 367 transitSelectBox.setEnabled(false); 368 //adHocCloseLoop.setEnabled(true); 369 inTransitBox.setEnabled(false); 370 inTransitBox.setSelected(true); 371 initializeStartingBlockComboDynamic(); 372 viaBlockBox.setVisible(true); 373 viaBlockBoxLabel.setVisible(true); 374 } 375 }); 376 377 //p3.add(adHocCloseLoop); 378 //adHocCloseLoop.setToolTipText(Bundle.getMessage("TransitCloseLoopHint")); 379 380 p3.add(new JLabel(Bundle.getMessage("TransitBoxLabel") + " :")); 381 p3.add(transitSelectBox); 382 transitSelectBox.addActionListener(this::handleTransitSelectionChanged); 383 transitSelectBox.setToolTipText(Bundle.getMessage("TransitBoxHint")); 384 initiatePane.add(p3); 385 386 // Train in transit 387 JPanel p4 = new JPanel(); 388 p4.add(inTransitBox); 389 inTransitBox.addActionListener( ev -> handleInTransitClick()); 390 inTransitBox.setToolTipText(Bundle.getMessage("InTransitBoxHint")); 391 initiatePane.add(p4); 392 393 // Starting block, add Via for adhoc transits 394 JPanel p5 = new JPanel(); 395 p5.add(new JLabel(Bundle.getMessage("StartingBlockBoxLabel") + " :")); 396 p5.add(startingBlockBox); 397 startingBlockBox.setToolTipText(Bundle.getMessage("StartingBlockBoxHint")); 398 startingBlockBox.addActionListener( ev -> handleStartingBlockSelectionChanged()); 399 p5.add(viaBlockBoxLabel); 400 p5.add(viaBlockBox); 401 viaBlockBox.setToolTipText(Bundle.getMessage("ViaBlockBoxHint")); 402 viaBlockBox.addActionListener(viaBlockBoxListener); 403 initiatePane.add(p5); 404 405 // Destination block 406 JPanel p6 = new JPanel(); 407 p6.add(new JLabel(Bundle.getMessage("DestinationBlockBoxLabel") + ":")); 408 p6.add(destinationBlockBox); 409 destinationBlockBox.setToolTipText(Bundle.getMessage("DestinationBlockBoxHint")); 410 initiatePane.add(p6); 411 412 // Train detection scope 413 JPanel p7 = new JPanel(); 414 p7.add(trainDetectionLabel); 415 initializeTrainDetectionBox(); 416 p7.add(trainDetectionComboBox); 417 trainDetectionComboBox.setToolTipText(Bundle.getMessage("TrainDetectionBoxHint")); 418 initiatePane.add(p7); 419 420 // Allocation method 421 JPanel p8 = new JPanel(); 422 p8.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("AllocateMethodLabel"))); 423 allocateMethodButtonGroup.add(allocateAllTheWayRadioButton); 424 allocateMethodButtonGroup.add(allocateBySafeRadioButton); 425 allocateMethodButtonGroup.add(allocateNumberOfBlocks); 426 p8.add(allocateAllTheWayRadioButton); 427 allocateAllTheWayRadioButton.setToolTipText(Bundle.getMessage("AllocateAllTheWayHint")); 428 p8.add(allocateBySafeRadioButton); 429 allocateBySafeRadioButton.setToolTipText(Bundle.getMessage("AllocateSafeHint")); 430 p8.add(allocateNumberOfBlocks); 431 allocateNumberOfBlocks.setToolTipText(Bundle.getMessage("AllocateMethodHint")); 432 allocateAllTheWayRadioButton.addActionListener( ev -> handleAllocateAllTheWayButtonChanged()); 433 allocateBySafeRadioButton.addActionListener( ev -> handleAllocateBySafeButtonChanged()); 434 allocateNumberOfBlocks.addActionListener( ev -> handleAllocateNumberOfBlocksButtonChanged()); 435 p8.add(allocateCustomSpinner); 436 allocateCustomSpinner.setToolTipText(Bundle.getMessage("AllocateMethodHint")); 437 initiatePane.add(p8); 438 439 // Restart at end 440 JPanel p9 = new JPanel(); 441 p9.add(resetWhenDoneBox); 442 resetWhenDoneBox.addActionListener( ev -> handleResetWhenDoneClick()); 443 resetWhenDoneBox.setToolTipText(Bundle.getMessage("ResetWhenDoneBoxHint")); 444 initiatePane.add(p9); 445 446 // Restart using sensor 447 JPanel p9a = new JPanel(); 448 ((FlowLayout) p9a.getLayout()).setVgap(1); 449 p9a.add(delayedReStartLabel); 450 p9a.add(delayedReStartBox); 451 p9a.add(resetRestartSensorBox); 452 resetRestartSensorBox.setToolTipText(Bundle.getMessage("ResetRestartSensorHint")); 453 resetRestartSensorBox.setSelected(true); 454 delayedReStartBox.addActionListener( ev -> handleResetWhenDoneClick()); 455 delayedReStartBox.setToolTipText(Bundle.getMessage("DelayedReStartHint")); 456 initiatePane.add(p9a); 457 458 // Restart using timer 459 JPanel p9b = new JPanel(); 460 ((FlowLayout) p9b.getLayout()).setVgap(1); 461 p9b.add(delayMinLabel); 462 p9b.add(delayMinSpinner); // already set to 0 463 delayMinSpinner.setToolTipText(Bundle.getMessage("RestartTimedHint")); 464 p9b.add(delayReStartSensorLabel); 465 p9b.add(delayReStartSensor); 466 delayReStartSensor.setAllowNull(true); 467 handleResetWhenDoneClick(); 468 initiatePane.add(p9b); 469 470 initiatePane.add(new JSeparator()); 471 472 // Reverse at end 473 JPanel p10 = new JPanel(); 474 p10.add(reverseAtEndBox); 475 reverseAtEndBox.setToolTipText(Bundle.getMessage("ReverseAtEndBoxHint")); 476 initiatePane.add(p10); 477 reverseAtEndBox.addActionListener( ev -> handleReverseAtEndBoxClick()); 478 479 // Reverse using sensor 480 JPanel pDelayReverseRestartDetails = new JPanel(); 481 ((FlowLayout) pDelayReverseRestartDetails.getLayout()).setVgap(1); 482 pDelayReverseRestartDetails.add(delayReverseReStartLabel); 483 pDelayReverseRestartDetails.add(reverseDelayedRestartType); 484 pDelayReverseRestartDetails.add(delayReverseResetSensorBox); 485 delayReverseResetSensorBox.setToolTipText(Bundle.getMessage("ReverseResetRestartSensorHint")); 486 delayReverseResetSensorBox.setSelected(true); 487 reverseDelayedRestartType.addActionListener( ev -> handleReverseAtEndBoxClick()); 488 reverseDelayedRestartType.setToolTipText(Bundle.getMessage("ReverseDelayedReStartHint")); 489 initiatePane.add(pDelayReverseRestartDetails); 490 491 // Reverse using timer 492 JPanel pDelayReverseRestartDetails2 = new JPanel(); 493 ((FlowLayout) pDelayReverseRestartDetails2.getLayout()).setVgap(1); 494 pDelayReverseRestartDetails2.add(delayReverseMinLabel); 495 pDelayReverseRestartDetails2.add(delayReverseMinSpinner); // already set to 0 496 delayReverseMinSpinner.setToolTipText(Bundle.getMessage("ReverseRestartTimedHint")); 497 pDelayReverseRestartDetails2.add(delayReverseReStartSensorLabel); 498 pDelayReverseRestartDetails2.add(delayReverseReStartSensor); 499 delayReverseReStartSensor.setAllowNull(true); 500 handleReverseAtEndBoxClick(); 501 initiatePane.add(pDelayReverseRestartDetails2); 502 503 initiatePane.add(new JSeparator()); 504 505 // Terminate when done option 506 JPanel p11 = new JPanel(); 507 p11.setLayout(new FlowLayout()); 508 p11.add(terminateWhenDoneBox); 509 terminateWhenDoneBox.addActionListener( ev -> handleTerminateWhenDoneBoxClick()); 510 initiatePane.add(p11); 511 512 // Optional next train, tied to terminate when done. 513 terminateWhenDoneDetails.setLayout(new FlowLayout()); 514 terminateWhenDoneDetails.add(nextTrainLabel); 515 terminateWhenDoneDetails.add(nextTrain); 516 nextTrain.setToolTipText(Bundle.getMessage("TerminateWhenDoneNextTrainHint")); 517 initiatePane.add(terminateWhenDoneDetails); 518 handleTerminateWhenDoneBoxClick(); 519 520 initiatePane.add(new JSeparator()); 521 522 // Priority and train type. 523 JPanel p12 = new JPanel(); 524 p12.setLayout(new FlowLayout()); 525 p12.add(new JLabel(Bundle.getMessage("PriorityLabel") + ":")); 526 p12.add(prioritySpinner); // already set to 5 527 prioritySpinner.setToolTipText(Bundle.getMessage("PriorityHint")); 528 p12.add(new JLabel(" ")); 529 p12.add(new JLabel(Bundle.getMessage("TrainTypeBoxLabel"))); 530 initializeTrainTypeBox(); 531 p12.add(trainTypeBox); 532 trainTypeBox.setSelectedIndex(1); 533 trainTypeBox.setToolTipText(Bundle.getMessage("TrainTypeBoxHint")); 534 initiatePane.add(p12); 535 536 // Delayed start option 537 JPanel p13 = new JPanel(); 538 p13.add(new JLabel(Bundle.getMessage("DelayedStart"))); 539 p13.add(delayedStartBox); 540 delayedStartBox.setToolTipText(Bundle.getMessage("DelayedStartHint")); 541 delayedStartBox.addActionListener(this::handleDelayStartClick); 542 p13.add(departureTimeLabel); 543 departureHrSpinner.setEditor(new JSpinner.NumberEditor(departureHrSpinner, "00")); 544 p13.add(departureHrSpinner); 545 departureHrSpinner.setValue(8); 546 departureHrSpinner.setToolTipText(Bundle.getMessage("DepartureTimeHrHint")); 547 p13.add(departureSepLabel); 548 departureMinSpinner.setEditor(new JSpinner.NumberEditor(departureMinSpinner, "00")); 549 p13.add(departureMinSpinner); 550 departureMinSpinner.setValue(0); 551 departureMinSpinner.setToolTipText(Bundle.getMessage("DepartureTimeMinHint")); 552 p13.add(delaySensor); 553 delaySensor.setAllowNull(true); 554 p13.add(resetStartSensorBox); 555 resetStartSensorBox.setToolTipText(Bundle.getMessage("ResetStartSensorHint")); 556 resetStartSensorBox.setSelected(true); 557 handleDelayStartClick(null); 558 initiatePane.add(p13); 559 560 // Load at startup option 561 JPanel p14 = new JPanel(); 562 p14.setLayout(new FlowLayout()); 563 p14.add(loadAtStartupBox); 564 loadAtStartupBox.setToolTipText(Bundle.getMessage("LoadAtStartupBoxHint")); 565 loadAtStartupBox.setSelected(false); 566 initiatePane.add(p14); 567 568 // Auto run option 569 initiatePane.add(new JSeparator()); 570 JPanel p15 = new JPanel(); 571 p15.add(autoRunBox); 572 autoRunBox.addActionListener( ev -> handleAutoRunClick()); 573 autoRunBox.setToolTipText(Bundle.getMessage("AutoRunBoxHint")); 574 autoRunBox.setSelected(false); 575 initiatePane.add(p15); 576 initializeAutoRunItems(); 577 578 // Footer buttons 579 JPanel ftr = new JPanel(); 580 JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel")); 581 ftr.add(cancelButton); 582 cancelButton.addActionListener( ev -> cancelInitiateTrain()); 583 cancelButton.setToolTipText(Bundle.getMessage("CancelButtonHint")); 584 ftr.add(addNewTrainButton = new JButton(Bundle.getMessage("ButtonCreate"))); 585 addNewTrainButton.addActionListener( e1 -> addNewTrain()); 586 addNewTrainButton.setToolTipText(Bundle.getMessage("AddNewTrainButtonHint")); 587 588 JPanel mainPane = new JPanel(new BorderLayout()); 589 JScrollPane scrPane = new JScrollPane(initiatePane); 590 mainPane.add(hdr, BorderLayout.NORTH); 591 mainPane.add(scrPane, BorderLayout.CENTER); 592 mainPane.add(ftr, BorderLayout.SOUTH); 593 initiateFrame.setContentPane(mainPane); 594 switch (trainInfo.getTrainsFrom()) { 595 case TRAINSFROMROSTER: 596 radioTrainsFromRoster.setSelected(true); 597 break; 598 case TRAINSFROMOPS: 599 radioTrainsFromOps.setSelected(true); 600 break; 601 case TRAINSFROMUSER: 602 radioTrainsFromUser.setSelected(true); 603 break; 604 case TRAINSFROMSETLATER: 605 default: 606 radioTrainsFromSetLater.setSelected(true); 607 } 608 609 } 610 autoRunBox.setSelected(false); 611 loadAtStartupBox.setSelected(false); 612 initializeFreeTransitsCombo(new ArrayList<>()); 613 refreshNextTrainCombo(); 614 setTrainsFromOptions(trainInfo.getTrainsFrom()); 615 initiateFrame.pack(); 616 initiateFrame.setVisible(true); 617 618 trainInfoToDialog(trainInfo); 619 } 620 621 private void refreshNextTrainCombo() { 622 Object saveEntry = null; 623 if (nextTrain.getSelectedIndex() > 0) { 624 saveEntry=nextTrain.getSelectedItem(); 625 } 626 nextTrain.removeAllItems(); 627 nextTrain.addItem(" "); 628 for (String file: _tiFile.getTrainInfoFileNames()) { 629 nextTrain.addItem(file); 630 } 631 if (saveEntry != null) { 632 nextTrain.setSelectedItem(saveEntry); 633 } 634 } 635 636 private void setTrainsFromOptions(TrainsFrom transFrom) { 637 switch (transFrom) { 638 case TRAINSFROMROSTER: 639 initializeFreeRosterEntriesCombo(); 640 rosterComboBox.setVisible(true); 641 trainSelectBox.setVisible(false); 642 trainFieldLabel.setVisible(true); 643 trainNameField.setVisible(true); 644 dccAddressFieldLabel.setVisible(false); 645 dccAddressSpinner.setVisible(false); 646 break; 647 case TRAINSFROMOPS: 648 initializeFreeTrainsCombo(); 649 trainSelectBox.setVisible(true); 650 rosterComboBox.setVisible(false); 651 trainFieldLabel.setVisible(true); 652 trainNameField.setVisible(true); 653 dccAddressFieldLabel.setVisible(true); 654 dccAddressSpinner.setVisible(true); 655 setSpeedProfileOptions(trainInfo,false); 656 break; 657 case TRAINSFROMUSER: 658 trainNameField.setText(""); 659 trainSelectBox.setVisible(false); 660 rosterComboBox.setVisible(false); 661 trainFieldLabel.setVisible(true); 662 trainNameField.setVisible(true); 663 dccAddressFieldLabel.setVisible(true); 664 dccAddressSpinner.setVisible(true); 665 dccAddressSpinner.setEnabled(true); 666 setSpeedProfileOptions(trainInfo,false); 667 break; 668 case TRAINSFROMSETLATER: 669 default: 670 rosterComboBox.setVisible(false); 671 trainSelectBox.setVisible(false); 672 trainFieldLabel.setVisible(true); 673 trainNameField.setVisible(true); 674 dccAddressFieldLabel.setVisible(false); 675 dccAddressSpinner.setVisible(false); 676 } 677 } 678 679 private void initializeTrainTypeBox() { 680 trainTypeBox.removeAllItems(); 681 trainTypeBox.addItem("<" + Bundle.getMessage("None").toLowerCase() + ">"); // <none> 682 trainTypeBox.addItem(Bundle.getMessage("LOCAL_PASSENGER")); 683 trainTypeBox.addItem(Bundle.getMessage("LOCAL_FREIGHT")); 684 trainTypeBox.addItem(Bundle.getMessage("THROUGH_PASSENGER")); 685 trainTypeBox.addItem(Bundle.getMessage("THROUGH_FREIGHT")); 686 trainTypeBox.addItem(Bundle.getMessage("EXPRESS_PASSENGER")); 687 trainTypeBox.addItem(Bundle.getMessage("EXPRESS_FREIGHT")); 688 trainTypeBox.addItem(Bundle.getMessage("MOW")); 689 // NOTE: The above must correspond in order and name to definitions in ActiveTrain.java. 690 } 691 692 private void initializeTrainDetectionBox() { 693 trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionWholeTrain"),TrainDetection.TRAINDETECTION_WHOLETRAIN)); 694 trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadAndTail"),TrainDetection.TRAINDETECTION_HEADANDTAIL)); 695 trainDetectionComboBox.addItem(new TrainDetectionItem(Bundle.getMessage("TrainDetectionHeadOnly"),TrainDetection.TRAINDETECTION_HEADONLY)); 696 } 697 698 private void initializeScaleLengthBox() { 699 trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleFeet"), TrainLengthUnits.TRAINLENGTH_SCALEFEET)); 700 trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInScaleMeters"), TrainLengthUnits.TRAINLENGTH_SCALEMETERS)); 701 trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualInchs"), TrainLengthUnits.TRAINLENGTH_ACTUALINCHS)); 702 trainLengthUnitsComboBox.addItem(new TrainLengthUnitsItem(Bundle.getMessage("TrainLengthInActualcm"), TrainLengthUnits.TRAINLENGTH_ACTUALCM)); 703 } 704 705 private void handleTransitSelectionChanged(ActionEvent e) { 706 int index = transitSelectBox.getSelectedIndex(); 707 if (index < 0) { 708 return; 709 } 710 Transit t = transitSelectBox.getSelectedItem(); 711 if ((t != null) && (t != selectedTransit)) { 712 selectedTransit = t; 713 initializeStartingBlockCombo(); 714 initializeDestinationBlockCombo(); 715 initiateFrame.pack(); 716 } 717 } 718 719 private void handleInTransitClick() { 720 if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) { 721 JmriJOptionPane.showMessageDialog(initiateFrame, Bundle 722 .getMessage("NoEntryBlocks"), Bundle.getMessage("MessageTitle"), 723 JmriJOptionPane.INFORMATION_MESSAGE); 724 inTransitBox.setSelected(true); 725 } 726 initializeStartingBlockCombo(); 727 initializeDestinationBlockCombo(); 728 initiateFrame.pack(); 729 } 730 731 private void handleTrainSelectionChanged() { 732 if (!trainsFromButtonGroup.getSelection().getActionCommand().equals("TRAINSFROMOPS")) { 733 return; 734 } 735 int ix = trainSelectBox.getSelectedIndex(); 736 if (ix < 1) { // no train selected 737 dccAddressSpinner.setEnabled(false); 738 return; 739 } 740 dccAddressSpinner.setEnabled(true); 741 int dccAddress; 742 try { 743 dccAddress = Integer.parseInt((((Train) trainSelectBox.getSelectedItem()).getLeadEngineDccAddress())); 744 } catch (NumberFormatException ex) { 745 JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error43"), 746 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 747 return; 748 } 749 dccAddressSpinner.setValue (dccAddress); 750 trainNameField.setText(((Train) trainSelectBox.getSelectedItem()).getName()); 751 } 752 753 private void handleRosterSelectionChanged(ActionEvent e) { 754 if (!trainsFromButtonGroup.getSelection().getActionCommand().equals("TRAINSFROMROSTER")) { 755 return; 756 } 757 int ix = rosterComboBox.getSelectedIndex(); 758 if (ix > 0) { // first item is "Select Loco" string 759 RosterEntry r = (RosterEntry) rosterComboBox.getItemAt(ix); 760 // check to see if speed profile exists and is not empty 761 if (r.getSpeedProfile() == null || r.getSpeedProfile().getProfileSize() < 1) { 762 // disable profile boxes etc. 763 setSpeedProfileOptions(trainInfo,false); 764 } else { 765 // enable profile boxes 766 setSpeedProfileOptions(trainInfo,true); 767 } 768 maxSpeedSpinner.setValue(r.getMaxSpeedPCT()/100.0f); 769 trainNameField.setText(r.titleString()); 770 if (r.getAttribute("DispatcherTrainType") != null && !r.getAttribute("DispatcherTrainType").equals("")) { 771 trainTypeBox.setSelectedItem(r.getAttribute("DispatcherTrainType")); 772 } 773 } else { 774 setSpeedProfileOptions(trainInfo,false); 775 } 776 } 777 778 private void handleDelayStartClick(ActionEvent e) { 779 departureHrSpinner.setVisible(false); 780 departureMinSpinner.setVisible(false); 781 departureTimeLabel.setVisible(false); 782 departureSepLabel.setVisible(false); 783 delaySensor.setVisible(false); 784 resetStartSensorBox.setVisible(false); 785 if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) { 786 departureHrSpinner.setVisible(true); 787 departureMinSpinner.setVisible(true); 788 departureTimeLabel.setVisible(true); 789 departureSepLabel.setVisible(true); 790 } else if (delayedStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) { 791 delaySensor.setVisible(true); 792 resetStartSensorBox.setVisible(true); 793 } 794 initiateFrame.pack(); // to fit extra hh:mm in window 795 } 796 797 private void handleResetWhenDoneClick() { 798 delayMinSpinner.setVisible(false); 799 delayMinLabel.setVisible(false); 800 delayedReStartLabel.setVisible(false); 801 delayedReStartBox.setVisible(false); 802 delayReStartSensorLabel.setVisible(false); 803 delayReStartSensor.setVisible(false); 804 resetRestartSensorBox.setVisible(false); 805 if (resetWhenDoneBox.isSelected()) { 806 delayedReStartLabel.setVisible(true); 807 delayedReStartBox.setVisible(true); 808 terminateWhenDoneBox.setSelected(false); 809 if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) { 810 delayMinSpinner.setVisible(true); 811 delayMinLabel.setVisible(true); 812 } else if (delayedReStartBox.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) { 813 delayReStartSensor.setVisible(true); 814 delayReStartSensorLabel.setVisible(true); 815 resetRestartSensorBox.setVisible(true); 816 } 817 } else { 818 terminateWhenDoneBox.setEnabled(true); 819 } 820 initiateFrame.pack(); 821 } 822 823 private void handleTerminateWhenDoneBoxClick() { 824 if (terminateWhenDoneBox.isSelected()) { 825 refreshNextTrainCombo(); 826 resetWhenDoneBox.setSelected(false); 827 terminateWhenDoneDetails.setVisible(true); 828 } else { 829 terminateWhenDoneDetails.setVisible(false); 830 } 831 } 832 833 private void handleReverseAtEndBoxClick() { 834 delayReverseMinSpinner.setVisible(false); 835 delayReverseMinLabel.setVisible(false); 836 delayReverseReStartLabel.setVisible(false); 837 reverseDelayedRestartType.setVisible(false); 838 delayReverseReStartSensorLabel.setVisible(false); 839 delayReverseReStartSensor.setVisible(false); 840 delayReverseResetSensorBox.setVisible(false); 841 if (reverseAtEndBox.isSelected()) { 842 delayReverseReStartLabel.setVisible(true); 843 reverseDelayedRestartType.setVisible(true); 844 if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartTimed"))) { 845 delayReverseMinSpinner.setVisible(true); 846 delayReverseMinLabel.setVisible(true); 847 } else if (reverseDelayedRestartType.getSelectedItem().equals(Bundle.getMessage("DelayedStartSensor"))) { 848 delayReverseReStartSensor.setVisible(true); 849 delayReStartSensorLabel.setVisible(true); 850 delayReverseResetSensorBox.setVisible(true); 851 } 852 } 853 initiateFrame.pack(); 854 855 if (resetWhenDoneBox.isSelected()) { 856 terminateWhenDoneBox.setSelected(false); 857 terminateWhenDoneBox.setEnabled(false); 858 } else { 859 terminateWhenDoneBox.setEnabled(true); 860 } 861 } 862 863 private void handleAutoRunClick() { 864 showHideAutoRunItems(autoRunBox.isSelected()); 865 initiateFrame.pack(); 866 } 867 868 private void handleStartingBlockSelectionChanged() { 869 if (radioTransitsAdHoc.isSelected() ) { 870 initializeViaBlockDynamicCombo(); 871 initializeDestinationBlockDynamicCombo(); 872 } else { 873 initializeDestinationBlockCombo(); 874 } 875 initiateFrame.pack(); 876 } 877 878 private void handleViaBlockSelectionChanged() { 879 if (radioTransitsAdHoc.isSelected() ) { 880 initializeDestinationBlockDynamicCombo(); 881 } else { 882 initializeDestinationBlockCombo(); 883 } 884 initiateFrame.pack(); 885 } 886 887 private void handleAllocateAllTheWayButtonChanged() { 888 allocateCustomSpinner.setVisible(false); 889 } 890 891 private void handleAllocateBySafeButtonChanged() { 892 allocateCustomSpinner.setVisible(false); 893 } 894 895 private void handleAllocateNumberOfBlocksButtonChanged() { 896 allocateCustomSpinner.setVisible(true); 897 } 898 899 private void cancelInitiateTrain() { 900 _dispatcher.newTrainDone(null); 901 } 902 903 /* 904 * Handles press of "Add New Train" button. 905 * Move data to TrainInfo validating basic information 906 * Call dispatcher to start the train from traininfo which 907 * completes validation. 908 */ 909 private void addNewTrain() { 910 try { 911 validateDialog(); 912 trainInfo = new TrainInfo(); 913 dialogToTrainInfo(trainInfo); 914 if (radioTransitsAdHoc.isSelected()) { 915 int ixStart, ixEnd, ixVia; 916 ixStart = startingBlockBox.getSelectedIndex(); 917 ixEnd = destinationBlockBox.getSelectedIndex(); 918 ixVia = viaBlockBox.getSelectedIndex(); 919 // search for a transit if ones available. 920 Transit tmpTransit = null; 921 int routeCount = 9999; 922 int startBlockSeq = 0; 923 int endBlockSeq = 0; 924 log.debug("Start[{}]Via[{}]Dest[{}}]", 925 startingBlockBoxList.get(ixStart).getDisplayName(), 926 viaBlockBoxList.get(ixVia).getDisplayName(), 927 destinationBlockBoxList.get(ixEnd).getDisplayName()); 928 for (Transit tr : InstanceManager.getDefault(jmri.TransitManager.class) 929 .getListUsingBlock(startingBlockBoxList.get(ixStart))) { 930 if (tr.getState() == Transit.IDLE 931 && tr.containsBlock(startingBlockBoxList.get(ixStart)) 932 && tr.containsBlock(viaBlockBoxList.get(ixVia)) && 933 tr.containsBlock(destinationBlockBoxList.get(ixEnd))) { 934 log.debug("[{}] contains all blocks", tr.getDisplayName()); 935 int ixCountStart = -1, ixCountVia = -1, ixCountDest = -1, ixCount = 0; 936 List<Block> transitBlocks = tr.getInternalBlocksList(); 937 List<Integer> transitBlockSeq = tr.getBlockSeqList(); 938 for (Block blk : transitBlocks) { 939 log.debug("Checking Block[{}] t[{}] BlockSequ[{}]", 940 blk.getDisplayName(), 941 ixCount, 942 transitBlockSeq.get(ixCount)); 943 if (ixCountStart == -1 && blk == startingBlockBoxList.get(ixStart)) { 944 log.trace("ixOne[{}]block[{}]",ixCount,blk.getDisplayName()); 945 ixCountStart = ixCount; 946 } else if (ixCountStart != -1 && ixCountVia == -1 && blk == viaBlockBoxList.get(ixVia)) { 947 log.trace("ixTwo[{}]block[{}]",ixCount,blk.getDisplayName()); 948 if (ixCount != ixCountStart + 1) { 949 log.debug("AdHoc {}:via and start not ajacent",tr.getDisplayName()); 950 break; 951 } 952 ixCountVia = ixCount; 953 } else if (ixCountStart != -1 && ixCountVia != -1 && ixCountDest == -1 && blk == destinationBlockBoxList.get(ixEnd)) { 954 ixCountDest = ixCount; 955 log.trace("ixThree[{}]block[{}]",ixCountDest,blk.getDisplayName()); 956 break; 957 } 958 ixCount++; 959 } 960 if (ixCountVia == (ixCountStart + 1) && ixCountDest > ixCountStart) { 961 log.debug("Canuse [{}", tr.getDisplayName()); 962 Integer routeBlockLength = 963 transitBlockSeq.get(ixCountDest) - transitBlockSeq.get(ixCountStart); 964 if (routeBlockLength < routeCount) { 965 routeCount = ixCountDest - ixCountStart; 966 tmpTransit = tr; 967 startBlockSeq = transitBlockSeq.get(ixCountStart).intValue(); 968 endBlockSeq = transitBlockSeq.get(ixCountDest).intValue(); 969 } 970 } 971 } 972 } 973 if (tmpTransit != null && 974 (JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("Question6",tmpTransit.getDisplayName()), 975 "Question", 976 JmriJOptionPane.YES_NO_OPTION, 977 JmriJOptionPane.QUESTION_MESSAGE) == JmriJOptionPane.YES_OPTION)) { 978 // use transit found 979 trainInfo.setDynamicTransit(false); 980 trainInfo.setTransitName(tmpTransit.getDisplayName()); 981 trainInfo.setTransitId(tmpTransit.getDisplayName()); 982 trainInfo.setStartBlockSeq(startBlockSeq); 983 trainInfo.setStartBlockName(getBlockName(startingBlockBoxList.get(ixStart)) + "-" + startBlockSeq); 984 trainInfo.setDestinationBlockSeq(endBlockSeq); 985 trainInfo.setDestinationBlockName(getBlockName(destinationBlockBoxList.get(ixEnd)) + "-" + endBlockSeq); 986 trainInfoToDialog(trainInfo); 987 } else { 988 // use a true ad-hoc 989 List<LayoutBlock> blockList = _dispatcher.getAdHocRoute(startingBlockBoxList.get(ixStart), 990 destinationBlockBoxList.get(ixEnd), 991 viaBlockBoxList.get(ixVia)); 992 if (blockList == null) { 993 JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error51"), 994 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 995 return; 996 } 997 } 998 } 999 _dispatcher.loadTrainFromTrainInfoThrowsException(trainInfo,"NONE",""); 1000 } catch (IllegalArgumentException ex) { 1001 JmriJOptionPane.showMessageDialog(initiateFrame, ex.getMessage(), 1002 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 1003 } 1004 } 1005 1006 private void initializeFreeTransitsCombo(List<Transit> transitList) { 1007 Set<Transit> excludeTransits = new HashSet<>(); 1008 for (Transit t : _TransitManager.getNamedBeanSet()) { 1009 if (t.getState() != Transit.IDLE) { 1010 excludeTransits.add(t); 1011 } 1012 } 1013 transitSelectBox.setExcludedItems(excludeTransits); 1014 JComboBoxUtil.setupComboBoxMaxRows(transitSelectBox); 1015 1016 if (transitSelectBox.getItemCount() > 0) { 1017 transitSelectBox.setSelectedIndex(0); 1018 selectedTransit = transitSelectBox.getItemAt(0); 1019 } else { 1020 selectedTransit = null; 1021 } 1022 } 1023 1024 private void initializeFreeRosterEntriesCombo() { 1025 rosterComboBox.update(); 1026 // remove used entries 1027 for (int ix = rosterComboBox.getItemCount() - 1; ix > 1; ix--) { // remove from back first item is the "select loco" message 1028 if ( !_dispatcher.isAddressFree( ((RosterEntry)rosterComboBox.getItemAt(ix)).getDccLocoAddress().getNumber() ) ) { 1029 rosterComboBox.removeItemAt(ix); 1030 } 1031 } 1032 } 1033 1034 private void initializeFreeTrainsCombo() { 1035 Train prevValue = null; 1036 if (trainSelectBox.getSelectedIndex() > 0) { 1037 // item zero is a string 1038 prevValue = (Train)trainSelectBox.getSelectedItem(); 1039 } 1040 ActionListener[] als = trainSelectBox.getActionListeners(); 1041 for ( ActionListener al: als) { 1042 trainSelectBox.removeActionListener(al); 1043 } 1044 trainSelectBox.removeAllItems(); 1045 trainSelectBox.addItem("Select Train"); 1046 // initialize free trains from operations 1047 List<Train> trains = InstanceManager.getDefault(TrainManager.class).getTrainsByNameList(); 1048 if (trains.size() > 0) { 1049 for (int i = 0; i < trains.size(); i++) { 1050 Train t = trains.get(i); 1051 if (t != null) { 1052 String tName = t.getName(); 1053 if (_dispatcher.isTrainFree(tName)) { 1054 trainSelectBox.addItem(t); 1055 } 1056 } 1057 } 1058 } 1059 if (prevValue != null) { 1060 trainSelectBox.setSelectedItem(prevValue); 1061 } 1062 for ( ActionListener al: als) { 1063 trainSelectBox.addActionListener(al); 1064 } 1065 } 1066 1067 /** 1068 * Sets the labels and inputs for speed profile running 1069 * @param b True if the roster entry has valid speed profile else false 1070 */ 1071 private void setSpeedProfileOptions(TrainInfo info,boolean b) { 1072 useSpeedProfileLabel.setEnabled(b); 1073 useSpeedProfileCheckBox.setEnabled(b); 1074 stopBySpeedProfileLabel.setEnabled(b); 1075 stopBySpeedProfileCheckBox.setEnabled(b); 1076 stopBySpeedProfileAdjustLabel.setEnabled(b); 1077 stopBySpeedProfileAdjustSpinner.setEnabled(b); 1078 if (!b) { 1079 useSpeedProfileCheckBox.setSelected(false); 1080 stopBySpeedProfileCheckBox.setSelected(false); 1081 1082 } 1083 } 1084 1085 private void initializeStartingBlockCombo() { 1086 String prevValue = (String)startingBlockBox.getSelectedItem(); 1087 startingBlockBox.removeAllItems(); 1088 startingBlockBoxList.clear(); 1089 if (!inTransitBox.isSelected() && selectedTransit.getEntryBlocksList().isEmpty()) { 1090 inTransitBox.setSelected(true); 1091 } 1092 if (inTransitBox.isSelected()) { 1093 startingBlockBoxList = selectedTransit.getInternalBlocksList(); 1094 } else { 1095 startingBlockBoxList = selectedTransit.getEntryBlocksList(); 1096 } 1097 startingBlockSeqList = selectedTransit.getBlockSeqList(); 1098 boolean found = false; 1099 for (int i = 0; i < startingBlockBoxList.size(); i++) { 1100 Block b = startingBlockBoxList.get(i); 1101 int seq = startingBlockSeqList.get(i).intValue(); 1102 startingBlockBox.addItem(getBlockName(b) + "-" + seq); 1103 if (!found && b.getState() == Block.OCCUPIED) { 1104 startingBlockBox.setSelectedItem(getBlockName(b) + "-" + seq); 1105 found = true; 1106 } 1107 } 1108 if (prevValue != null) { 1109 startingBlockBox.setSelectedItem(prevValue); 1110 } 1111 JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox); 1112 } 1113 1114 private void initializeDestinationBlockCombo() { 1115 String prevValue = (String)destinationBlockBox.getSelectedItem(); 1116 destinationBlockBox.removeAllItems(); 1117 destinationBlockBoxList.clear(); 1118 int index = startingBlockBox.getSelectedIndex(); 1119 if (index < 0) { 1120 return; 1121 } 1122 Block startBlock = startingBlockBoxList.get(index); 1123 destinationBlockBoxList = selectedTransit.getDestinationBlocksList( 1124 startBlock, inTransitBox.isSelected()); 1125 destinationBlockSeqList = selectedTransit.getDestBlocksSeqList(); 1126 for (int i = 0; i < destinationBlockBoxList.size(); i++) { 1127 Block b = destinationBlockBoxList.get(i); 1128 String bName = getBlockName(b); 1129 if (selectedTransit.getBlockCount(b) > 1) { 1130 int seq = destinationBlockSeqList.get(i).intValue(); 1131 bName = bName + "-" + seq; 1132 } 1133 destinationBlockBox.addItem(bName); 1134 } 1135 if (prevValue != null) { 1136 destinationBlockBox.setSelectedItem(prevValue); 1137 } 1138 JComboBoxUtil.setupComboBoxMaxRows(destinationBlockBox); 1139 } 1140 1141 private String getBlockName(Block b) { 1142 if (b != null) { 1143 return b.getDisplayName(); 1144 } 1145 return " "; 1146 } 1147 1148 protected void showActivateFrame() { 1149 if (initiateFrame != null) { 1150 initializeFreeTransitsCombo(new ArrayList<>()); 1151 initiateFrame.setVisible(true); 1152 } else { 1153 _dispatcher.newTrainDone(null); 1154 } 1155 } 1156 1157 /** 1158 * Show the Frame. 1159 * @param re currently unused. 1160 */ 1161 public void showActivateFrame(RosterEntry re) { 1162 showActivateFrame(); 1163 } 1164 1165 protected void loadTrainInfo(ActionEvent e) { 1166 List<TrainInfoFileSummary> names = _tiFile.getTrainInfoFileSummaries(); 1167 if (!names.isEmpty()) { 1168 JTable table = new JTable(){ 1169 @Override 1170 public Dimension getPreferredScrollableViewportSize() { 1171 return new Dimension(super.getPreferredSize().width, 1172 super.getPreferredScrollableViewportSize().height); 1173 } 1174 }; 1175 DefaultTableModel tm = new DefaultTableModel( 1176 new Object[]{ 1177 Bundle.getMessage("FileNameColumnTitle"), 1178 Bundle.getMessage("TrainColumnTitle"), 1179 Bundle.getMessage("TransitColumnTitle"), 1180 Bundle.getMessage("StartBlockColumnTitle"), 1181 Bundle.getMessage("EndBlockColumnTitle"), 1182 Bundle.getMessage("DccColumnTitleColumnTitle") 1183 }, 0) { 1184 @Override 1185 public boolean isCellEditable(int row, int column) { 1186 //all cells false 1187 return false; 1188 } 1189 }; 1190 1191 table.setModel(tm); 1192 for (TrainInfoFileSummary fs: names) { 1193 tm.addRow(new Object[] {fs.getFileName(),fs.getTrainName(), 1194 fs.getTransitName(),fs.getStartBlockName() 1195 ,fs.getEndBlockName(),fs.getDccAddress()}); 1196 } 1197 JPanel jp = new JPanel(new BorderLayout()); 1198 TableColumnModel columnModel = table.getColumnModel(); 1199 table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF ); 1200 for (int column = 0; column < table.getColumnCount(); column++) { 1201 int width = 30; // Min width 1202 for (int row = 0; row < table.getRowCount(); row++) { 1203 TableCellRenderer renderer = table.getCellRenderer(row, column); 1204 Component comp = table.prepareRenderer(renderer, row, column); 1205 width = Math.max(comp.getPreferredSize().width +1 , width); 1206 } 1207 if(width > 300) 1208 width=300; 1209 columnModel.getColumn(column).setPreferredWidth(width); 1210 } 1211 //jp.setPreferredSize(table.getPreferredSize()); 1212 jp.add(table); 1213 JScrollPane sp = new JScrollPane(table, 1214 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 1215 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); 1216 int optionSelected = JmriJOptionPane.showOptionDialog(initiateFrame, 1217 sp, Bundle.getMessage("LoadTrainTitle"), JmriJOptionPane.OK_CANCEL_OPTION, JmriJOptionPane.PLAIN_MESSAGE, 1218 null,null,null); 1219 if (optionSelected != JmriJOptionPane.OK_OPTION) { 1220 //Canceled 1221 return; 1222 } 1223 if (table.getSelectedRow() < 0) { 1224 return; 1225 } 1226 String selName = (String)table.getModel().getValueAt(table.getSelectedRow(),0); 1227 if ((selName == null) || (selName.isEmpty())) { 1228 return; 1229 } 1230 //read xml data from selected filename and move it into the new train dialog box 1231 _trainInfoName = selName; 1232 try { 1233 trainInfo = _tiFile.readTrainInfo( selName); 1234 if (trainInfo != null) { 1235 // process the information just read 1236 trainInfoToDialog(trainInfo); 1237 } 1238 } catch (java.io.IOException ioe) { 1239 log.error("IO Exception when reading train info file", ioe); 1240 } catch (org.jdom2.JDOMException jde) { 1241 log.error("JDOM Exception when reading train info file", jde); 1242 } 1243 handleDelayStartClick(null); 1244 handleReverseAtEndBoxClick(); 1245 } 1246 } 1247 1248 private void saveTrainInfo() { 1249 saveTrainInfo(false); 1250 refreshNextTrainCombo(); 1251 } 1252 1253 private void saveTrainInfoAsTemplate() { 1254 saveTrainInfo(true); 1255 } 1256 1257 private void saveTrainInfo(boolean asTemplate) { 1258 try { 1259 dialogToTrainInfo(trainInfo); 1260 } catch (IllegalArgumentException ide) { 1261 JmriJOptionPane.showMessageDialog(initiateFrame, ide.getMessage(), 1262 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 1263 return; 1264 } 1265 // get file name 1266 String fileName; 1267 if (asTemplate) { 1268 fileName = normalizeXmlFileName(nameOfTemplateFile); 1269 } else { 1270 String eName = JmriJOptionPane.showInputDialog(initiateFrame, 1271 Bundle.getMessage("EnterFileName") + " :", _trainInfoName); 1272 if (eName == null) { //Cancel pressed 1273 return; 1274 } 1275 if (eName.length() < 1) { 1276 JmriJOptionPane.showMessageDialog(initiateFrame, Bundle.getMessage("Error25"), 1277 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 1278 return; 1279 } 1280 fileName = normalizeXmlFileName(eName); 1281 _trainInfoName = fileName; 1282 } 1283 // check if train info file name is in use 1284 String[] names = _tiFile.getTrainInfoFileNames(); 1285 if (names.length > 0) { 1286 boolean found = false; 1287 for (int i = 0; i < names.length; i++) { 1288 if (fileName.equals(names[i])) { 1289 found = true; 1290 } 1291 } 1292 if (found) { 1293 // file by that name is already present 1294 int selectedValue = JmriJOptionPane.showOptionDialog(initiateFrame, 1295 Bundle.getMessage("Question3", fileName), 1296 Bundle.getMessage("WarningTitle"), JmriJOptionPane.DEFAULT_OPTION, 1297 JmriJOptionPane.QUESTION_MESSAGE, null, 1298 new Object[]{Bundle.getMessage("ButtonReplace"),Bundle.getMessage("ButtonNo")}, 1299 Bundle.getMessage("ButtonNo")); 1300 if (selectedValue != 0 ) { // array position 0 , replace not selected 1301 return; // return without writing if "No" response 1302 } 1303 } 1304 } 1305 // write the Train Info file 1306 try { 1307 _tiFile.writeTrainInfo(trainInfo, fileName); 1308 } //catch (org.jdom2.JDOMException jde) { 1309 // log.error("JDOM exception writing Train Info: "+jde); 1310 //} 1311 catch (java.io.IOException ioe) { 1312 log.error("IO exception writing Train Info", ioe); 1313 } 1314 } 1315 1316 private void deleteTrainInfo() { 1317 String[] names = _tiFile.getTrainInfoFileNames(); 1318 if (names.length > 0) { 1319 Object selName = JmriJOptionPane.showInputDialog(initiateFrame, 1320 Bundle.getMessage("DeleteTrainChoice"), Bundle.getMessage("DeleteTrainTitle"), 1321 JmriJOptionPane.QUESTION_MESSAGE, null, names, names[0]); 1322 if ((selName == null) || (((String) selName).isEmpty())) { 1323 return; 1324 } 1325 _tiFile.deleteTrainInfoFile((String) selName); 1326 } 1327 } 1328 1329 private void trainInfoToDialog(TrainInfo info) { 1330 if (!info.getDynamicTransit()) { 1331 radioTransitsPredefined.setSelected(true); 1332 if (!info.getTransitName().isEmpty()) { 1333 try { 1334 transitSelectBox.setSelectedItemByName(info.getTransitName()); 1335 } catch (Exception ex) { 1336 log.warn("Transit {} from file not in Transit menu", info.getTransitName()); 1337 JmriJOptionPane.showMessageDialog(initiateFrame, 1338 Bundle.getMessage("TransitWarn", info.getTransitName()), 1339 null, JmriJOptionPane.WARNING_MESSAGE); 1340 } 1341 } 1342 } else { 1343 radioTransitsAdHoc.setSelected(true); 1344 } 1345 switch (info.getTrainsFrom()) { 1346 case TRAINSFROMROSTER: 1347 radioTrainsFromRoster.setSelected(true); 1348 if (!info.getRosterId().isEmpty()) { 1349 if (!setRosterComboBox(rosterComboBox, info.getRosterId())) { 1350 log.warn("Roster {} from file not in Roster Combo", info.getRosterId()); 1351 JmriJOptionPane.showMessageDialog(initiateFrame, 1352 Bundle.getMessage("TrainWarn", info.getRosterId()), 1353 null, JmriJOptionPane.WARNING_MESSAGE); 1354 } 1355 } 1356 break; 1357 case TRAINSFROMOPS: 1358 radioTrainsFromOps.setSelected(true); 1359 if (!info.getTrainName().isEmpty()) { 1360 if (!setTrainComboBox(trainSelectBox, info.getTrainName())) { 1361 log.warn("Train {} from file not in Train Combo", info.getTrainName()); 1362 JmriJOptionPane.showMessageDialog(initiateFrame, 1363 Bundle.getMessage("TrainWarn", info.getTrainName()), 1364 null, JmriJOptionPane.WARNING_MESSAGE); 1365 } 1366 } 1367 break; 1368 case TRAINSFROMUSER: 1369 radioTrainsFromUser.setSelected(true); 1370 dccAddressSpinner.setValue(Integer.valueOf(info.getDccAddress())); 1371 break; 1372 case TRAINSFROMSETLATER: 1373 default: 1374 radioTrainsFromSetLater.setSelected(true); 1375 } 1376 trainNameField.setText(info.getTrainUserName()); 1377 trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection()); 1378 inTransitBox.setSelected(info.getTrainInTransit()); 1379 if (radioTransitsAdHoc.isSelected()) { 1380 initializeStartingBlockComboDynamic(); 1381 } else { 1382 initializeStartingBlockCombo(); 1383 } 1384 setComboBox(startingBlockBox, info.getStartBlockName()); 1385 if (radioTransitsAdHoc.isSelected()) { 1386 initializeViaBlockDynamicCombo(); 1387 setComboBox(viaBlockBox, info.getViaBlockName()); 1388 } 1389 if (radioTransitsAdHoc.isSelected()) { 1390 initializeDestinationBlockDynamicCombo(); 1391 } else { 1392 initializeDestinationBlockCombo(); 1393 } 1394 setComboBox(destinationBlockBox, info.getDestinationBlockName()); 1395 1396 setAllocateMethodButtons(info.getAllocationMethod()); 1397 prioritySpinner.setValue(info.getPriority()); 1398 resetWhenDoneBox.setSelected(info.getResetWhenDone()); 1399 reverseAtEndBox.setSelected(info.getReverseAtEnd()); 1400 setDelayModeBox(info.getDelayedStart(), delayedStartBox); 1401 //delayedStartBox.setSelected(info.getDelayedStart()); 1402 departureHrSpinner.setValue(info.getDepartureTimeHr()); 1403 departureMinSpinner.setValue(info.getDepartureTimeMin()); 1404 delaySensor.setSelectedItem(info.getDelaySensor()); 1405 resetStartSensorBox.setSelected(info.getResetStartSensor()); 1406 setDelayModeBox(info.getDelayedRestart(), delayedReStartBox); 1407 delayMinSpinner.setValue(info.getRestartDelayMin()); 1408 delayReStartSensor.setSelectedItem(info.getRestartSensor()); 1409 resetRestartSensorBox.setSelected(info.getResetRestartSensor()); 1410 1411 resetStartSensorBox.setSelected(info.getResetStartSensor()); 1412 setDelayModeBox(info.getReverseDelayedRestart(), reverseDelayedRestartType); 1413 delayReverseMinSpinner.setValue(info.getReverseRestartDelayMin()); 1414 delayReverseReStartSensor.setSelectedItem(info.getReverseRestartSensor()); 1415 delayReverseResetSensorBox.setSelected(info.getReverseResetRestartSensor()); 1416 1417 terminateWhenDoneBox.setSelected(info.getTerminateWhenDone()); 1418 nextTrain.setSelectedIndex(-1); 1419 try { 1420 nextTrain.setSelectedItem(info.getNextTrain()); 1421 } catch (Exception ex){ 1422 nextTrain.setSelectedIndex(-1); 1423 } 1424 handleTerminateWhenDoneBoxClick(); 1425 setComboBox(trainTypeBox, info.getTrainType()); 1426 autoRunBox.setSelected(info.getAutoRun()); 1427 loadAtStartupBox.setSelected(info.getLoadAtStartup()); 1428 setAllocateMethodButtons(info.getAllocationMethod()); 1429 autoTrainInfoToDialog(info); 1430 } 1431 1432 private boolean validateDialog() throws IllegalArgumentException { 1433 int index = transitSelectBox.getSelectedIndex(); 1434 if (index < 0) { 1435 throw new IllegalArgumentException(Bundle.getMessage("Error44")); 1436 } 1437 switch (trainsFromButtonGroup.getSelection().getActionCommand()) { 1438 case "TRAINSFROMROSTER": 1439 if (rosterComboBox.getSelectedIndex() < 1 ) { 1440 throw new IllegalArgumentException(Bundle.getMessage("Error41")); 1441 } 1442 break; 1443 case "TRAINSFROMOPS": 1444 if (trainSelectBox.getSelectedIndex() < 1) { 1445 throw new IllegalArgumentException(Bundle.getMessage("Error42")); 1446 } 1447 break; 1448 case "TRAINSFROMUSER": 1449 if (trainNameField.getText().isEmpty()) { 1450 throw new IllegalArgumentException(Bundle.getMessage("Error22")); 1451 } 1452 break; 1453 case "TRAINSFROMSETLATER": 1454 default: 1455 } 1456 index = startingBlockBox.getSelectedIndex(); 1457 if (index < 0) { 1458 throw new IllegalArgumentException(Bundle.getMessage("Error13")); 1459 } 1460 index = destinationBlockBox.getSelectedIndex(); 1461 if (index < 0) { 1462 throw new IllegalArgumentException(Bundle.getMessage("Error8")); 1463 } 1464 if (radioTransitsAdHoc.isSelected()) { 1465 index = viaBlockBox.getSelectedIndex(); 1466 if (index < 0) { 1467 throw new IllegalArgumentException(Bundle.getMessage("Error8")); 1468 } 1469 } 1470 if ((!reverseAtEndBox.isSelected()) && resetWhenDoneBox.isSelected() 1471 && (!selectedTransit.canBeResetWhenDone())) { 1472 resetWhenDoneBox.setSelected(false); 1473 throw new IllegalArgumentException(Bundle.getMessage("NoResetMessage")); 1474 } 1475 int max = Math.round((float) maxSpeedSpinner.getValue()*100.0f); 1476 int min = Math.round((float) minReliableOperatingSpeedSpinner.getValue()*100.0f); 1477 if ((max-min) < 10) { 1478 throw new IllegalArgumentException(Bundle.getMessage("Error49", 1479 maxSpeedSpinner.getValue(), minReliableOperatingSpeedSpinner.getValue())); 1480 } 1481 return true; 1482 } 1483 1484 private boolean dialogToTrainInfo(TrainInfo info) { 1485 int index = transitSelectBox.getSelectedIndex(); 1486 info.setDynamicTransit(radioTransitsAdHoc.isSelected()); 1487 if (!info.getDynamicTransit() && index >= 0 ) { 1488 info.setTransitName(transitSelectBox.getSelectedItem().getDisplayName()); 1489 info.setTransitId(transitSelectBox.getSelectedItem().getDisplayName()); 1490 } 1491 switch (trainsFromButtonGroup.getSelection().getActionCommand()) { 1492 case "TRAINSFROMROSTER": 1493 info.setRosterId(((RosterEntry) rosterComboBox.getSelectedItem()).getId()); 1494 info.setDccAddress(((RosterEntry) rosterComboBox.getSelectedItem()).getDccAddress()); 1495 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMROSTER); 1496 setTrainsFromOptions(trainInfo.getTrainsFrom()); 1497 break; 1498 case "TRAINSFROMOPS": 1499 info.setTrainName(((Train) trainSelectBox.getSelectedItem()).toString()); 1500 info.setDccAddress(String.valueOf(dccAddressSpinner.getValue())); 1501 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMOPS); 1502 setTrainsFromOptions(trainInfo.getTrainsFrom()); 1503 break; 1504 case "TRAINSFROMUSER": 1505 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMUSER); 1506 info.setDccAddress(String.valueOf(dccAddressSpinner.getValue())); 1507 break; 1508 case "TRAINSFROMSETLATER": 1509 default: 1510 trainInfo.setTrainsFrom(TrainsFrom.TRAINSFROMSETLATER); 1511 info.setTrainName(""); 1512 info.setDccAddress(""); 1513 } 1514 info.setTrainUserName(trainNameField.getText()); 1515 info.setTrainInTransit(inTransitBox.isSelected()); 1516 info.setStartBlockName((String) startingBlockBox.getSelectedItem()); 1517 index = startingBlockBox.getSelectedIndex(); 1518 info.setStartBlockId(startingBlockBoxList.get(index).getDisplayName()); 1519 if (info.getDynamicTransit()) { 1520 info.setStartBlockSeq(1); 1521 } else { 1522 info.setStartBlockSeq(startingBlockSeqList.get(index).intValue()); 1523 } 1524 index = destinationBlockBox.getSelectedIndex(); 1525 info.setDestinationBlockId(destinationBlockBoxList.get(index).getDisplayName()); 1526 info.setDestinationBlockName(destinationBlockBoxList.get(index).getDisplayName()); 1527 if (info.getDynamicTransit()) { 1528 info.setViaBlockName(viaBlockBoxList.get(viaBlockBox.getSelectedIndex()).getDisplayName()); 1529 } else { 1530 info.setDestinationBlockSeq(destinationBlockSeqList.get(index).intValue()); 1531 } 1532 info.setPriority((Integer) prioritySpinner.getValue()); 1533 info.setTrainDetection(((TrainDetectionItem)trainDetectionComboBox.getSelectedItem()).value); 1534 info.setResetWhenDone(resetWhenDoneBox.isSelected()); 1535 info.setReverseAtEnd(reverseAtEndBox.isSelected()); 1536 info.setDelayedStart(delayModeFromBox(delayedStartBox)); 1537 info.setDelaySensorName(delaySensor.getSelectedItemDisplayName()); 1538 info.setResetStartSensor(resetStartSensorBox.isSelected()); 1539 info.setDepartureTimeHr((Integer) departureHrSpinner.getValue()); 1540 info.setDepartureTimeMin((Integer) departureMinSpinner.getValue()); 1541 info.setTrainType((String) trainTypeBox.getSelectedItem()); 1542 info.setAutoRun(autoRunBox.isSelected()); 1543 info.setLoadAtStartup(loadAtStartupBox.isSelected()); 1544 info.setAllocateAllTheWay(false); // force to false next field is now used. 1545 if (allocateAllTheWayRadioButton.isSelected()) { 1546 info.setAllocationMethod(ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN); 1547 } else if (allocateBySafeRadioButton.isSelected()) { 1548 info.setAllocationMethod(ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS); 1549 } else { 1550 info.setAllocationMethod((Integer) allocateCustomSpinner.getValue()); 1551 } 1552 info.setDelayedRestart(delayModeFromBox(delayedReStartBox)); 1553 info.setRestartSensorName(delayReStartSensor.getSelectedItemDisplayName()); 1554 info.setResetRestartSensor(resetRestartSensorBox.isSelected()); 1555 info.setRestartDelayMin((Integer) delayMinSpinner.getValue()); 1556 1557 info.setReverseDelayedRestart(delayModeFromBox(reverseDelayedRestartType)); 1558 info.setReverseRestartSensorName(delayReverseReStartSensor.getSelectedItemDisplayName()); 1559 info.setReverseResetRestartSensor(delayReverseResetSensorBox.isSelected()); 1560 info.setReverseRestartDelayMin((Integer) delayReverseMinSpinner.getValue()); 1561 1562 info.setTerminateWhenDone(terminateWhenDoneBox.isSelected()); 1563 if (nextTrain.getSelectedIndex() > 0 ) { 1564 info.setNextTrain((String)nextTrain.getSelectedItem()); 1565 } else { 1566 info.setNextTrain("None"); 1567 } 1568 autoRunItemsToTrainInfo(info); 1569 return true; 1570 } 1571 1572 private boolean setRosterComboBox(RosterEntryComboBox box, String txt) { 1573 boolean found = false; 1574 for (int i = 1; i < box.getItemCount(); i++) { 1575 if (txt.equals(((RosterEntry) box.getItemAt(i)).getId())) { 1576 box.setSelectedIndex(i); 1577 found = true; 1578 break; 1579 } 1580 } 1581 if (!found && box.getItemCount() > 0) { 1582 box.setSelectedIndex(0); 1583 } 1584 return found; 1585 } 1586 1587 // Normalizes a suggested xml file name. Returns null string if a valid name cannot be assembled 1588 private String normalizeXmlFileName(String name) { 1589 if (name.length() < 1) { 1590 return ""; 1591 } 1592 String newName = name; 1593 // strip off .xml or .XML if present 1594 if ((name.endsWith(".xml")) || (name.endsWith(".XML"))) { 1595 newName = name.substring(0, name.length() - 4); 1596 if (newName.length() < 1) { 1597 return ""; 1598 } 1599 } 1600 // replace all non-alphanumeric characters with underscore 1601 newName = newName.replaceAll("[\\W]", "_"); 1602 return (newName + ".xml"); 1603 } 1604 1605 private boolean setTrainComboBox(JComboBox<Object> box, String txt) { 1606 boolean found = false; 1607 for (int i = 1; i < box.getItemCount(); i++) { //skip the select train item 1608 if (txt.equals(box.getItemAt(i).toString())) { 1609 box.setSelectedIndex(i); 1610 found = true; 1611 break; 1612 } 1613 } 1614 if (!found && box.getItemCount() > 0) { 1615 box.setSelectedIndex(0); 1616 } 1617 return found; 1618 } 1619 1620 private boolean setComboBox(JComboBox<String> box, String txt) { 1621 boolean found = false; 1622 for (int i = 0; i < box.getItemCount(); i++) { 1623 if (txt.equals(box.getItemAt(i))) { 1624 box.setSelectedIndex(i); 1625 found = true; 1626 break; 1627 } 1628 } 1629 if (!found && box.getItemCount() > 0) { 1630 box.setSelectedIndex(0); 1631 } 1632 return found; 1633 } 1634 1635 int delayModeFromBox(JComboBox<String> box) { 1636 String mode = (String) box.getSelectedItem(); 1637 int result = jmri.util.StringUtil.getStateFromName(mode, delayedStartInt, delayedStartString); 1638 1639 if (result < 0) { 1640 log.warn("unexpected mode string in turnoutMode: {}", mode); 1641 throw new IllegalArgumentException(); 1642 } 1643 return result; 1644 } 1645 1646 void setDelayModeBox(int mode, JComboBox<String> box) { 1647 String result = jmri.util.StringUtil.getNameFromState(mode, delayedStartInt, delayedStartString); 1648 box.setSelectedItem(result); 1649 } 1650 1651 /** 1652 * The following are for items that are only for automatic running of 1653 * ActiveTrains They are isolated here to simplify changing them in the 1654 * future. 1655 * <ul> 1656 * <li>initializeAutoRunItems - initializes the display of auto run items in 1657 * this window 1658 * <li>initializeAutoRunValues - initializes the values of auto run items 1659 * from values in a saved train info file hideAutoRunItems - hides all auto 1660 * run items in this window showAutoRunItems - shows all auto run items in 1661 * this window 1662 * <li>autoTrainInfoToDialog - gets auto run items from a train info, puts 1663 * values in items, and initializes auto run dialog items 1664 * <li>autoTrainItemsToTrainInfo - copies values of auto run items to train 1665 * info for saving to a file 1666 * <li>readAutoRunItems - reads and checks values of all auto run items. 1667 * returns true if OK, sends appropriate messages and returns false if not 1668 * OK 1669 * <li>setAutoRunItems - sets the user entered auto run items in the new 1670 * AutoActiveTrain 1671 * </ul> 1672 */ 1673 // auto run items in ActivateTrainFrame 1674 private final JPanel pa1 = new JPanel(); 1675 private final JLabel speedFactorLabel = new JLabel(Bundle.getMessage("SpeedFactorLabel")); 1676 private final JSpinner speedFactorSpinner = new JSpinner(); 1677 private final JLabel minReliableOperatingSpeedLabel = new JLabel(Bundle.getMessage("MinReliableOperatingSpeedLabel")); 1678 private final JSpinner minReliableOperatingSpeedSpinner = new JSpinner(); 1679 private final JLabel maxSpeedLabel = new JLabel(Bundle.getMessage("MaxSpeedLabel")); 1680 private final JSpinner maxSpeedSpinner = new JSpinner(); 1681 private final JPanel pa2 = new JPanel(); 1682 private final JLabel rampRateLabel = new JLabel(Bundle.getMessage("RampRateBoxLabel")); 1683 private final JComboBox<String> rampRateBox = new JComboBox<>(); 1684 private final JPanel pa2a = new JPanel(); 1685 private final JLabel useSpeedProfileLabel = new JLabel(Bundle.getMessage("UseSpeedProfileLabel")); 1686 private final JCheckBox useSpeedProfileCheckBox = new JCheckBox( ); 1687 private final JLabel stopBySpeedProfileLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileLabel")); 1688 private final JCheckBox stopBySpeedProfileCheckBox = new JCheckBox( ); 1689 private final JLabel stopBySpeedProfileAdjustLabel = new JLabel(Bundle.getMessage("StopBySpeedProfileAdjustLabel")); 1690 private final JSpinner stopBySpeedProfileAdjustSpinner = new JSpinner(); 1691 private final JPanel pa3 = new JPanel(); 1692 private final JCheckBox soundDecoderBox = new JCheckBox(Bundle.getMessage("SoundDecoder")); 1693 private final JCheckBox runInReverseBox = new JCheckBox(Bundle.getMessage("RunInReverse")); 1694 private final JPanel pa4 = new JPanel(); 1695 private final JLabel fNumberBellLabel = new JLabel(Bundle.getMessage("fnumberbelllabel")); 1696 private final JSpinner fNumberBellSpinner = new JSpinner(); 1697 private final JLabel fNumberHornLabel = new JLabel(Bundle.getMessage("fnumberhornlabel")); 1698 private final JSpinner fNumberHornSpinner = new JSpinner(); 1699 private final JLabel fNumberLightLabel = new JLabel(Bundle.getMessage("fnumberlightlabel")); 1700 private final JSpinner fNumberLightSpinner = new JSpinner(); 1701 private final JPanel pa5_FNumbers = new JPanel(); 1702 protected static class TrainDetectionJCombo extends JComboBox<TrainDetectionItem> { 1703 public void setSelectedItemByValue(TrainDetection trainDetVar) { 1704 for ( int ix = 0; ix < getItemCount() ; ix ++ ) { 1705 if (getItemAt(ix).value == trainDetVar) { 1706 this.setSelectedIndex(ix); 1707 break; 1708 } 1709 } 1710 } 1711 } 1712 1713 private final JLabel trainDetectionLabel = new JLabel(Bundle.getMessage("TrainDetection")); 1714 public final TrainDetectionJCombo trainDetectionComboBox = new TrainDetectionJCombo(); 1715 1716 protected static class TrainLengthUnitsJCombo extends JComboBox<TrainLengthUnitsItem> { 1717 public void setSelectedItemByValue(TrainLengthUnits var) { 1718 for ( int ix = 0; ix < getItemCount() ; ix ++ ) { 1719 if (getItemAt(ix).value == var) { 1720 this.setSelectedIndex(ix); 1721 break; 1722 } 1723 } 1724 } 1725 } 1726 1727 public final TrainLengthUnitsJCombo trainLengthUnitsComboBox = new TrainLengthUnitsJCombo(); 1728 private final JLabel trainLengthLabel = new JLabel(Bundle.getMessage("MaxTrainLengthLabel")); 1729 private JLabel trainLengthAltLengthLabel; // I18N Label 1730 private final JSpinner maxTrainLengthSpinner = new JSpinner(); // initialized later 1731 1732 private void initializeAutoRunItems() { 1733 initializeRampCombo(); 1734 initializeScaleLengthBox(); 1735 pa1.setLayout(new FlowLayout()); 1736 pa1.add(speedFactorLabel); 1737 speedFactorSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(2.0f), Float.valueOf(0.01f))); 1738 speedFactorSpinner.setEditor(new JSpinner.NumberEditor(speedFactorSpinner, "# %")); 1739 pa1.add(speedFactorSpinner); 1740 speedFactorSpinner.setToolTipText(Bundle.getMessage("SpeedFactorHint")); 1741 pa1.add(new JLabel(" ")); 1742 pa1.add(maxSpeedLabel); 1743 maxSpeedSpinner.setModel(new SpinnerNumberModel(Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(1.0f), Float.valueOf(0.01f))); 1744 maxSpeedSpinner.setEditor(new JSpinner.NumberEditor(maxSpeedSpinner, "# %")); 1745 pa1.add(maxSpeedSpinner); 1746 maxSpeedSpinner.setToolTipText(Bundle.getMessage("MaxSpeedHint")); 1747 pa1.add(minReliableOperatingSpeedLabel); 1748 minReliableOperatingSpeedSpinner.setModel(new SpinnerNumberModel(Float.valueOf(0.0f), Float.valueOf(0.0f), Float.valueOf(1.0f), Float.valueOf(0.01f))); 1749 minReliableOperatingSpeedSpinner.setEditor(new JSpinner.NumberEditor(minReliableOperatingSpeedSpinner, "# %")); 1750 pa1.add(minReliableOperatingSpeedSpinner); 1751 minReliableOperatingSpeedSpinner.setToolTipText(Bundle.getMessage("MinReliableOperatingSpeedHint")); 1752 initiatePane.add(pa1); 1753 pa2.setLayout(new FlowLayout()); 1754 pa2.add(rampRateLabel); 1755 pa2.add(rampRateBox); 1756 rampRateBox.setToolTipText(Bundle.getMessage("RampRateBoxHint")); 1757 pa2.add(useSpeedProfileLabel); 1758 pa2.add(useSpeedProfileCheckBox); 1759 useSpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint")); 1760 initiatePane.add(pa2); 1761 pa2a.setLayout(new FlowLayout()); 1762 pa2a.add(stopBySpeedProfileLabel); 1763 pa2a.add(stopBySpeedProfileCheckBox); 1764 stopBySpeedProfileCheckBox.setToolTipText(Bundle.getMessage("UseSpeedProfileHint")); // reuse identical hint for Stop 1765 pa2a.add(stopBySpeedProfileAdjustLabel); 1766 stopBySpeedProfileAdjustSpinner.setModel(new SpinnerNumberModel( Float.valueOf(1.0f), Float.valueOf(0.1f), Float.valueOf(5.0f), Float.valueOf(0.01f))); 1767 stopBySpeedProfileAdjustSpinner.setEditor(new JSpinner.NumberEditor(stopBySpeedProfileAdjustSpinner, "# %")); 1768 pa2a.add(stopBySpeedProfileAdjustSpinner); 1769 stopBySpeedProfileAdjustSpinner.setToolTipText(Bundle.getMessage("StopBySpeedProfileAdjustHint")); 1770 initiatePane.add(pa2a); 1771 pa3.setLayout(new FlowLayout()); 1772 pa3.add(soundDecoderBox); 1773 soundDecoderBox.setToolTipText(Bundle.getMessage("SoundDecoderBoxHint")); 1774 pa3.add(new JLabel(" ")); 1775 pa3.add(runInReverseBox); 1776 runInReverseBox.setToolTipText(Bundle.getMessage("RunInReverseBoxHint")); 1777 initiatePane.add(pa3); 1778 maxTrainLengthSpinner.setModel(new SpinnerNumberModel(Float.valueOf(18.0f), Float.valueOf(0.0f), Float.valueOf(10000.0f), Float.valueOf(0.5f))); 1779 maxTrainLengthSpinner.setEditor(new JSpinner.NumberEditor(maxTrainLengthSpinner, "###0.0")); 1780 maxTrainLengthSpinner.setToolTipText(Bundle.getMessage("MaxTrainLengthHint")); // won't be updated while Dispatcher is open 1781 maxTrainLengthSpinner.addChangeListener( e -> handlemaxTrainLengthChangeUnitsLength()); 1782 trainLengthUnitsComboBox.addActionListener( e -> handlemaxTrainLengthChangeUnitsLength()); 1783 trainLengthAltLengthLabel=new JLabel(); 1784 pa4.setLayout(new FlowLayout()); 1785 pa4.add(trainLengthLabel); 1786 pa4.add(maxTrainLengthSpinner); 1787 pa4.add(trainLengthUnitsComboBox); 1788 pa4.add(trainLengthAltLengthLabel); 1789 initiatePane.add(pa4); 1790 pa5_FNumbers.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("fnumbers"))); 1791 pa5_FNumbers.setLayout(new FlowLayout()); 1792 fNumberLightSpinner.setModel(new SpinnerNumberModel(0,0,100,1)); 1793 fNumberLightSpinner.setToolTipText(Bundle.getMessage("fnumberlighthint")); 1794 pa5_FNumbers.add(fNumberLightLabel); 1795 pa5_FNumbers.add(fNumberLightSpinner); 1796 fNumberBellSpinner.setModel(new SpinnerNumberModel(0,0,100,1)); 1797 fNumberBellSpinner.setToolTipText(Bundle.getMessage("fnumberbellhint")); 1798 pa5_FNumbers.add(fNumberBellLabel); 1799 pa5_FNumbers.add(fNumberBellSpinner); 1800 fNumberHornSpinner.setModel(new SpinnerNumberModel(0,0,100,1)); 1801 fNumberHornSpinner.setToolTipText(Bundle.getMessage("fnumberhornhint")); 1802 pa5_FNumbers.add(fNumberHornLabel); 1803 pa5_FNumbers.add(fNumberHornSpinner); 1804 initiatePane.add(pa5_FNumbers); 1805 showHideAutoRunItems(autoRunBox.isSelected()); // initialize with auto run items hidden 1806 } 1807 1808 private void handlemaxTrainLengthChangeUnitsLength() { 1809 trainLengthAltLengthLabel.setText(maxTrainLengthCalculateAltFormatted( 1810 ((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue(), 1811 (float) maxTrainLengthSpinner.getValue())); 1812 } 1813 1814 /** 1815 * Get an I18N String of the max TrainLength. 1816 * @param fromUnits the Length Unit. 1817 * @param fromValue the length. 1818 * @return String format of the length. 1819 */ 1820 private String maxTrainLengthCalculateAltFormatted(TrainLengthUnits fromUnits, float fromValue) { 1821 float value = maxTrainLengthCalculateAlt(fromUnits, fromValue); 1822 switch (fromUnits) { 1823 case TRAINLENGTH_ACTUALINCHS: 1824 return String.format(Locale.getDefault(), "%.2f %s", 1825 value, Bundle.getMessage("TrainLengthInScaleFeet")); 1826 case TRAINLENGTH_ACTUALCM: 1827 return String.format(Locale.getDefault(), "%.1f %s", 1828 value, Bundle.getMessage("TrainLengthInScaleMeters")); 1829 case TRAINLENGTH_SCALEFEET: 1830 return String.format(Locale.getDefault(), "%.1f %s", 1831 value, Bundle.getMessage("TrainLengthInActualInchs")); 1832 case TRAINLENGTH_SCALEMETERS: 1833 return String.format(Locale.getDefault(), "%.0f %s", 1834 value, Bundle.getMessage("TrainLengthInActualcm")); 1835 default: 1836 log.error("Invalid TrainLengthUnits must have been updated, fix maxTrainLengthCalculateAltFormatted"); 1837 } 1838 return ""; 1839 } 1840 1841 private float maxTrainLengthToScaleMeters(TrainLengthUnits fromUnits, float fromValue) { 1842 float value; 1843 // convert to meters. 1844 switch (fromUnits) { 1845 case TRAINLENGTH_ACTUALINCHS: 1846 value = fromValue / 12.0f * (float) _dispatcher.getScale().getScaleRatio(); 1847 value = value / 3.28084f; 1848 break; 1849 case TRAINLENGTH_ACTUALCM: 1850 value = fromValue / 100.0f * (float) _dispatcher.getScale().getScaleRatio(); 1851 break; 1852 case TRAINLENGTH_SCALEFEET: 1853 value = fromValue / 3.28084f; 1854 break; 1855 case TRAINLENGTH_SCALEMETERS: 1856 value = fromValue; 1857 break; 1858 default: 1859 value = 0; 1860 log.error("Invalid TrainLengthUnits has been updated, fix me"); 1861 } 1862 return value; 1863 } 1864 1865 /* 1866 * Calculates the reciprocal unit. Actual to Scale and vice versa 1867 */ 1868 private float maxTrainLengthCalculateAlt(TrainLengthUnits fromUnits, float fromValue) { 1869 switch (fromUnits) { 1870 case TRAINLENGTH_ACTUALINCHS: 1871 // calc scale feet 1872 return (float) jmri.util.MathUtil.granulize(fromValue / 12 * (float) _dispatcher.getScale().getScaleRatio(),0.1f); 1873 case TRAINLENGTH_ACTUALCM: 1874 // calc scale meter 1875 return fromValue / 100 * (float) _dispatcher.getScale().getScaleRatio(); 1876 case TRAINLENGTH_SCALEFEET: 1877 // calc actual inchs 1878 return fromValue * 12 * (float) _dispatcher.getScale().getScaleFactor(); 1879 case TRAINLENGTH_SCALEMETERS: 1880 // calc actual cm. 1881 return fromValue * 100 * (float) _dispatcher.getScale().getScaleFactor(); 1882 default: 1883 log.error("Invalid TrainLengthUnits has been updated, fix me"); 1884 } 1885 return 0; 1886 } 1887 1888 private void showHideAutoRunItems(boolean value) { 1889 pa1.setVisible(value); 1890 pa2.setVisible(value); 1891 pa2a.setVisible(value); 1892 pa3.setVisible(value); 1893 pa4.setVisible(value); 1894 pa5_FNumbers.setVisible(value); 1895 } 1896 1897 private void autoTrainInfoToDialog(TrainInfo info) { 1898 speedFactorSpinner.setValue(info.getSpeedFactor()); 1899 maxSpeedSpinner.setValue(info.getMaxSpeed()); 1900 minReliableOperatingSpeedSpinner.setValue(info.getMinReliableOperatingSpeed()); 1901 setComboBox(rampRateBox, info.getRampRate()); 1902 trainDetectionComboBox.setSelectedItemByValue(info.getTrainDetection()); 1903 runInReverseBox.setSelected(info.getRunInReverse()); 1904 soundDecoderBox.setSelected(info.getSoundDecoder()); 1905 trainLengthUnitsComboBox.setSelectedItemByValue(info.getTrainLengthUnits()); 1906 switch (info.getTrainLengthUnits()) { 1907 case TRAINLENGTH_SCALEFEET: 1908 maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet()); 1909 break; 1910 case TRAINLENGTH_SCALEMETERS: 1911 maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters()); 1912 break; 1913 case TRAINLENGTH_ACTUALINCHS: 1914 maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleFeet() * 12.0f * (float)_dispatcher.getScale().getScaleFactor()); 1915 break; 1916 case TRAINLENGTH_ACTUALCM: 1917 maxTrainLengthSpinner.setValue(info.getMaxTrainLengthScaleMeters() * 100.0f * (float)_dispatcher.getScale().getScaleFactor()); 1918 break; 1919 default: 1920 maxTrainLengthSpinner.setValue(0.0f); 1921 } 1922 useSpeedProfileCheckBox.setSelected(info.getUseSpeedProfile()); 1923 stopBySpeedProfileCheckBox.setSelected(info.getStopBySpeedProfile()); 1924 stopBySpeedProfileAdjustSpinner.setValue(info.getStopBySpeedProfileAdjust()); 1925 fNumberLightSpinner.setValue(info.getFNumberLight()); 1926 fNumberBellSpinner.setValue(info.getFNumberBell()); 1927 fNumberHornSpinner.setValue(info.getFNumberHorn()); 1928 showHideAutoRunItems(autoRunBox.isSelected()); 1929 initiateFrame.pack(); 1930 } 1931 1932 private void autoRunItemsToTrainInfo(TrainInfo info) { 1933 info.setSpeedFactor((float) speedFactorSpinner.getValue()); 1934 info.setMaxSpeed((float) maxSpeedSpinner.getValue()); 1935 info.setMinReliableOperatingSpeed((float) minReliableOperatingSpeedSpinner.getValue()); 1936 info.setRampRate((String) rampRateBox.getSelectedItem()); 1937 info.setRunInReverse(runInReverseBox.isSelected()); 1938 info.setSoundDecoder(soundDecoderBox.isSelected()); 1939 info.setTrainLengthUnits(((TrainLengthUnitsItem) trainLengthUnitsComboBox.getSelectedItem()).getValue()); 1940 info.setMaxTrainLengthScaleMeters(maxTrainLengthToScaleMeters( info.getTrainLengthUnits(), (float) maxTrainLengthSpinner.getValue())); 1941 1942 // Only use speed profile values if enabled 1943 if (useSpeedProfileCheckBox.isEnabled()) { 1944 info.setUseSpeedProfile(useSpeedProfileCheckBox.isSelected()); 1945 info.setStopBySpeedProfile(stopBySpeedProfileCheckBox.isSelected()); 1946 info.setStopBySpeedProfileAdjust((float) stopBySpeedProfileAdjustSpinner.getValue()); 1947 } else { 1948 info.setUseSpeedProfile(false); 1949 info.setStopBySpeedProfile(false); 1950 info.setStopBySpeedProfileAdjust(1.0f); 1951 } 1952 info.setFNumberLight((int)fNumberLightSpinner.getValue()); 1953 info.setFNumberBell((int)fNumberBellSpinner.getValue()); 1954 info.setFNumberHorn((int)fNumberHornSpinner.getValue()); 1955 } 1956 1957 private void initializeRampCombo() { 1958 rampRateBox.removeAllItems(); 1959 rampRateBox.addItem(Bundle.getMessage("RAMP_NONE")); 1960 rampRateBox.addItem(Bundle.getMessage("RAMP_FAST")); 1961 rampRateBox.addItem(Bundle.getMessage("RAMP_MEDIUM")); 1962 rampRateBox.addItem(Bundle.getMessage("RAMP_MED_SLOW")); 1963 rampRateBox.addItem(Bundle.getMessage("RAMP_SLOW")); 1964 rampRateBox.addItem(Bundle.getMessage("RAMP_SPEEDPROFILE")); 1965 // Note: the order above must correspond to the numbers in AutoActiveTrain.java 1966 } 1967 1968 /** 1969 * Sets up the RadioButtons and visability of spinner for the allocation method 1970 * 1971 * @param value 0, Allocate by Safe spots, -1, allocate as far as possible Any 1972 * other value the number of sections to allocate 1973 */ 1974 private void setAllocateMethodButtons(int value) { 1975 switch (value) { 1976 case ActiveTrain.ALLOCATE_BY_SAFE_SECTIONS: 1977 allocateBySafeRadioButton.setSelected(true); 1978 allocateCustomSpinner.setVisible(false); 1979 break; 1980 case ActiveTrain.ALLOCATE_AS_FAR_AS_IT_CAN: 1981 allocateAllTheWayRadioButton.setSelected(true); 1982 allocateCustomSpinner.setVisible(false); 1983 break; 1984 default: 1985 allocateNumberOfBlocks.setSelected(true); 1986 allocateCustomSpinner.setVisible(true); 1987 allocateCustomSpinner.setValue(value); 1988 } 1989 } 1990 1991 /* 1992 * Layout block stuff 1993 */ 1994 private ArrayList<LayoutBlock> getOccupiedBlockList() { 1995 LayoutBlockManager lBM = InstanceManager.getDefault(LayoutBlockManager.class); 1996 ArrayList<LayoutBlock> lBlocks = new ArrayList<>(); 1997 for (LayoutBlock lB : lBM.getNamedBeanSet()) { 1998 if (lB.getBlock().getState() == Block.OCCUPIED) { 1999 lBlocks.add(lB); 2000 } 2001 } 2002 return lBlocks; 2003 } 2004 2005 private void initializeStartingBlockComboDynamic() { 2006 startingBlockBox.removeAllItems(); 2007 startingBlockBoxList.clear(); 2008 for (LayoutBlock lB: getOccupiedBlockList()) { 2009 if (!startingBlockBoxList.contains(lB.getBlock())) { 2010 startingBlockBoxList.add(lB.getBlock()); 2011 startingBlockBox.addItem(getBlockName(lB.getBlock())); 2012 } 2013 } 2014 JComboBoxUtil.setupComboBoxMaxRows(startingBlockBox); 2015 } 2016 2017 private void initializeViaBlockDynamicCombo() { 2018 String prevValue = (String) viaBlockBox.getSelectedItem(); 2019 viaBlockBox.removeActionListener(viaBlockBoxListener); 2020 viaBlockBox.removeAllItems(); 2021 viaBlockBoxList.clear(); 2022 LayoutBlockManager lBM = InstanceManager.getDefault(LayoutBlockManager.class); 2023 if (startingBlockBox.getSelectedItem() != null) { 2024 LayoutBlock lBSrc; 2025 if (startingBlockBox.getSelectedIndex() >= 0) { 2026 lBSrc = lBM.getByUserName((String) startingBlockBox.getSelectedItem()); 2027 if (lBSrc != null) { 2028 int rX = lBSrc.getNumberOfNeighbours() - 1; 2029 for (; rX > -1; rX--) { 2030 viaBlockBox.addItem(lBSrc.getNeighbourAtIndex(rX).getDisplayName()); 2031 viaBlockBoxList.add(lBSrc.getNeighbourAtIndex(rX)); 2032 } 2033 } 2034 } 2035 } 2036 if (prevValue != null) { 2037 viaBlockBox.setSelectedItem(prevValue); 2038 } 2039 viaBlockBox.addActionListener(viaBlockBoxListener); 2040 } 2041 2042 private void initializeDestinationBlockDynamicCombo() { 2043 destinationBlockBox.removeAllItems(); 2044 destinationBlockBoxList.clear(); 2045 LayoutBlockManager lBM = InstanceManager.getDefault(LayoutBlockManager.class); 2046 if (startingBlockBox.getSelectedItem() != null) { 2047 LayoutBlock lBSrc; 2048 if (startingBlockBox.getSelectedIndex() >= 0 2049 && viaBlockBox.getSelectedIndex() >= 0) { 2050 lBSrc = lBM.getByUserName((String) startingBlockBox.getSelectedItem()); 2051 Block b = viaBlockBoxList.get(viaBlockBox.getSelectedIndex()); 2052 if (lBSrc != null) { 2053 int rX = lBSrc.getNumberOfRoutes() - 1; 2054 for (; rX > -1; rX--) { 2055 if (lBSrc.getRouteNextBlockAtIndex(rX) == b) { 2056 destinationBlockBox.addItem(lBSrc.getRouteDestBlockAtIndex(rX).getDisplayName()); 2057 destinationBlockBoxList.add(lBSrc.getRouteDestBlockAtIndex(rX)); 2058 } 2059 } 2060 } 2061 } 2062 } 2063 } 2064 2065 /* 2066 * Check Advanced routing 2067 */ 2068 private boolean checkAdvancedRouting() { 2069 if (!InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled()) { 2070 int response = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("AdHocNeedsEnableBlockRouting"), 2071 Bundle.getMessage("AdHocNeedsBlockRouting"), JmriJOptionPane.YES_NO_OPTION); 2072 if (response == 0) { 2073 InstanceManager.getDefault(LayoutBlockManager.class).enableAdvancedRouting(true); 2074 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("AdhocNeedsBlockRoutingEnabled")); 2075 } else { 2076 return false; 2077 } 2078 } 2079 return true; 2080 } 2081 2082 /* 2083 * ComboBox item. 2084 */ 2085 protected static class TrainDetectionItem { 2086 2087 private final String key; 2088 private TrainDetection value; 2089 2090 public TrainDetectionItem(String text, TrainDetection trainDetection ) { 2091 this.key = text; 2092 this.value = trainDetection; 2093 } 2094 2095 @Override 2096 public String toString() { 2097 return key; 2098 } 2099 2100 public String getKey() { 2101 return key; 2102 } 2103 2104 public TrainDetection getValue() { 2105 return value; 2106 } 2107 } 2108 2109 /* 2110 * ComboBox item. 2111 */ 2112 protected static class TrainLengthUnitsItem { 2113 2114 private final String key; 2115 private TrainLengthUnits value; 2116 2117 public TrainLengthUnitsItem(String text, TrainLengthUnits trainLength ) { 2118 this.key = text; 2119 this.value = trainLength; 2120 } 2121 2122 @Override 2123 public String toString() { 2124 return key; 2125 } 2126 2127 public String getKey() { 2128 return key; 2129 } 2130 2131 public TrainLengthUnits getValue() { 2132 return value; 2133 } 2134 } 2135 2136 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActivateTrainFrame.class); 2137 2138}