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