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