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