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