001package jmri.jmrit.dispatcher; 002 003import java.beans.PropertyChangeListener; 004import java.beans.PropertyChangeSupport; 005import java.util.ArrayList; 006import java.util.Date; 007import java.util.List; 008 009import javax.annotation.OverridingMethodsMustInvokeSuper; 010 011import jmri.Block; 012import jmri.InstanceManager; 013import jmri.NamedBeanHandle; 014import jmri.Path; 015import jmri.Section; 016import jmri.Sensor; 017import jmri.Transit; 018import jmri.Transit.TransitType; 019import jmri.TransitSection; 020import jmri.Section.SectionType; 021import jmri.beans.PropertyChangeProvider; 022import jmri.jmrit.display.layoutEditor.LayoutBlock; 023import jmri.jmrit.display.layoutEditor.LayoutBlockManager; 024 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028/** 029 * This class holds information and options for an ActiveTrain, that is a train 030 * that has been linked to a Transit and activated for transit around the 031 * layout. 032 * <p> 033 * An ActiveTrain may be assigned one of the following modes, which specify how 034 * the active train will be run through its transit: AUTOMATIC - indicates the 035 * ActiveTrain will be run under automatic control of the computer. (Automatic 036 * Running) MANUAL - indicates an ActiveTrain running in AUTOMATIC mode has 037 * reached a Special Action in its Transit that requires MANUAL operation. When 038 * this happens, the status changes to WORKING, and the mode changes to MANUAL. 039 * The ActiveTrain will be run by an operator using a throttle. AUTOMATIC 040 * running is resumed when the work has been completed. DISPATCHED - indicates 041 * the ActiveTrain will be run by an operator using a throttle. A dispatcher 042 * will allocate Sections to the ActiveTrain as needed, control optional signals 043 * using a CTC panel or computer logic, and arbitrate any conflicts between 044 * ActiveTrains. (Human Dispatcher). 045 * <p> 046 * An ActiveTrain will have one of the following statuses: 047 * <dl> 048 * <dt>RUNNING</dt><dd>Actively running on the layout, according to its mode of 049 * operation.</dd> 050 * <dt>PAUSED</dt><dd>Paused waiting for a user-specified number of fast clock 051 * minutes. The Active Train is expected to move to either RUNNING or WAITING 052 * once the specified number of minutes has elapsed. This is intended for 053 * automatic station stops. (automatic trains only)</dd> 054 * <dt>WAITING</dt><dd>Stopped waiting for a Section allocation. This is the 055 * state the Active Train is in when it is created in Dispatcher.</dd> 056 * <dt>WORKING</dt><dd>Performing work under control of a human engineer. This is 057 * the state an Active Train assumes when an engineer is picking up or setting 058 * out cars at industries. (automatic trains only)</dd> 059 * <dt>READY</dt><dd>Train has completed WORKING, and is awaiting a restart - 060 * dispatcher clearance to resume running. (automatic trains only)</dd> 061 * <dt>STOPPED</dt><dd>Train was stopped by the dispatcher. Dispatcher must 062 * resume. (automatic trains only)</dd> 063 * <dt>DONE</dt><dd>Train has completed its transit of the layout and is ready to 064 * be terminated by the dispatcher, or Restart pressed to repeat the automated 065 * run.</dd> 066 * </dl> 067 * Status is a bound property. 068 * <p> 069 * The ActiveTrain status should maintained (setStatus) by the running class, or 070 * if running in DISPATCHED mode, by Dispatcher. When an ActiveTrain is WAITING, 071 * and the dispatcher allocates a section to it, the status of the ActiveTrain 072 * is automatically set to RUNNING. So an autoRun class can listen to the status 073 * of the ActiveTrain to trigger start up if the train has been waiting for the 074 * dispatcher. Note: There is still more to be programmed here. 075 * <p> 076 * Train information supplied when the ActiveTrain is created can come from any 077 * of the following: 078 * <dl> 079 * <dt>ROSTER</dt><dd>The train was selected from the JMRI roster menu</dd> 080 * <dt>OPERATIONS</dt><dd>The train was selected from trains available from JMRI 081 * operations</dd> 082 * <dt>USER</dt><dd>Neither menu was used--the user entered a name and DCC 083 * address.</dd> 084 * </dl> 085 * Train source information is recorded when an ActiveTrain is created, 086 * and may be referenced by getTrainSource if it is needed by other objects. The 087 * train source should be specified in the Dispatcher Options window prior to 088 * creating an ActiveTrain. 089 * <p> 090 * ActiveTrains are referenced via a list in DispatcherFrame, which serves as a 091 * manager for ActiveTrain objects. 092 * <p> 093 * ActiveTrains are transient, and are not saved to disk. Active Train 094 * information can be saved to disk, making set up with the same options, etc 095 * very easy. 096 * <p> 097 * An ActiveTrain runs through its Transit in the FORWARD direction, until a 098 * Transit Action reverses the direction of travel in the Transit. When running 099 * with its Transit reversed, the Active Train returns to its starting Section. 100 * Upon reaching and stopping in its starting Section, the Transit is 101 * automatically set back to the forward direction. If AutoRestart is set, the 102 * run is repeated. The direction of travel in the Transit is maintained here. 103 * 104 * <p> 105 * This file is part of JMRI. 106 * <p> 107 * JMRI is open source software; you can redistribute it and/or modify it under 108 * the terms of version 2 of the GNU General Public License as published by the 109 * Free Software Foundation. See the "COPYING" file for a copy of this license. 110 * <p> 111 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 112 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 113 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 114 * 115 * @author Dave Duchamp Copyright (C) 2008-2011 116 */ 117public class ActiveTrain implements PropertyChangeProvider { 118 119 private static final jmri.NamedBean.DisplayOptions USERSYS = jmri.NamedBean.DisplayOptions.USERNAME_SYSTEMNAME; 120 121 /** 122 * Create an ActiveTrain. 123 * 124 * @param t the transit linked to this ActiveTrain 125 * @param name the train name 126 * @param trainSource the source for this ActiveTrain 127 */ 128 public ActiveTrain(Transit t, String name, int trainSource) { 129 mTransit = t; 130 mTrainName = name; 131 mTrainSource = trainSource; 132 } 133 134 /** 135 * Constants representing the Status of this ActiveTrain When created, the 136 * Status of an Active Train is always WAITING, 137 */ 138 public static final int RUNNING = 0x01; // running on the layout 139 public static final int PAUSED = 0x02; // paused for a number of fast minutes 140 public static final int WAITING = 0x04; // waiting for a section allocation 141 public static final int WORKING = 0x08; // actively working 142 public static final int READY = 0x10; // completed work, waiting for restart 143 public static final int STOPPED = 0x20; // stopped by the dispatcher (auto trains only) 144 public static final int DONE = 0x40; // completed its transit 145 146 /** 147 * Constants representing Type of ActiveTrains. 148 */ 149 public static final int NONE = 0x00; // no train type defined 150 public static final int LOCAL_PASSENGER = 0x01; // low priority local passenger train 151 public static final int LOCAL_FREIGHT = 0x02; // low priority freight train performing local tasks 152 public static final int THROUGH_PASSENGER = 0x03; // normal priority through passenger train 153 public static final int THROUGH_FREIGHT = 0x04; // normal priority through freight train 154 public static final int EXPRESS_PASSENGER = 0x05; // high priority passenger train 155 public static final int EXPRESS_FREIGHT = 0x06; // high priority freight train 156 public static final int MOW = 0x07; // low priority maintenance of way train 157 158 /** 159 * Constants representing the mode of running of the Active Train The mode 160 * is set when the Active Train is created. The mode may be switched during 161 * a run. 162 */ 163 public static final int AUTOMATIC = 0x02; // requires mAutoRun to be "true" (auto trains only) 164 public static final int MANUAL = 0x04; // requires mAutoRun to be "true" (auto trains only) 165 public static final int DISPATCHED = 0x08; 166 public static final int TERMINATED = 0x10; //terminated 167 168 /** 169 * Constants representing the source of the train information 170 */ 171 public static final int ROSTER = 0x01; 172 public static final int OPERATIONS = 0x02; 173 public static final int USER = 0x04; 174 175 /** 176 * The value of {@link #getAllocateMethod()} if allocating as many sections as are clear. 177 */ 178 public static final int ALLOCATE_AS_FAR_AS_IT_CAN = -1; 179 /** 180 * The value of {@link #getAllocateMethod()} if allocating up until the next safe section 181 */ 182 public static final int ALLOCATE_BY_SAFE_SECTIONS = 0; 183 184 /** 185 * How much of the train can be detected 186 */ 187 public enum TrainDetection { 188 TRAINDETECTION_WHOLETRAIN, 189 TRAINDETECTION_HEADONLY, 190 TRAINDETECTION_HEADANDTAIL 191 } 192 193 /** 194 * Scale Length type 195 */ 196 public enum TrainLengthUnits { 197 TRAINLENGTH_SCALEFEET, 198 TRAINLENGTH_SCALEMETERS, 199 TRAINLENGTH_ACTUALINCHS, 200 TRAINLENGTH_ACTUALCM 201 } 202 203 // instance variables 204 private DispatcherFrame mDispatcher = null; 205 private Transit mTransit = null; 206 private String mTrainName = ""; 207 private int mTrainSource = ROSTER; 208 private jmri.jmrit.roster.RosterEntry mRoster = null; 209 private int mStatus = WAITING; 210 private int mMode = DISPATCHED; 211 private boolean mTransitReversed = false; // true if Transit is running in reverse 212 private boolean mAllocationReversed = false; // true if allocating Sections in reverse 213 private AutoActiveTrain mAutoActiveTrain = null; 214 private final List<AllocatedSection> mAllocatedSections = new ArrayList<>(); 215 private jmri.Section mLastAllocatedSection = null; 216 private Section mLastAllocOverrideSafe = null; 217 private int mLastAllocatedSectionSeqNumber = 0; 218 private jmri.Section mSecondAllocatedSection = null; 219 private int mNextAllocationNumber = 1; 220 private jmri.Section mNextSectionToAllocate = null; 221 private int mNextSectionSeqNumber = 0; 222 private int mNextSectionDirection = 0; 223 private jmri.Block mStartBlock = null; 224 private int mStartBlockSectionSequenceNumber = 0; 225 private jmri.Block mEndBlock = null; 226 private jmri.Section mEndBlockSection = null; 227 private int mEndBlockSectionSequenceNumber = 0; 228 private int mPriority = 0; 229 private boolean mAutoRun = false; 230 private String mDccAddress = ""; 231 private boolean mResetWhenDone = true; 232 private boolean mReverseAtEnd = false; 233 private int mAllocateMethod = 3; 234 public final static int NODELAY = 0x00; 235 public final static int TIMEDDELAY = 0x01; 236 public final static int SENSORDELAY = 0x02; 237 private TrainDetection trainDetection = TrainDetection.TRAINDETECTION_HEADONLY; 238 239 private int mDelayedRestart = NODELAY; 240 private int mDelayedStart = NODELAY; 241 private int mDepartureTimeHr = 8; 242 private int mDepartureTimeMin = 0; 243 private int mRestartDelay = 0; 244 private NamedBeanHandle<jmri.Sensor> mStartSensor = null; // A Sensor that when changes state to active will trigger the trains start. 245 private boolean resetStartSensor = true; 246 private NamedBeanHandle<jmri.Sensor> mRestartSensor = null; // A Sensor that when changes state to active will trigger the trains restart. 247 private boolean resetRestartSensor = true; 248 private NamedBeanHandle<jmri.Sensor> mReverseRestartSensor = null; // A Sensor that when changes state to active will trigger the trains restart. 249 private boolean resetReverseRestartSensor = true; 250 private int mDelayReverseRestart = NODELAY; 251 private int mTrainType = LOCAL_FREIGHT; 252 private boolean terminateWhenFinished = false; 253 private String mNextTrain = ""; 254 private int mSignalType; 255 256 // start up instance variables 257 private boolean mStarted = false; 258 259 // 260 // Access methods 261 // 262 public boolean getStarted() { 263 return mStarted; 264 } 265 266 public void setDispatcher(DispatcherFrame df) { 267 mDispatcher = df; 268 mSignalType = df.getSignalType(); 269 if (mTransit.getTransitType() == TransitType.DYNAMICADHOC) { 270 mSignalType = DispatcherFrame.SECTIONSALLOCATED; 271 } 272 } 273 274 public void setStarted() { 275 mStarted = true; 276 mStatus = RUNNING; 277 holdAllocation(false); 278 setStatus(WAITING); 279 if (mAutoActiveTrain != null && mDispatcher.getSignalType() == DispatcherFrame.SIGNALMAST) { 280 mAutoActiveTrain.setupNewCurrentSignal(null,false); 281 } 282 } 283 284 public Transit getTransit() { 285 return mTransit; 286 } 287 288 public String getTransitName() { 289 String s = mTransit.getDisplayName(); 290 return s; 291 } 292 293 public String getActiveTrainName() { 294 return (mTrainName + " / " + getTransitName()); 295 } 296 297 // Note: Transit and Train may not be changed once an ActiveTrain is created. 298 public String getTrainName() { 299 return mTrainName; 300 } 301 302 public int getTrainSource() { 303 return mTrainSource; 304 } 305 306 public void setRosterEntry(jmri.jmrit.roster.RosterEntry re) { 307 mRoster = re; 308 } 309 310 public jmri.jmrit.roster.RosterEntry getRosterEntry() { 311 if (mRoster == null && getTrainSource() == ROSTER) { 312 //Try to resolve the roster based upon the train name 313 mRoster = jmri.jmrit.roster.Roster.getDefault().getEntryForId(getTrainName()); 314 } else if (getTrainSource() != ROSTER) { 315 mRoster = null; 316 } 317 return mRoster; 318 } 319 320 public int getStatus() { 321 return mStatus; 322 } 323 324 public void setStatus(int status) { 325 if (restartPoint) { 326 return; 327 } 328 if ((status == RUNNING) || (status == PAUSED) || (status == WAITING) || (status == WORKING) 329 || (status == READY) || (status == STOPPED) || (status == DONE)) { 330 if (mStatus != status) { 331 int old = mStatus; 332 mStatus = status; 333 firePropertyChange("status", Integer.valueOf(old), Integer.valueOf(mStatus)); 334 if (mStatus == DONE) { 335 mDispatcher.terminateActiveTrain(this,terminateWhenFinished,true); 336 } 337 } 338 } else { 339 log.error("Invalid ActiveTrain status - {}", status); 340 } 341 } 342 343 public void setControlingSignal(Object oldSignal, Object newSignal) { 344 firePropertyChange("signal", oldSignal, newSignal); 345 } 346 347 public String getStatusText() { 348 if (mStatus == RUNNING) { 349 return Bundle.getMessage("RUNNING"); 350 } else if (mStatus == PAUSED) { 351 return Bundle.getMessage("PAUSED"); 352 } else if (mStatus == WAITING) { 353 if (!mStarted) { 354 if (mDelayedStart == TIMEDDELAY) { 355 return jmri.jmrit.beantable.LogixTableAction.formatTime(mDepartureTimeHr, 356 mDepartureTimeMin) + " " + Bundle.getMessage("START"); 357 } else if (mDelayedStart == SENSORDELAY) { 358 return (Bundle.getMessage("BeanNameSensor") + " " + getDelaySensorName()); 359 } 360 } 361 return Bundle.getMessage("WAITING"); 362 } else if (mStatus == WORKING) { 363 return Bundle.getMessage("WORKING"); 364 } else if (mStatus == READY) { 365 if (restartPoint && getDelayedRestart() == TIMEDDELAY) { 366 return jmri.jmrit.beantable.LogixTableAction.formatTime(restartHr, 367 restartMin) + " " + Bundle.getMessage("START"); 368 } else if (restartPoint && getDelayedRestart() == SENSORDELAY) { 369 return (Bundle.getMessage("BeanNameSensor") + " " + getRestartSensorName()); 370 } 371 return Bundle.getMessage("READY"); 372 } else if (mStatus == STOPPED) { 373 return Bundle.getMessage("STOPPED"); 374 } else if (mStatus == DONE) { 375 return Bundle.getMessage("DONE"); 376 } 377 return (""); 378 } 379 380 /** 381 * sets the train detection type 382 * @param value {@link ActiveTrain.TrainDetection} 383 */ 384 public void setTrainDetection(TrainDetection value) { 385 trainDetection = value; 386 } 387 388 /** 389 * Gets the train detection type 390 * @return {@link ActiveTrain.TrainDetection} 391 */ 392 public TrainDetection getTrainDetection() { 393 return trainDetection; 394 } 395 396 public boolean isTransitReversed() { 397 return mTransitReversed; 398 } 399 400 public void setTransitReversed(boolean set) { 401 mTransitReversed = set; 402 } 403 404 public boolean isAllocationReversed() { 405 return mAllocationReversed; 406 } 407 408 public void setAllocationReversed(boolean set) { 409 mAllocationReversed = set; 410 } 411 412 public int getDelayedStart() { 413 return mDelayedStart; 414 } 415 416 public void setNextTrain(String nextTrain) { 417 mNextTrain = nextTrain; 418 } 419 420 public String getNextTrain() { 421 return mNextTrain; 422 } 423 424 public void setDelayedStart(int delay) { 425 mDelayedStart = delay; 426 } 427 428 public int getDelayedRestart() { 429 return mDelayedRestart; 430 } 431 432 public void setDelayedRestart(int delay) { 433 mDelayedRestart = delay; 434 } 435 436 public int getDelayReverseRestart() { 437 return mDelayReverseRestart; 438 } 439 440 public void setReverseDelayRestart(int delay) { 441 mDelayReverseRestart = delay; 442 } 443 444 public int getDepartureTimeHr() { 445 return mDepartureTimeHr; 446 } 447 448 public void setDepartureTimeHr(int hr) { 449 mDepartureTimeHr = hr; 450 } 451 452 public int getDepartureTimeMin() { 453 return mDepartureTimeMin; 454 } 455 456 public void setDepartureTimeMin(int min) { 457 mDepartureTimeMin = min; 458 } 459 460 public void setRestartDelay(int min) { 461 mRestartDelay = min; 462 } 463 464 public int getRestartDelay() { 465 return mRestartDelay; 466 } 467 468 int mReverseRestartDelay; 469 public int getReverseRestartDelay() { 470 return mReverseRestartDelay; 471 } 472 public void setReverseRestartDelay(int min) { 473 mReverseRestartDelay = min; 474 } 475 476 int restartHr = 0; 477 int restartMin = 0; 478 479 public int getRestartDepartHr() { 480 return restartHr; 481 } 482 483 public int getRestartDepartMin() { 484 return restartMin; 485 } 486 487 public void setTerminateWhenDone(boolean boo) { 488 terminateWhenFinished = boo; 489 } 490 491 public jmri.Sensor getDelaySensor() { 492 if (mStartSensor == null) { 493 return null; 494 } 495 return mStartSensor.getBean(); 496 } 497 498 public String getDelaySensorName() { 499 if (mStartSensor == null) { 500 return null; 501 } 502 return mStartSensor.getName(); 503 } 504 505 public void setDelaySensor(jmri.Sensor s) { 506 if (s == null) { 507 mStartSensor = null; 508 return; 509 } 510 mStartSensor = jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(s.getDisplayName(), s); 511 } 512 513 public void setResetStartSensor(boolean b) { 514 resetStartSensor = b; 515 } 516 517 public boolean getResetStartSensor() { 518 return resetStartSensor; 519 } 520 521 public jmri.Sensor getReverseRestartSensor() { 522 if (mReverseRestartSensor == null) { 523 return null; 524 } 525 return mReverseRestartSensor.getBean(); 526 } 527 528 public String getReverseRestartSensorName() { 529 if (mReverseRestartSensor == null) { 530 return null; 531 } 532 return mReverseRestartSensor.getName(); 533 } 534 535 public void setReverseDelaySensor(jmri.Sensor s) { 536 if (s == null) { 537 mReverseRestartSensor = null; 538 return; 539 } 540 mReverseRestartSensor = jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(s.getDisplayName(), s); 541 } 542 543 public void setReverseResetRestartSensor(boolean b) { 544 resetReverseRestartSensor = b; 545 } 546 547 public boolean getResetReverseRestartSensor() { 548 return resetReverseRestartSensor; 549 } 550 551 public jmri.Sensor getRestartSensor() { 552 if (mRestartSensor == null) { 553 return null; 554 } 555 return mRestartSensor.getBean(); 556 } 557 558 public String getRestartSensorName() { 559 if (mRestartSensor == null) { 560 return null; 561 } 562 return mRestartSensor.getName(); 563 } 564 565 public void setRestartSensor(jmri.Sensor s) { 566 if (s == null) { 567 mRestartSensor = null; 568 return; 569 } 570 mRestartSensor = jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(s.getDisplayName(), s); 571 } 572 573 public void setResetRestartSensor(boolean b) { 574 resetRestartSensor = b; 575 } 576 577 public boolean getResetRestartSensor() { 578 return resetRestartSensor; 579 } 580 581 public int getSignalType() { 582 return mSignalType; 583 } 584 585 private java.beans.PropertyChangeListener delaySensorListener = null; 586 private java.beans.PropertyChangeListener restartSensorListener = null; 587 private java.beans.PropertyChangeListener restartAllocationSensorListener = null; 588 589 public void initializeDelaySensor() { 590 if (mStartSensor == null) { 591 log.error("Call to initialise delay on start sensor, but none specified"); 592 return; 593 } 594 if (delaySensorListener == null) { 595 final ActiveTrain at = this; 596 delaySensorListener = new java.beans.PropertyChangeListener() { 597 @Override 598 public void propertyChange(java.beans.PropertyChangeEvent e) { 599 if (e.getPropertyName().equals("KnownState")) { 600 if (((Integer) e.getNewValue()).intValue() == jmri.Sensor.ACTIVE) { 601 getDelaySensor().removePropertyChangeListener(delaySensorListener); 602 mDispatcher.removeDelayedTrain(at); 603 setStarted(); 604 mDispatcher.queueScanOfAllocationRequests(); 605 if (resetStartSensor) { 606 try { 607 getDelaySensor().setKnownState(jmri.Sensor.INACTIVE); 608 log.debug("Start sensor {} set back to inActive", getDelaySensor().getDisplayName(USERSYS)); 609 } catch (jmri.JmriException ex) { 610 log.error("Error resetting start sensor {} back to inActive", getDelaySensor().getDisplayName(USERSYS)); 611 } 612 } 613 } 614 } 615 } 616 }; 617 } 618 getDelaySensor().addPropertyChangeListener(delaySensorListener); 619 } 620 621 public void initializeRestartSensor(Sensor restartSensor, boolean resetSensor) { 622 if (restartSensor == null) { 623 log.error("Call to initialise delay on restart sensor, but none specified"); 624 return; 625 } 626 if (restartSensorListener == null) { 627 final ActiveTrain at = this; 628 restartSensorListener = new java.beans.PropertyChangeListener() { 629 @Override 630 public void propertyChange(java.beans.PropertyChangeEvent e) { 631 if (e.getPropertyName().equals("KnownState")) { 632 if (((Integer) e.getNewValue()).intValue() == jmri.Sensor.ACTIVE) { 633 restartSensor.removePropertyChangeListener(restartSensorListener); 634 restartSensorListener = null; 635 mDispatcher.removeDelayedTrain(at); 636 restart(); 637 mDispatcher.queueScanOfAllocationRequests(); 638 if (resetSensor) { 639 try { 640 restartSensor.setKnownState(jmri.Sensor.INACTIVE); 641 log.debug("Restart sensor {} set back to inActive", getRestartSensor().getDisplayName(USERSYS)); 642 } catch (jmri.JmriException ex) { 643 log.error("Error resetting restart sensor back to inActive"); 644 } 645 } 646 } 647 } 648 } 649 }; 650 } 651 restartSensor.addPropertyChangeListener(restartSensorListener); 652 } 653 654 public void initializeRestartAllocationSensor(NamedBeanHandle<jmri.Sensor> restartAllocationSensor) { 655 if (restartAllocationSensor == null) { 656 log.error("Call to initialise delay on restart allocation sensor, but none specified"); 657 return; 658 } 659 if (restartAllocationSensorListener == null) { 660 restartAllocationSensorListener = new java.beans.PropertyChangeListener() { 661 @Override 662 public void propertyChange(java.beans.PropertyChangeEvent e) { 663 if (e.getPropertyName().equals("KnownState")) { 664 if (((Integer) e.getNewValue()).intValue() == jmri.Sensor.INACTIVE) { 665 restartAllocationSensor.getBean().removePropertyChangeListener(restartAllocationSensorListener); 666 restartAllocationSensorListener = null; 667 mDispatcher.queueScanOfAllocationRequests(); 668 } 669 } 670 } 671 }; 672 } 673 restartAllocationSensor.getBean().addPropertyChangeListener(restartAllocationSensorListener); 674 } 675 676 public void setTrainType(int type) { 677 mTrainType = type; 678 } 679 680 /** 681 * set train type using localized string name as stored 682 * 683 * @param sType name, such as "LOCAL_PASSENGER" 684 */ 685 public void setTrainType(String sType) { 686 if (sType.equals(Bundle.getMessage("LOCAL_FREIGHT"))) { 687 setTrainType(LOCAL_FREIGHT); 688 } else if (sType.equals(Bundle.getMessage("LOCAL_PASSENGER"))) { 689 setTrainType(LOCAL_PASSENGER); 690 } else if (sType.equals(Bundle.getMessage("THROUGH_FREIGHT"))) { 691 setTrainType(THROUGH_FREIGHT); 692 } else if (sType.equals(Bundle.getMessage("THROUGH_PASSENGER"))) { 693 setTrainType(THROUGH_PASSENGER); 694 } else if (sType.equals(Bundle.getMessage("EXPRESS_FREIGHT"))) { 695 setTrainType(EXPRESS_FREIGHT); 696 } else if (sType.equals(Bundle.getMessage("EXPRESS_PASSENGER"))) { 697 setTrainType(EXPRESS_PASSENGER); 698 } else if (sType.equals(Bundle.getMessage("MOW"))) { 699 setTrainType(MOW); 700 } 701 } 702 703 public int getTrainType() { 704 return mTrainType; 705 } 706 707 public String getTrainTypeText() { 708 if (mTrainType == LOCAL_FREIGHT) { 709 return Bundle.getMessage("LOCAL_FREIGHT"); 710 } else if (mTrainType == LOCAL_PASSENGER) { 711 return Bundle.getMessage("LOCAL_PASSENGER"); 712 } else if (mTrainType == THROUGH_FREIGHT) { 713 return Bundle.getMessage("THROUGH_FREIGHT"); 714 } else if (mTrainType == THROUGH_PASSENGER) { 715 return Bundle.getMessage("THROUGH_PASSENGER"); 716 } else if (mTrainType == EXPRESS_FREIGHT) { 717 return Bundle.getMessage("EXPRESS_FREIGHT"); 718 } else if (mTrainType == EXPRESS_PASSENGER) { 719 return Bundle.getMessage("EXPRESS_PASSENGER"); 720 } else if (mTrainType == MOW) { 721 return Bundle.getMessage("MOW"); 722 } 723 return (""); 724 } 725 726 public int getMode() { 727 return mMode; 728 } 729 730 public void forcePassNextSafeSection() { 731 for (AllocatedSection as: mAllocatedSections) { 732 if (as.getTransitSection().getSection() == mLastAllocatedSection 733 && as.getTransitSection().isSafe() 734 && as.getNextSection().getOccupancy() == Section.UNOCCUPIED) { 735 mLastAllocOverrideSafe = mLastAllocatedSection; 736 } 737 } 738 } 739 740 public void setMode(int mode) { 741 if ((mode == AUTOMATIC) || (mode == MANUAL) 742 || (mode == DISPATCHED || mode == TERMINATED)) { 743 int old = mMode; 744 mMode = mode; 745 firePropertyChange("mode", Integer.valueOf(old), Integer.valueOf(mMode)); 746 } else { 747 log.error("Attempt to set ActiveTrain mode to illegal value - {}", mode); 748 } 749 } 750 751 public String getModeText() { 752 if (mMode == AUTOMATIC) { 753 return Bundle.getMessage("AUTOMATIC"); 754 } else if (mMode == MANUAL) { 755 return Bundle.getMessage("MANUAL"); 756 } else if (mMode == DISPATCHED) { 757 return Bundle.getMessage("DISPATCHED"); 758 } else if (mMode == TERMINATED) { 759 return Bundle.getMessage("TERMINATED"); 760 } 761 return (""); 762 } 763 764 public void setAutoActiveTrain(AutoActiveTrain aat) { 765 mAutoActiveTrain = aat; 766 } 767 768 public AutoActiveTrain getAutoActiveTrain() { 769 return mAutoActiveTrain; 770 } 771 772 public int getRunningDirectionFromSectionAndSeq(jmri.Section s, int seqNo) { 773 int dir = mTransit.getDirectionFromSectionAndSeq(s, seqNo); 774 if (mTransitReversed) { 775 if (dir == jmri.Section.FORWARD) { 776 dir = jmri.Section.REVERSE; 777 } else { 778 dir = jmri.Section.FORWARD; 779 } 780 } 781 return dir; 782 } 783 784 public int getAllocationDirectionFromSectionAndSeq(jmri.Section s, int seqNo) { 785 int dir = mTransit.getDirectionFromSectionAndSeq(s, seqNo); 786 if (mAllocationReversed) { 787 if (dir == jmri.Section.FORWARD) { 788 dir = jmri.Section.REVERSE; 789 } else { 790 dir = jmri.Section.FORWARD; 791 } 792 } 793 return dir; 794 } 795 796 public void addAllocatedSection(AllocatedSection as) { 797 if (as != null) { 798 mAllocatedSections.add(as); 799 if (as.getSection() == mNextSectionToAllocate) { 800 // this is the next Section in the Transit, update pointers 801 mLastAllocatedSection = as.getSection(); 802 mLastAllocOverrideSafe = null; 803 mLastAllocatedSectionSeqNumber = mNextSectionSeqNumber; 804 mNextSectionToAllocate = as.getNextSection(); 805 mNextSectionSeqNumber = as.getNextSectionSequence(); 806 mNextSectionDirection = getAllocationDirectionFromSectionAndSeq( 807 mNextSectionToAllocate, mNextSectionSeqNumber); 808 as.setAllocationNumber(mNextAllocationNumber); 809 mNextAllocationNumber++; 810 } else { 811 // this is an extra allocated Section 812 as.setAllocationNumber(-1); 813 } 814 if ((mStatus == WAITING) && mStarted) { 815 setStatus(RUNNING); 816 } 817 if (as.getSequence() == 2) { 818 mSecondAllocatedSection = as.getSection(); 819 } 820 if (mDispatcher.getNameInAllocatedBlock()) { 821 if (mDispatcher.getRosterEntryInBlock() && getRosterEntry() != null) { 822 as.getSection().setNameFromActiveBlock(getRosterEntry()); 823 } else { 824 as.getSection().setNameInBlocks(mTrainName); 825 } 826 as.getSection().suppressNameUpdate(true); 827 } 828 if (mDispatcher.getExtraColorForAllocated()) { 829 as.getSection().setAlternateColorFromActiveBlock(true); 830 } 831 // notify anyone interested 832 pcs.firePropertyChange("sectionallocated",as , null); 833 refreshPanel(); 834 } else { 835 log.error("Null Allocated Section reference in addAllocatedSection of ActiveTrain"); 836 } 837 } 838 839 private void refreshPanel() { 840 var editorManager = InstanceManager.getDefault(jmri.jmrit.display.EditorManager.class); 841 for (var panel : editorManager.getAll(jmri.jmrit.display.layoutEditor.LayoutEditor.class)) { 842 panel.redrawPanel(); 843 } 844 } 845 846 public void removeAllocatedSection(AllocatedSection as) { 847 if (as == null) { 848 log.error("Null AllocatedSection reference in removeAllocatedSection of ActiveTrain"); 849 return; 850 } 851 int index = -1; 852 for (int i = 0; i < mAllocatedSections.size(); i++) { 853 if (as == mAllocatedSections.get(i)) { 854 index = i; 855 } 856 } 857 if (index < 0) { 858 log.error("Attempt to remove an unallocated Section {}", as.getSection().getDisplayName(USERSYS)); 859 return; 860 } 861 mAllocatedSections.remove(index); 862 if (mDispatcher.getNameInAllocatedBlock()) { 863 as.getSection().clearNameInUnoccupiedBlocks(); 864 as.getSection().suppressNameUpdate(false); 865 } 866 for (Block b: as.getSection().getBlockList()) { 867 if (!mDispatcher.checkForBlockInAllocatedSection(b, as.getSection())) { 868 String userName = b.getUserName(); 869 if (userName != null) { 870 LayoutBlock lb = InstanceManager.getDefault(LayoutBlockManager.class).getByUserName(userName); 871 if (lb != null) { 872 lb.setUseExtraColor(false); 873 } 874 } 875 } 876 } 877 // notify anyone interested 878 pcs.firePropertyChange("sectiondeallocated",as , null); 879 refreshPanel(); 880 if (as.getSection() == mLastAllocatedSection) { 881 mLastAllocatedSection = null; 882 mLastAllocOverrideSafe = null; 883 if (mAllocatedSections.size() > 0) { 884 mLastAllocatedSection = mAllocatedSections.get( 885 mAllocatedSections.size() - 1).getSection(); 886 mLastAllocatedSectionSeqNumber = mAllocatedSections.size() - 1; 887 } 888 } 889 } 890 891 /** 892 * This resets the state of the ActiveTrain so that it can be reallocated. 893 */ 894 public void allocateAFresh() { 895 setStatus(WAITING); 896 holdAllocation = false; 897 setTransitReversed(false); 898 List<AllocatedSection> sectionsToRelease = new ArrayList<>(); 899 for (AllocatedSection as : mDispatcher.getAllocatedSectionsList()) { 900 if (as.getActiveTrain() == this) { 901 sectionsToRelease.add(as); 902 } 903 } 904 for (AllocatedSection as : sectionsToRelease) { 905 mDispatcher.releaseAllocatedSection(as, true); // need to find Allocated Section 906 mDispatcher.queueWaitForEmpty(); //ensure release processed before proceding. 907 as.getSection().setState(jmri.Section.FREE); 908 } 909 if (mLastAllocatedSection != null) { 910 mLastAllocatedSection.setState(jmri.Section.FREE); 911 } 912 resetAllAllocatedSections(); 913 clearAllocations(); 914 setAllocationReversed(false); 915 // wait for AutoAllocate to do complete. 916 mDispatcher.queueWaitForEmpty(); 917 if (mAutoRun) { 918 mAutoActiveTrain.allocateAFresh(); 919 } 920 mDispatcher.allocateNewActiveTrain(this); 921 } 922 923 public void clearAllocations() { 924 for (AllocatedSection as : getAllocatedSectionList()) { 925 removeAllocatedSection(as); 926 } 927 } 928 929 public List<AllocatedSection> getAllocatedSectionList() { 930 List<AllocatedSection> list = new ArrayList<>(); 931 for (int i = 0; i < mAllocatedSections.size(); i++) { 932 list.add(mAllocatedSections.get(i)); 933 } 934 return list; 935 } 936 937 /** 938 * Returns list of all Blocks occupied by or allocated to this train. They 939 * are in order from the tail of the train to the head of the train then on 940 * to the forward-most allocated block. Note that unoccupied blocks can 941 * exist before and after the occupied blocks. 942 * 943 * TODO: doesn't handle reversing of adjacent multi-block sections well 944 * 945 * @return the list of blocks order of occupation 946 */ 947 public List<Block> getBlockList() { 948 List<Block> list = new ArrayList<>(); 949 for (int i = 0; i < mAllocatedSections.size(); i++) { // loop thru allocated sections, then all blocks for each section 950 Section s = mAllocatedSections.get(i).getSection(); 951 List<Block> bl = s.getBlockList(); 952 if (bl.size() > 1) { //sections with multiple blocks need extra logic 953 954 boolean blocksConnected = true; 955 //determine if blocks should be added in forward or reverse order based on connectivity 956 if (i == 0) { //for first section, compare last block to first of next section 957 if (mAllocatedSections.size() > 1 958 && //only one section, assume forward 959 !connected(bl.get(bl.size() - 1), mAllocatedSections.get(i + 1).getSection().getBlockList().get(0))) { 960 blocksConnected = false; 961 } 962 } else { //not first section, check for connectivity between last block in list, and first block in this section 963 if (!connected(list.get(list.size() - 1), bl.get(0))) { //last block is not connected to first block, add reverse 964 blocksConnected = false; 965 } 966 } 967 if (blocksConnected) { //blocks were connected, so add to outgoing in forward order 968 for (int j = 0; j < bl.size(); j++) { 969 Block b = bl.get(j); 970 list.add(b); 971 log.trace("block {} ({}) added to list for Section {} (fwd)", b.getDisplayName(USERSYS), 972 (b.getState() == Block.OCCUPIED ? "OCCUPIED" : "UNOCCUPIED"), 973 s.getDisplayName(USERSYS)); 974 } 975 } else { //not connected, add in reverse order 976 for (int j = bl.size() - 1; j >= 0; j--) { 977 Block b = bl.get(j); 978 list.add(b); 979 log.trace("block {} ({}) added to list for Section {} (rev)", b.getDisplayName(USERSYS), 980 (b.getState() == Block.OCCUPIED ? "OCCUPIED" : "UNOCCUPIED"), 981 s.getDisplayName(USERSYS)); 982 } 983 } 984 985 } else { //single block sections are simply added to the outgoing list 986 Block b = bl.get(0); 987 list.add(b); 988 log.trace("block {} ({}) added to list for Section {} (one)", b.getDisplayName(USERSYS), 989 (b.getState() == Block.OCCUPIED ? "OCCUPIED" : "UNOCCUPIED"), 990 s.getDisplayName(USERSYS)); 991 } 992 } 993 return list; 994 } 995 996 /* copied from Section.java */ 997 private boolean connected(Block b1, Block b2) { 998 if ((b1 != null) && (b2 != null)) { 999 List<Path> paths = b1.getPaths(); 1000 for (int i = 0; i < paths.size(); i++) { 1001 if (paths.get(i).getBlock() == b2) { 1002 return true; 1003 } 1004 } 1005 } 1006 return false; 1007 } 1008 1009 public jmri.Section getLastAllocatedSection() { 1010 return mLastAllocatedSection; 1011 } 1012 1013 public Section getLastAllocOverrideSafe() { 1014 return mLastAllocOverrideSafe; 1015 } 1016 1017 public int getLastAllocatedSectionSeqNumber() { 1018 return mLastAllocatedSectionSeqNumber; 1019 } 1020 1021 public String getLastAllocatedSectionName() { 1022 if (mLastAllocatedSection == null) { 1023 return "<" + Bundle.getMessage("None").toLowerCase() + ">"; // <none> 1024 } 1025 return getSectionName(mLastAllocatedSection); 1026 } 1027 1028 public jmri.Section getNextSectionToAllocate() { 1029 return mNextSectionToAllocate; 1030 } 1031 1032 public int getNextSectionSeqNumber() { 1033 return mNextSectionSeqNumber; 1034 } 1035 1036 public String getNextSectionToAllocateName() { 1037 if (mNextSectionToAllocate == null) { 1038 return "<" + Bundle.getMessage("None").toLowerCase() + ">"; // <none> 1039 } 1040 return getSectionName(mNextSectionToAllocate); 1041 } 1042 1043 private String getSectionName(jmri.Section sc) { 1044 String s = sc.getDisplayName(); 1045 return s; 1046 } 1047 1048 public jmri.Block getStartBlock() { 1049 return mStartBlock; 1050 } 1051 1052 public void setStartBlock(jmri.Block sBlock) { 1053 mStartBlock = sBlock; 1054 } 1055 1056 public int getStartBlockSectionSequenceNumber() { 1057 return mStartBlockSectionSequenceNumber; 1058 } 1059 1060 public void setStartBlockSectionSequenceNumber(int sBlockSeqNum) { 1061 mStartBlockSectionSequenceNumber = sBlockSeqNum; 1062 } 1063 1064 public jmri.Block getEndBlock() { 1065 return mEndBlock; 1066 } 1067 1068 public void setEndBlock(jmri.Block eBlock) { 1069 mEndBlock = eBlock; 1070 } 1071 1072 public jmri.Section getEndBlockSection() { 1073 return mEndBlockSection; 1074 } 1075 1076 public void setEndBlockSection(jmri.Section eSection) { 1077 mEndBlockSection = eSection; 1078 } 1079 1080 public int getEndBlockSectionSequenceNumber() { 1081 return mEndBlockSectionSequenceNumber; 1082 } 1083 1084 public void setEndBlockSectionSequenceNumber(int eBlockSeqNum) { 1085 mEndBlockSectionSequenceNumber = eBlockSeqNum; 1086 } 1087 1088 public int getPriority() { 1089 return mPriority; 1090 } 1091 1092 public void setPriority(int priority) { 1093 mPriority = priority; 1094 } 1095 1096 public boolean getAutoRun() { 1097 return mAutoRun; 1098 } 1099 1100 public void setAutoRun(boolean autoRun) { 1101 mAutoRun = autoRun; 1102 } 1103 1104 public String getDccAddress() { 1105 return mDccAddress; 1106 } 1107 1108 public void setDccAddress(String dccAddress) { 1109 mDccAddress = dccAddress; 1110 } 1111 1112 public boolean getResetWhenDone() { 1113 return mResetWhenDone; 1114 } 1115 1116 public void setResetWhenDone(boolean s) { 1117 mResetWhenDone = s; 1118 } 1119 1120 public boolean getReverseAtEnd() { 1121 return mReverseAtEnd; 1122 } 1123 1124 public void setReverseAtEnd(boolean s) { 1125 mReverseAtEnd = s; 1126 } 1127 1128 protected jmri.Section getSecondAllocatedSection() { 1129 return mSecondAllocatedSection; 1130 } 1131 1132 /** 1133 * Returns the AllocateM Method to be used by autoAllocate 1134 * 1135 * @return The number of Blocks ahead to be allocated or 0 = Allocate By Safe 1136 * sections or -1 - Allocate All The Way. 1137 */ 1138 public int getAllocateMethod() { 1139 return mAllocateMethod; 1140 } 1141 1142 /** 1143 * Sets the Allocation Method to be used bu autoAllocate 1144 * @param i The number of Blocks ahead to be allocated or 0 = Allocate By Safe 1145 * sections or -1 - Allocate All The Way. 1146 */ 1147 public void setAllocateMethod(int i) { 1148 mAllocateMethod = i; 1149 } 1150 1151 // 1152 // Operating methods 1153 // 1154 public AllocationRequest initializeFirstAllocation() { 1155 if (mAllocatedSections.size() > 0) { 1156 log.error("ERROR - Request to initialize first allocation, when allocations already present"); 1157 return null; 1158 } 1159 if ((mStartBlockSectionSequenceNumber > 0) && (mStartBlock != null)) { 1160 mNextSectionToAllocate = mTransit.getSectionFromBlockAndSeq(mStartBlock, 1161 mStartBlockSectionSequenceNumber); 1162 if (mNextSectionToAllocate == null) { 1163 mNextSectionToAllocate = mTransit.getSectionFromConnectedBlockAndSeq(mStartBlock, 1164 mStartBlockSectionSequenceNumber); 1165 if (mNextSectionToAllocate == null) { 1166 log.error("ERROR - Cannot find Section for first allocation of ActiveTrain{}", getActiveTrainName()); 1167 return null; 1168 } 1169 } 1170 mNextSectionSeqNumber = mStartBlockSectionSequenceNumber; 1171 mNextSectionDirection = getAllocationDirectionFromSectionAndSeq(mNextSectionToAllocate, 1172 mNextSectionSeqNumber); 1173 } else { 1174 log.error("ERROR - Insufficient information to initialize first allocation"); 1175 return null; 1176 } 1177 if (!mDispatcher.requestAllocation(this, 1178 mNextSectionToAllocate, mNextSectionDirection, mNextSectionSeqNumber, true, null, true)) { 1179 log.error("Allocation request failed for first allocation of {}", getActiveTrainName()); 1180 } 1181 if (mDispatcher.getRosterEntryInBlock() && getRosterEntry() != null) { 1182 mStartBlock.setValue(getRosterEntry()); 1183 } else if (mDispatcher.getShortNameInBlock()) { 1184 mStartBlock.setValue(mTrainName); 1185 } 1186 AllocationRequest ar = mDispatcher.findAllocationRequestInQueue(mNextSectionToAllocate, 1187 mNextSectionSeqNumber, mNextSectionDirection, this); 1188 return ar; 1189 } 1190 1191 protected boolean addEndSection(jmri.Section s, int seq) { 1192 AllocatedSection as = mAllocatedSections.get(mAllocatedSections.size() - 1); 1193 if (!as.setNextSection(s, seq)) { 1194 return false; 1195 } 1196 setEndBlockSection(s); 1197 setEndBlockSectionSequenceNumber(seq); 1198 //At this stage the section direction hasn't been set, by default the exit block returned is the reverse if the section is free 1199 setEndBlock(s.getExitBlock()); 1200 mNextSectionSeqNumber = seq; 1201 mNextSectionToAllocate = s; 1202 return true; 1203 } 1204 1205 /*This is for use where the transit has been extended, then the last section has been cancelled no 1206 checks are performed, these should be done by a higher level code*/ 1207 protected void removeLastAllocatedSection() { 1208 AllocatedSection as = mAllocatedSections.get(mAllocatedSections.size() - 1); 1209 //Set the end block using the AllocatedSections exit block before clearing the next section in the allocatedsection 1210 setEndBlock(as.getExitBlock()); 1211 1212 as.setNextSection(null, 0); 1213 setEndBlockSection(as.getSection()); 1214 1215 setEndBlockSectionSequenceNumber(getEndBlockSectionSequenceNumber() - 1); 1216 // In theory the following values should have already been set if there are no more sections to allocate. 1217 mNextSectionSeqNumber = 0; 1218 mNextSectionToAllocate = null; 1219 } 1220 1221 protected AllocatedSection reverseAllAllocatedSections() { 1222 AllocatedSection aSec = null; 1223 for (int i = 0; i < mAllocatedSections.size(); i++) { 1224 aSec = mAllocatedSections.get(i); 1225 int dir = mTransit.getDirectionFromSectionAndSeq(aSec.getSection(), aSec.getSequence()); 1226 if (dir == jmri.Section.FORWARD) { 1227 aSec.getSection().setState(jmri.Section.REVERSE); 1228 } else { 1229 aSec.getSection().setState(jmri.Section.FORWARD); 1230 } 1231 aSec.setStoppingSensors(); 1232 } 1233 return aSec; 1234 } 1235 1236 protected void resetAllAllocatedSections() { 1237 for (int i = 0; i < mAllocatedSections.size(); i++) { 1238 AllocatedSection aSec = mAllocatedSections.get(i); 1239 int dir = mTransit.getDirectionFromSectionAndSeq(aSec.getSection(), aSec.getSequence()); 1240 aSec.getSection().setState(dir); 1241 aSec.setStoppingSensors(); 1242 } 1243 } 1244 1245 protected void setRestart(int delayType, int restartDelay, Sensor delaySensor, boolean resetSensorAfter) { 1246 if (delayType == NODELAY) { 1247 holdAllocation(false); 1248 return; 1249 } 1250 1251 setStatus(READY); 1252 restartPoint = true; 1253 if (delayType == TIMEDDELAY) { 1254 Date now = jmri.InstanceManager.getDefault(jmri.Timebase.class).getTime(); 1255 @SuppressWarnings("deprecation") // Date.getHours 1256 int nowHours = now.getHours(); 1257 @SuppressWarnings("deprecation") // Date.getMinutes 1258 int nowMinutes = now.getMinutes(); 1259 int hours = restartDelay / 60; 1260 int minutes = restartDelay % 60; 1261 restartHr = nowHours + hours + ((nowMinutes + minutes) / 60); 1262 restartMin = ((nowMinutes + minutes) % 60); 1263 if (restartHr>23){ 1264 restartHr=restartHr-24; 1265 } 1266 } 1267 mDispatcher.addDelayedTrain(this, delayType, delaySensor, resetSensorAfter ); 1268 } 1269 1270 protected boolean isInAllocatedList(AllocatedSection as) { 1271 for (int i = 0; i < mAllocatedSections.size(); i++) { 1272 if (mAllocatedSections.get(i) == as) { 1273 return true; 1274 } 1275 } 1276 return false; 1277 } 1278 1279 protected boolean isInAllocatedList(Section s) { 1280 for (int i = 0; i < mAllocatedSections.size(); i++) { 1281 if ((mAllocatedSections.get(i)).getSection() == s) { 1282 return true; 1283 } 1284 } 1285 return false; 1286 } 1287 1288 1289 boolean restartPoint = false; 1290 1291 private boolean holdAllocation = false; 1292 1293 protected void holdAllocation(boolean boo) { 1294 holdAllocation = boo; 1295 } 1296 1297 protected boolean holdAllocation() { 1298 return holdAllocation; 1299 } 1300 1301 protected boolean reachedRestartPoint() { 1302 return restartPoint; 1303 } 1304 1305 protected void restart() { 1306 log.debug("{}: restarting", getTrainName()); 1307 restartPoint = false; 1308 holdAllocation(false); 1309 setStatus(WAITING); 1310 if (mAutoActiveTrain != null) { 1311 mAutoActiveTrain.setupNewCurrentSignal(null,true); 1312 } 1313 } 1314 1315 public void terminate() { 1316 mDispatcher.removeDelayedTrain(this); 1317 if (getDelaySensor() != null && delaySensorListener != null) { 1318 getDelaySensor().removePropertyChangeListener(delaySensorListener); 1319 } 1320 if (getRestartSensor() != null && restartSensorListener != null) { 1321 getRestartSensor().removePropertyChangeListener(restartSensorListener); 1322 } 1323 setMode(TERMINATED); 1324 mTransit.setState(Transit.IDLE); 1325 deleteAdHocTransit(mTransit); 1326 } 1327 1328 private void deleteAdHocTransit(Transit sysname) { 1329 Transit adht = sysname; 1330 if (adht != null && adht.getTransitType() == TransitType.DYNAMICADHOC) { 1331 List<Section> tmpSecs = new ArrayList<Section>(); 1332 for (TransitSection ts : adht.getTransitSectionList()) { 1333 if (ts.getSection().getSectionType() == SectionType.DYNAMICADHOC) { 1334 tmpSecs.add(ts.getSection()); 1335 } 1336 } 1337 InstanceManager.getDefault(jmri.TransitManager.class).deleteTransit(adht); 1338 for (Section ts : tmpSecs) { 1339 InstanceManager.getDefault(jmri.SectionManager.class).deleteSection(ts); 1340 } 1341 } 1342 } 1343 1344 public void dispose() { 1345 if (getTransit()!=null) { 1346 getTransit().removeTemporarySections(); 1347 } 1348 } 1349 1350 // Property Change Support 1351 private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); 1352 1353 @OverridingMethodsMustInvokeSuper 1354 protected void firePropertyChange(String p, Object old, Object n) { 1355 pcs.firePropertyChange(p, old, n); 1356 } 1357 1358 @Override 1359 public void addPropertyChangeListener(PropertyChangeListener listener) { 1360 pcs.addPropertyChangeListener(listener); 1361 } 1362 1363 @Override 1364 public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { 1365 pcs.addPropertyChangeListener(propertyName, listener); 1366 } 1367 1368 @Override 1369 public PropertyChangeListener[] getPropertyChangeListeners() { 1370 return pcs.getPropertyChangeListeners(); 1371 } 1372 1373 @Override 1374 public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { 1375 return pcs.getPropertyChangeListeners(propertyName); 1376 } 1377 1378 @Override 1379 public void removePropertyChangeListener(PropertyChangeListener listener) { 1380 pcs.removePropertyChangeListener(listener); 1381 } 1382 1383 @Override 1384 public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { 1385 pcs.removePropertyChangeListener(propertyName, listener); 1386 } 1387 1388 private final static Logger log = LoggerFactory.getLogger(ActiveTrain.class); 1389 1390}