001package jmri.jmrit.operations.rollingstock.cars; 002 003import java.beans.PropertyChangeEvent; 004 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008import jmri.InstanceManager; 009import jmri.jmrit.operations.locations.*; 010import jmri.jmrit.operations.locations.schedules.Schedule; 011import jmri.jmrit.operations.locations.schedules.ScheduleItem; 012import jmri.jmrit.operations.rollingstock.RollingStock; 013import jmri.jmrit.operations.routes.RouteLocation; 014import jmri.jmrit.operations.trains.schedules.TrainSchedule; 015import jmri.jmrit.operations.trains.schedules.TrainScheduleManager; 016import jmri.jmrit.operations.trains.trainbuilder.TrainCommon; 017 018/** 019 * Represents a car on the layout 020 * 021 * @author Daniel Boudreau Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014, 022 * 2015, 2023, 2025 023 */ 024public class Car extends RollingStock { 025 026 CarLoads carLoads = InstanceManager.getDefault(CarLoads.class); 027 028 protected boolean _passenger = false; 029 protected boolean _hazardous = false; 030 protected boolean _caboose = false; 031 protected boolean _fred = false; 032 protected boolean _utility = false; 033 protected boolean _loadGeneratedByStaging = false; 034 protected Kernel _kernel = null; 035 protected String _loadName = carLoads.getDefaultEmptyName(); 036 protected int _wait = 0; 037 038 protected boolean _clone = false; 039 protected int _cloneOrder = 9999999; 040 041 protected Location _rweDestination = null; // return when empty destination 042 protected Track _rweDestTrack = null; // return when empty track 043 protected String _rweLoadName = carLoads.getDefaultEmptyName(); 044 045 protected Location _rwlDestination = null; // return when loaded destination 046 protected Track _rwlDestTrack = null; // return when loaded track 047 protected String _rwlLoadName = carLoads.getDefaultLoadName(); 048 049 // schedule items 050 protected String _scheduleId = NONE; // the schedule id assigned to this car 051 protected String _nextLoadName = NONE; // next load by schedule 052 protected Location _finalDestination = null; 053 protected Track _finalDestTrack = null; // final track by schedule or router 054 protected Location _previousFinalDestination = null; 055 protected Track _previousFinalDestTrack = null; 056 protected String _previousScheduleId = NONE; 057 protected String _pickupScheduleId = NONE; 058 059 protected String _routePath = NONE; 060 061 public static final String EXTENSION_REGEX = " "; 062 public static final String CABOOSE_EXTENSION = Bundle.getMessage("(C)"); 063 public static final String FRED_EXTENSION = Bundle.getMessage("(F)"); 064 public static final String PASSENGER_EXTENSION = Bundle.getMessage("(P)"); 065 public static final String UTILITY_EXTENSION = Bundle.getMessage("(U)"); 066 public static final String HAZARDOUS_EXTENSION = Bundle.getMessage("(H)"); 067 public static final String CLONE = TrainCommon.HYPHEN + "(Clone)"; // NOI18N 068 // parentheses are special chars 069 public static final String CLONE_REGEX = TrainCommon.HYPHEN + "\\(Clone\\)"; // NOI18N 070 071 public static final String LOAD_CHANGED_PROPERTY = "Car load changed"; // NOI18N 072 public static final String RWE_LOAD_CHANGED_PROPERTY = "Car RWE load changed"; // NOI18N 073 public static final String RWL_LOAD_CHANGED_PROPERTY = "Car RWL load changed"; // NOI18N 074 public static final String WAIT_CHANGED_PROPERTY = "Car wait changed"; // NOI18N 075 public static final String FINAL_DESTINATION_CHANGED_PROPERTY = "Car final destination changed"; // NOI18N 076 public static final String FINAL_DESTINATION_TRACK_CHANGED_PROPERTY = "Car final destination track changed"; // NOI18N 077 public static final String RETURN_WHEN_EMPTY_CHANGED_PROPERTY = "Car return when empty changed"; // NOI18N 078 public static final String RETURN_WHEN_LOADED_CHANGED_PROPERTY = "Car return when loaded changed"; // NOI18N 079 public static final String SCHEDULE_ID_CHANGED_PROPERTY = "car schedule id changed"; // NOI18N 080 public static final String KERNEL_NAME_CHANGED_PROPERTY = "kernel name changed"; // NOI18N 081 082 public Car() { 083 super(); 084 loaded = true; 085 } 086 087 public Car(String road, String number) { 088 super(road, number); 089 loaded = true; 090 log.debug("New car ({} {})", road, number); 091 addPropertyChangeListeners(); 092 } 093 094 public Car copy() { 095 Car car = new Car(); 096 car.setBuilt(getBuilt()); 097 car.setColor(getColor()); 098 car.setLength(getLength()); 099 car.setLoadName(getLoadName()); 100 car.setWeightTons(getWeightTons()); 101 car.setReturnWhenEmptyLoadName(getReturnWhenEmptyLoadName()); 102 car.setReturnWhenLoadedLoadName(getReturnWhenLoadedLoadName()); 103 car.setNumber(getNumber()); 104 car.setOwnerName(getOwnerName()); 105 car.setRoadName(getRoadName()); 106 car.setTypeName(getTypeName()); 107 car.setComment(getComment()); 108 car.setCarHazardous(isCarHazardous()); 109 car.setCaboose(isCaboose()); 110 car.setFred(hasFred()); 111 car.setPassenger(isPassenger()); 112 car.setBlocking(getBlocking()); 113 car.setLastTrain(getLastTrain()); 114 car.setLastDate(getLastDate()); 115 car.setLoadGeneratedFromStaging(isLoadGeneratedFromStaging()); 116 car.setDivision(getDivision()); 117 car.loaded = true; 118 return car; 119 } 120 121 public void setCarHazardous(boolean hazardous) { 122 boolean old = _hazardous; 123 _hazardous = hazardous; 124 if (!old == hazardous) { 125 setDirtyAndFirePropertyChange("car hazardous", old ? "true" : "false", hazardous ? "true" : "false"); // NOI18N 126 } 127 } 128 129 public boolean isCarHazardous() { 130 return _hazardous; 131 } 132 133 public boolean isCarLoadHazardous() { 134 return carLoads.isHazardous(getTypeName(), getLoadName()); 135 } 136 137 /** 138 * Used to determine if the car is hazardous or the car's load is hazardous. 139 * 140 * @return true if the car or car's load is hazardous. 141 */ 142 public boolean isHazardous() { 143 return isCarHazardous() || isCarLoadHazardous(); 144 } 145 146 public void setPassenger(boolean passenger) { 147 boolean old = _passenger; 148 _passenger = passenger; 149 if (!old == passenger) { 150 setDirtyAndFirePropertyChange("car passenger", old ? "true" : "false", passenger ? "true" : "false"); // NOI18N 151 } 152 } 153 154 public boolean isPassenger() { 155 return _passenger; 156 } 157 158 public void setFred(boolean fred) { 159 boolean old = _fred; 160 _fred = fred; 161 if (!old == fred) { 162 setDirtyAndFirePropertyChange("car has fred", old ? "true" : "false", fred ? "true" : "false"); // NOI18N 163 } 164 } 165 166 /** 167 * Used to determine if car has FRED (Flashing Rear End Device). 168 * 169 * @return true if car has FRED. 170 */ 171 public boolean hasFred() { 172 return _fred; 173 } 174 175 public void setClone(boolean clone) { 176 boolean old = _clone; 177 _clone = clone; 178 if (!old == clone) { 179 setDirtyAndFirePropertyChange("car clone", old ? "true" : "false", clone ? "true" : "false"); // NOI18N 180 } 181 } 182 183 public boolean isClone() { 184 return _clone; 185 } 186 187 public void setCloneOrder(int number) { 188 _cloneOrder = number; 189 } 190 191 public int getCloneOrder() { 192 return _cloneOrder; 193 } 194 195 public void setLoadName(String load) { 196 String old = _loadName; 197 _loadName = load; 198 if (!old.equals(load)) { 199 setDirtyAndFirePropertyChange(LOAD_CHANGED_PROPERTY, old, load); 200 } 201 } 202 203 /** 204 * The load name assigned to this car. 205 * 206 * @return The load name assigned to this car. 207 */ 208 public String getLoadName() { 209 return _loadName; 210 } 211 212 public void setReturnWhenEmptyLoadName(String load) { 213 String old = _rweLoadName; 214 _rweLoadName = load; 215 if (!old.equals(load)) { 216 setDirtyAndFirePropertyChange(RWE_LOAD_CHANGED_PROPERTY, old, load); 217 } 218 } 219 220 public String getReturnWhenEmptyLoadName() { 221 return _rweLoadName; 222 } 223 224 public void setReturnWhenLoadedLoadName(String load) { 225 String old = _rwlLoadName; 226 _rwlLoadName = load; 227 if (!old.equals(load)) { 228 setDirtyAndFirePropertyChange(RWL_LOAD_CHANGED_PROPERTY, old, load); 229 } 230 } 231 232 public String getReturnWhenLoadedLoadName() { 233 return _rwlLoadName; 234 } 235 236 /** 237 * Gets the car's load's priority. 238 * 239 * @return The car's load priority. 240 */ 241 public String getLoadPriority() { 242 return (carLoads.getPriority(getTypeName(), getLoadName())); 243 } 244 245 /** 246 * Gets the car load's type, empty or load. 247 * 248 * @return type empty or type load 249 */ 250 public String getLoadType() { 251 return (carLoads.getLoadType(getTypeName(), getLoadName())); 252 } 253 254 public String getPickupComment() { 255 return carLoads.getPickupComment(getTypeName(), getLoadName()); 256 } 257 258 public String getDropComment() { 259 return carLoads.getDropComment(getTypeName(), getLoadName()); 260 } 261 262 public void setLoadGeneratedFromStaging(boolean fromStaging) { 263 _loadGeneratedByStaging = fromStaging; 264 } 265 266 public boolean isLoadGeneratedFromStaging() { 267 return _loadGeneratedByStaging; 268 } 269 270 /** 271 * Used to keep track of which item in a schedule was used for this car. 272 * 273 * @param id The ScheduleItem id for this car. 274 */ 275 public void setScheduleItemId(String id) { 276 log.debug("Set schedule item id ({}) for car ({})", id, toString()); 277 String old = _scheduleId; 278 _scheduleId = id; 279 if (!old.equals(id)) { 280 setDirtyAndFirePropertyChange(SCHEDULE_ID_CHANGED_PROPERTY, old, id); 281 } 282 } 283 284 public String getScheduleItemId() { 285 return _scheduleId; 286 } 287 288 public ScheduleItem getScheduleItem(Track track) { 289 ScheduleItem si = null; 290 // arrived at spur? 291 if (track != null && track.isSpur() && !getScheduleItemId().equals(NONE)) { 292 Schedule sch = track.getSchedule(); 293 if (sch == null) { 294 log.error("Schedule null for car ({}) at spur ({})", toString(), track.getName()); 295 } else { 296 si = sch.getItemById(getScheduleItemId()); 297 } 298 } 299 return si; 300 } 301 302 /** 303 * Only here for backwards compatibility before version 5.1.4. The next load 304 * name for this car. Normally set by a schedule. 305 * 306 * @param load the next load name. 307 */ 308 public void setNextLoadName(String load) { 309 String old = _nextLoadName; 310 _nextLoadName = load; 311 if (!old.equals(load)) { 312 setDirtyAndFirePropertyChange(LOAD_CHANGED_PROPERTY, old, load); 313 } 314 } 315 316 public String getNextLoadName() { 317 return _nextLoadName; 318 } 319 320 @Override 321 public String getWeightTons() { 322 String weight = super.getWeightTons(); 323 if (!_weightTons.equals(DEFAULT_WEIGHT)) { 324 return weight; 325 } 326 if (!isCaboose() && !isPassenger()) { 327 return weight; 328 } 329 // .9 tons/foot for caboose and passenger cars 330 try { 331 weight = Integer.toString((int) (Double.parseDouble(getLength()) * .9)); 332 } catch (Exception e) { 333 log.debug("Car ({}) length not set for caboose or passenger car", toString()); 334 } 335 return weight; 336 } 337 338 /** 339 * Returns a car's weight adjusted for load. An empty car's weight is 1/3 340 * the car's loaded weight. 341 */ 342 @Override 343 public int getAdjustedWeightTons() { 344 int weightTons = 0; 345 try { 346 // get loaded weight 347 weightTons = Integer.parseInt(getWeightTons()); 348 // adjust for empty weight if car is empty, 1/3 of loaded weight 349 if (!isCaboose() && !isPassenger() && getLoadType().equals(CarLoad.LOAD_TYPE_EMPTY)) { 350 weightTons = weightTons / 3; 351 } 352 } catch (NumberFormatException e) { 353 log.debug("Car ({}) weight not set", toString()); 354 } 355 return weightTons; 356 } 357 358 public void setWait(int count) { 359 int old = _wait; 360 _wait = count; 361 if (old != count) { 362 setDirtyAndFirePropertyChange(WAIT_CHANGED_PROPERTY, old, count); 363 } 364 } 365 366 public int getWait() { 367 return _wait; 368 } 369 370 /** 371 * Sets when this car will be picked up (day of the week) 372 * 373 * @param id See TrainSchedule.java 374 */ 375 public void setPickupScheduleId(String id) { 376 String old = _pickupScheduleId; 377 _pickupScheduleId = id; 378 if (!old.equals(id)) { 379 setDirtyAndFirePropertyChange("car pickup schedule changes", old, id); // NOI18N 380 } 381 } 382 383 public String getPickupScheduleId() { 384 return _pickupScheduleId; 385 } 386 387 public String getPickupScheduleName() { 388 if (getTrain() != null) { 389 return getPickupTime(); 390 } 391 TrainSchedule sch = InstanceManager.getDefault(TrainScheduleManager.class) 392 .getScheduleById(getPickupScheduleId()); 393 if (sch != null) { 394 return sch.getName(); 395 } 396 return NONE; 397 } 398 399 /** 400 * Sets the final destination for a car. 401 * 402 * @param destination The final destination for this car. 403 */ 404 public void setFinalDestination(Location destination) { 405 Location old = _finalDestination; 406 if (old != null) { 407 old.removePropertyChangeListener(this); 408 } 409 _finalDestination = destination; 410 if (_finalDestination != null) { 411 _finalDestination.addPropertyChangeListener(this); 412 } 413 if ((old != null && !old.equals(destination)) || (destination != null && !destination.equals(old))) { 414 setRoutePath(NONE); 415 setDirtyAndFirePropertyChange(FINAL_DESTINATION_CHANGED_PROPERTY, old, destination); 416 } 417 } 418 419 public Location getFinalDestination() { 420 return _finalDestination; 421 } 422 423 public String getFinalDestinationName() { 424 if (getFinalDestination() != null) { 425 return getFinalDestination().getName(); 426 } 427 return NONE; 428 } 429 430 public String getSplitFinalDestinationName() { 431 return TrainCommon.splitString(getFinalDestinationName()); 432 } 433 434 public void setFinalDestinationTrack(Track track) { 435 Track old = _finalDestTrack; 436 _finalDestTrack = track; 437 if ((old != null && !old.equals(track)) || (track != null && !track.equals(old))) { 438 if (old != null) { 439 old.removePropertyChangeListener(this); 440 old.deleteReservedInRoute(this); 441 } 442 if (_finalDestTrack != null) { 443 _finalDestTrack.addReservedInRoute(this); 444 _finalDestTrack.addPropertyChangeListener(this); 445 } 446 setDirtyAndFirePropertyChange(FINAL_DESTINATION_TRACK_CHANGED_PROPERTY, old, track); 447 } 448 } 449 450 public Track getFinalDestinationTrack() { 451 return _finalDestTrack; 452 } 453 454 public String getFinalDestinationTrackName() { 455 if (getFinalDestinationTrack() != null) { 456 return getFinalDestinationTrack().getName(); 457 } 458 return NONE; 459 } 460 461 public String getSplitFinalDestinationTrackName() { 462 return TrainCommon.splitString(getFinalDestinationTrackName()); 463 } 464 465 public void setPreviousFinalDestination(Location location) { 466 _previousFinalDestination = location; 467 } 468 469 public Location getPreviousFinalDestination() { 470 return _previousFinalDestination; 471 } 472 473 public String getPreviousFinalDestinationName() { 474 if (getPreviousFinalDestination() != null) { 475 return getPreviousFinalDestination().getName(); 476 } 477 return NONE; 478 } 479 480 public void setPreviousFinalDestinationTrack(Track track) { 481 _previousFinalDestTrack = track; 482 } 483 484 public Track getPreviousFinalDestinationTrack() { 485 return _previousFinalDestTrack; 486 } 487 488 public String getPreviousFinalDestinationTrackName() { 489 if (getPreviousFinalDestinationTrack() != null) { 490 return getPreviousFinalDestinationTrack().getName(); 491 } 492 return NONE; 493 } 494 495 public void setPreviousScheduleId(String id) { 496 _previousScheduleId = id; 497 } 498 499 public String getPreviousScheduleId() { 500 return _previousScheduleId; 501 } 502 503 public void setReturnWhenEmptyDestination(Location destination) { 504 Location old = _rweDestination; 505 _rweDestination = destination; 506 if ((old != null && !old.equals(destination)) || (destination != null && !destination.equals(old))) { 507 setDirtyAndFirePropertyChange(RETURN_WHEN_EMPTY_CHANGED_PROPERTY, null, null); 508 } 509 } 510 511 public Location getReturnWhenEmptyDestination() { 512 return _rweDestination; 513 } 514 515 public String getReturnWhenEmptyDestinationName() { 516 if (getReturnWhenEmptyDestination() != null) { 517 return getReturnWhenEmptyDestination().getName(); 518 } 519 return NONE; 520 } 521 522 public String getSplitReturnWhenEmptyDestinationName() { 523 return TrainCommon.splitString(getReturnWhenEmptyDestinationName()); 524 } 525 526 public void setReturnWhenEmptyDestTrack(Track track) { 527 Track old = _rweDestTrack; 528 _rweDestTrack = track; 529 if ((old != null && !old.equals(track)) || (track != null && !track.equals(old))) { 530 setDirtyAndFirePropertyChange(RETURN_WHEN_EMPTY_CHANGED_PROPERTY, null, null); 531 } 532 } 533 534 public Track getReturnWhenEmptyDestTrack() { 535 return _rweDestTrack; 536 } 537 538 public String getReturnWhenEmptyDestTrackName() { 539 if (getReturnWhenEmptyDestTrack() != null) { 540 return getReturnWhenEmptyDestTrack().getName(); 541 } 542 return NONE; 543 } 544 545 public String getSplitReturnWhenEmptyDestinationTrackName() { 546 return TrainCommon.splitString(getReturnWhenEmptyDestTrackName()); 547 } 548 549 public void setReturnWhenLoadedDestination(Location destination) { 550 Location old = _rwlDestination; 551 _rwlDestination = destination; 552 if ((old != null && !old.equals(destination)) || (destination != null && !destination.equals(old))) { 553 setDirtyAndFirePropertyChange(RETURN_WHEN_LOADED_CHANGED_PROPERTY, null, null); 554 } 555 } 556 557 public Location getReturnWhenLoadedDestination() { 558 return _rwlDestination; 559 } 560 561 public String getReturnWhenLoadedDestinationName() { 562 if (getReturnWhenLoadedDestination() != null) { 563 return getReturnWhenLoadedDestination().getName(); 564 } 565 return NONE; 566 } 567 568 public void setReturnWhenLoadedDestTrack(Track track) { 569 Track old = _rwlDestTrack; 570 _rwlDestTrack = track; 571 if ((old != null && !old.equals(track)) || (track != null && !track.equals(old))) { 572 setDirtyAndFirePropertyChange(RETURN_WHEN_LOADED_CHANGED_PROPERTY, null, null); 573 } 574 } 575 576 public Track getReturnWhenLoadedDestTrack() { 577 return _rwlDestTrack; 578 } 579 580 public String getReturnWhenLoadedDestTrackName() { 581 if (getReturnWhenLoadedDestTrack() != null) { 582 return getReturnWhenLoadedDestTrack().getName(); 583 } 584 return NONE; 585 } 586 587 /** 588 * Used to determine is car has been given a Return When Loaded (RWL) 589 * address or custom load 590 * 591 * @return true if car has RWL 592 */ 593 protected boolean isRwlEnabled() { 594 if (!getReturnWhenLoadedLoadName().equals(carLoads.getDefaultLoadName()) || 595 getReturnWhenLoadedDestination() != null) { 596 return true; 597 } 598 return false; 599 } 600 601 public void setRoutePath(String routePath) { 602 String old = _routePath; 603 _routePath = routePath; 604 if (!old.equals(routePath)) { 605 setDirtyAndFirePropertyChange("Route path change", old, routePath); 606 } 607 } 608 609 public String getRoutePath() { 610 return _routePath; 611 } 612 613 public void setCaboose(boolean caboose) { 614 boolean old = _caboose; 615 _caboose = caboose; 616 if (!old == caboose) { 617 setDirtyAndFirePropertyChange("car is caboose", old ? "true" : "false", caboose ? "true" : "false"); // NOI18N 618 } 619 } 620 621 public boolean isCaboose() { 622 return _caboose; 623 } 624 625 public void setUtility(boolean utility) { 626 boolean old = _utility; 627 _utility = utility; 628 if (!old == utility) { 629 setDirtyAndFirePropertyChange("car is utility", old ? "true" : "false", utility ? "true" : "false"); // NOI18N 630 } 631 } 632 633 public boolean isUtility() { 634 return _utility; 635 } 636 637 /** 638 * Used to determine if car is performing a local move. A local move is when 639 * a car is moved to a different track at the same location. 640 * 641 * @return true if local move 642 */ 643 public boolean isLocalMove() { 644 if (getTrain() == null && getLocation() != null) { 645 return getSplitLocationName().equals(getSplitDestinationName()); 646 } 647 if (getRouteLocation() == null || getRouteDestination() == null) { 648 return false; 649 } 650 if (getRouteLocation().equals(getRouteDestination()) && getTrack() != null) { 651 return true; 652 } 653 if (getTrain().isLocalSwitcher() && 654 getRouteLocation().getSplitName() 655 .equals(getRouteDestination().getSplitName()) && 656 getTrack() != null) { 657 return true; 658 } 659 // look for sequential locations with the "same" name 660 if (getRouteLocation().getSplitName().equals( 661 getRouteDestination().getSplitName()) && getTrain().getRoute() != null) { 662 boolean foundRl = false; 663 for (RouteLocation rl : getTrain().getRoute().getLocationsBySequenceList()) { 664 if (foundRl) { 665 if (getRouteDestination().getSplitName() 666 .equals(rl.getSplitName())) { 667 // user can specify the "same" location two more more 668 // times in a row 669 if (getRouteDestination() != rl) { 670 continue; 671 } else { 672 return true; 673 } 674 } else { 675 return false; 676 } 677 } 678 if (getRouteLocation().equals(rl)) { 679 foundRl = true; 680 } 681 } 682 } 683 return false; 684 } 685 686 /** 687 * A kernel is a group of cars that are switched as a unit. 688 * 689 * @param kernel The assigned Kernel for this car. 690 */ 691 public void setKernel(Kernel kernel) { 692 if (_kernel == kernel) { 693 return; 694 } 695 String old = ""; 696 if (_kernel != null) { 697 old = _kernel.getName(); 698 _kernel.delete(this); 699 } 700 _kernel = kernel; 701 String newName = ""; 702 if (_kernel != null) { 703 _kernel.add(this); 704 newName = _kernel.getName(); 705 } 706 if (!old.equals(newName)) { 707 setDirtyAndFirePropertyChange(KERNEL_NAME_CHANGED_PROPERTY, old, newName); // NOI18N 708 } 709 } 710 711 public Kernel getKernel() { 712 return _kernel; 713 } 714 715 public String getKernelName() { 716 if (_kernel != null) { 717 return _kernel.getName(); 718 } 719 return NONE; 720 } 721 722 /** 723 * Used to determine if car is lead car in a kernel 724 * 725 * @return true if lead car in a kernel 726 */ 727 public boolean isLead() { 728 if (getKernel() != null) { 729 return getKernel().isLead(this); 730 } 731 return false; 732 } 733 734 /** 735 * Updates all cars in a kernel. After the update, the cars will all have 736 * the same final destination, load, and route path. 737 */ 738 public void updateKernel() { 739 if (isLead()) { 740 for (Car car : getKernel().getCars()) { 741 car.setScheduleItemId(getScheduleItemId()); 742 car.setFinalDestination(getFinalDestination()); 743 car.setFinalDestinationTrack(getFinalDestinationTrack()); 744 car.setLoadGeneratedFromStaging(isLoadGeneratedFromStaging()); 745 car.setRoutePath(getRoutePath()); 746 car.setWait(getWait()); 747 if (InstanceManager.getDefault(CarLoads.class).containsName(car.getTypeName(), getLoadName())) { 748 car.setLoadName(getLoadName()); 749 } 750 } 751 } 752 } 753 754 /** 755 * Returns the car length or the length of the car's kernel including 756 * couplers. 757 * 758 * @return length of car or kernel 759 */ 760 public int getTotalKernelLength() { 761 if (getKernel() != null) { 762 return getKernel().getTotalLength(); 763 } 764 return getTotalLength(); 765 } 766 767 /** 768 * Used to determine if a car can be set out at a destination (location). 769 * Track is optional. In addition to all of the tests that checkDestination 770 * performs, spurs with schedules are also checked. 771 * 772 * @return status OKAY, TYPE, ROAD, LENGTH, ERROR_TRACK, CAPACITY, SCHEDULE, 773 * CUSTOM 774 */ 775 @Override 776 public String checkDestination(Location destination, Track track) { 777 String status = super.checkDestination(destination, track); 778 if (!status.equals(Track.OKAY) && !status.startsWith(Track.LENGTH)) { 779 return status; 780 } 781 // now check to see if the track has a schedule 782 if (track == null) { 783 return status; 784 } 785 String statusSchedule = track.checkSchedule(this); 786 if (status.startsWith(Track.LENGTH) && statusSchedule.equals(Track.OKAY)) { 787 return status; 788 } 789 return statusSchedule; 790 } 791 792 /** 793 * Sets the car's destination on the layout 794 * 795 * @param track (yard, spur, staging, or interchange track) 796 * @return "okay" if successful, "type" if the rolling stock's type isn't 797 * acceptable, or "length" if the rolling stock length didn't fit, 798 * or Schedule if the destination will not accept the car because 799 * the spur has a schedule and the car doesn't meet the schedule 800 * requirements. Also changes the car load status when the car 801 * reaches its destination. 802 */ 803 @Override 804 public String setDestination(Location destination, Track track) { 805 return setDestination(destination, track, !Car.FORCE); 806 } 807 808 /** 809 * Sets the car's destination on the layout 810 * 811 * @param track (yard, spur, staging, or interchange track) 812 * @param force when true ignore track length, type, and road when setting 813 * destination 814 * @return "okay" if successful, "type" if the rolling stock's type isn't 815 * acceptable, or "length" if the rolling stock length didn't fit, 816 * or Schedule if the destination will not accept the car because 817 * the spur has a schedule and the car doesn't meet the schedule 818 * requirements. Also changes the car load status when the car 819 * reaches its destination. Removes car if clone. 820 */ 821 @Override 822 public String setDestination(Location destination, Track track, boolean force) { 823 // save destination name and track in case car has reached its 824 // destination 825 String destinationName = getDestinationName(); 826 Track destinationTrack = getDestinationTrack(); 827 String status = super.setDestination(destination, track, force); 828 // return if not Okay 829 if (!status.equals(Track.OKAY)) { 830 return status; 831 } 832 // now check to see if the track has a schedule 833 if (track != null && destinationTrack != track && loaded) { 834 status = track.scheduleNext(this); 835 if (!status.equals(Track.OKAY)) { 836 return status; 837 } 838 } 839 // done? 840 if (destinationName.equals(NONE) || (destination != null) || getTrain() == null) { 841 return status; 842 } 843 // car was in a train and has been dropped off, update load, RWE could 844 // set a new final destination 845 if (isClone()) { 846 // destroy clone 847 InstanceManager.getDefault(KernelManager.class).deleteKernel(getKernelName()); 848 InstanceManager.getDefault(CarManager.class).deregister(this); 849 } else { 850 loadNext(destinationTrack); 851 } 852 return status; 853 } 854 855 /** 856 * Called when setting a car's destination to this spur. Loads the car with 857 * a final destination which is the ship address for the schedule item. 858 * 859 * @param scheduleItem The schedule item to be applied this this car 860 */ 861 public void loadNext(ScheduleItem scheduleItem) { 862 if (scheduleItem == null) { 863 return; // should never be null 864 } 865 // set the car's final destination and track 866 setFinalDestination(scheduleItem.getDestination()); 867 setFinalDestinationTrack(scheduleItem.getDestinationTrack()); 868 // bump hit count for this schedule item 869 scheduleItem.setHits(scheduleItem.getHits() + 1); 870 // set all cars in kernel same final destination 871 updateKernel(); 872 } 873 874 /** 875 * Called when car is delivered to track. Updates the car's wait, pickup 876 * day, and load if spur. If staging, can swap default loads, force load to 877 * default empty, or replace custom loads with the default empty load. Can 878 * trigger RWE or RWL. 879 * 880 * @param track the destination track for this car 881 */ 882 public void loadNext(Track track) { 883 setLoadGeneratedFromStaging(false); 884 if (track != null) { 885 if (track.isSpur()) { 886 ScheduleItem si = getScheduleItem(track); 887 if (si == null) { 888 log.debug("Schedule item ({}) is null for car ({}) at spur ({})", getScheduleItemId(), toString(), 889 track.getName()); 890 } else { 891 setWait(si.getWait()); 892 setPickupScheduleId(si.getPickupTrainScheduleId()); 893 } 894 updateLoad(track); 895 } 896 // update load optionally when car reaches staging 897 else if (track.isStaging()) { 898 if (track.isLoadSwapEnabled() && getLoadName().equals(carLoads.getDefaultEmptyName())) { 899 setLoadLoaded(); 900 } else if ((track.isLoadSwapEnabled() || track.isLoadEmptyEnabled()) && 901 getLoadName().equals(carLoads.getDefaultLoadName())) { 902 setLoadEmpty(); 903 } else if (track.isRemoveCustomLoadsEnabled() && 904 !getLoadName().equals(carLoads.getDefaultEmptyName()) && 905 !getLoadName().equals(carLoads.getDefaultLoadName())) { 906 // remove this car's final destination if it has one 907 setFinalDestination(null); 908 setFinalDestinationTrack(null); 909 if (getLoadType().equals(CarLoad.LOAD_TYPE_EMPTY) && isRwlEnabled()) { 910 setLoadLoaded(); 911 // car arriving into staging with the RWE load? 912 } else if (getLoadName().equals(getReturnWhenEmptyLoadName())) { 913 setLoadName(carLoads.getDefaultEmptyName()); 914 } else { 915 setLoadEmpty(); // note that RWE sets the car's final 916 // destination 917 } 918 } 919 } 920 } 921 } 922 923 /** 924 * Updates a car's load when placed at a spur. Load change delayed if wait 925 * count is greater than zero. 926 * 927 * @param track The spur the car is sitting on 928 */ 929 public void updateLoad(Track track) { 930 if (track.isDisableLoadChangeEnabled()) { 931 return; 932 } 933 if (getWait() > 0) { 934 return; // change load name when wait count reaches 0 935 } 936 // arriving at spur with a schedule? 937 String loadName = NONE; 938 ScheduleItem si = getScheduleItem(track); 939 if (si != null) { 940 loadName = si.getShipLoadName(); // can be NONE 941 } else { 942 // for backwards compatibility before version 5.1.4 943 log.debug("Schedule item ({}) is null for car ({}) at spur ({}), using next load name", getScheduleItemId(), 944 toString(), track.getName()); 945 loadName = getNextLoadName(); 946 } 947 setNextLoadName(NONE); 948 if (!loadName.equals(NONE)) { 949 setLoadName(loadName); 950 // RWE or RWL load and no destination? 951 if (getLoadName().equals(getReturnWhenEmptyLoadName()) && getFinalDestination() == null) { 952 setReturnWhenEmpty(); 953 } else if (getLoadName().equals(getReturnWhenLoadedLoadName()) && getFinalDestination() == null) { 954 setReturnWhenLoaded(); 955 } 956 } else { 957 // flip load names 958 if (getLoadType().equals(CarLoad.LOAD_TYPE_EMPTY)) { 959 setLoadLoaded(); 960 } else { 961 setLoadEmpty(); 962 } 963 } 964 setScheduleItemId(Car.NONE); 965 } 966 967 /** 968 * Sets the car's load to empty, triggers RWE load and destination if 969 * enabled. 970 */ 971 private void setLoadEmpty() { 972 if (!getLoadName().equals(getReturnWhenEmptyLoadName())) { 973 setLoadName(getReturnWhenEmptyLoadName()); // default RWE load is 974 // the "E" load 975 setReturnWhenEmpty(); 976 } 977 } 978 979 /* 980 * Don't set return address if in staging with the same RWE address and 981 * don't set return address if at the RWE address 982 */ 983 private void setReturnWhenEmpty() { 984 if (getReturnWhenEmptyDestination() != null && 985 (getLocation() != getReturnWhenEmptyDestination() || 986 (!getReturnWhenEmptyDestination().isStaging() && 987 getTrack() != getReturnWhenEmptyDestTrack()))) { 988 setFinalDestination(getReturnWhenEmptyDestination()); 989 if (getReturnWhenEmptyDestTrack() != null) { 990 setFinalDestinationTrack(getReturnWhenEmptyDestTrack()); 991 } 992 log.debug("Car ({}) has return when empty destination ({}, {}) load {}", toString(), 993 getFinalDestinationName(), getFinalDestinationTrackName(), getLoadName()); 994 } 995 } 996 997 /** 998 * Sets the car's load to loaded, triggers RWL load and destination if 999 * enabled. 1000 */ 1001 private void setLoadLoaded() { 1002 if (!getLoadName().equals(getReturnWhenLoadedLoadName())) { 1003 setLoadName(getReturnWhenLoadedLoadName()); // default RWL load is 1004 // the "L" load 1005 setReturnWhenLoaded(); 1006 } 1007 } 1008 1009 /* 1010 * Don't set return address if in staging with the same RWL address and 1011 * don't set return address if at the RWL address 1012 */ 1013 private void setReturnWhenLoaded() { 1014 if (getReturnWhenLoadedDestination() != null && 1015 (getLocation() != getReturnWhenLoadedDestination() || 1016 (!getReturnWhenLoadedDestination().isStaging() && 1017 getTrack() != getReturnWhenLoadedDestTrack()))) { 1018 setFinalDestination(getReturnWhenLoadedDestination()); 1019 if (getReturnWhenLoadedDestTrack() != null) { 1020 setFinalDestinationTrack(getReturnWhenLoadedDestTrack()); 1021 } 1022 log.debug("Car ({}) has return when loaded destination ({}, {}) load {}", toString(), 1023 getFinalDestinationName(), getFinalDestinationTrackName(), getLoadName()); 1024 } 1025 } 1026 1027 public String getTypeExtensions() { 1028 StringBuffer buf = new StringBuffer(); 1029 if (isCaboose()) { 1030 buf.append(EXTENSION_REGEX + CABOOSE_EXTENSION); 1031 } 1032 if (hasFred()) { 1033 buf.append(EXTENSION_REGEX + FRED_EXTENSION); 1034 } 1035 if (isPassenger()) { 1036 buf.append(EXTENSION_REGEX + PASSENGER_EXTENSION + EXTENSION_REGEX + getBlocking()); 1037 } 1038 if (isUtility()) { 1039 buf.append(EXTENSION_REGEX + UTILITY_EXTENSION); 1040 } 1041 if (isCarHazardous()) { 1042 buf.append(EXTENSION_REGEX + HAZARDOUS_EXTENSION); 1043 } 1044 return buf.toString(); 1045 } 1046 1047 @Override 1048 public void reset() { 1049 setScheduleItemId(getPreviousScheduleId()); // revert to previous 1050 setNextLoadName(NONE); 1051 setFinalDestination(getPreviousFinalDestination()); 1052 setFinalDestinationTrack(getPreviousFinalDestinationTrack()); 1053 if (isLoadGeneratedFromStaging()) { 1054 setLoadGeneratedFromStaging(false); 1055 setLoadName(InstanceManager.getDefault(CarLoads.class).getDefaultEmptyName()); 1056 } 1057 super.reset(); 1058 destroyClone(); 1059 } 1060 1061 /* 1062 * This routine destroys the clone and restores the cloned car to its 1063 * original location and load. Note there can be multiple clones for a car. 1064 * Only the first clone created has the right info. A clone has creation 1065 * order number appended to the road number. 1066 */ 1067 private void destroyClone() { 1068 if (isClone()) { 1069 // move cloned car back to original location 1070 CarManager carManager = InstanceManager.getDefault(CarManager.class); 1071 String[] number = getNumber().split(Car.CLONE_REGEX); 1072 Car car = carManager.getByRoadAndNumber(getRoadName(), number[0]); 1073 int cloneCreationNumber = Integer.parseInt(number[1]); 1074 if (cloneCreationNumber <= car.getCloneOrder()) { 1075 car.setLocation(getLocation(), getTrack(), Car.FORCE); 1076 car.setLoadName(getLoadName()); 1077 car.setLastTrain(getLastTrain()); 1078 car.setLastDate(getLastDate()); 1079 car.setFinalDestination(getPreviousFinalDestination()); 1080 car.setFinalDestinationTrack(getPreviousFinalDestinationTrack()); 1081 car.setPreviousFinalDestination(getPreviousFinalDestination()); 1082 car.setPreviousFinalDestinationTrack(getPreviousFinalDestinationTrack()); 1083 car.setScheduleItemId(getPreviousScheduleId()); 1084 car.setWait(0); 1085 // remember the last clone destroyed 1086 car.setCloneOrder(cloneCreationNumber); 1087 } 1088 InstanceManager.getDefault(KernelManager.class).deleteKernel(getKernelName()); 1089 carManager.deregister(this); 1090 } 1091 } 1092 1093 @Override 1094 public void dispose() { 1095 setKernel(null); 1096 setFinalDestination(null); // removes property change listener 1097 setFinalDestinationTrack(null); // removes property change listener 1098 InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this); 1099 InstanceManager.getDefault(CarLengths.class).removePropertyChangeListener(this); 1100 super.dispose(); 1101 } 1102 1103 // used to stop a track's schedule from bumping when loading car database 1104 private boolean loaded = false; 1105 1106 /** 1107 * Construct this Entry from XML. This member has to remain synchronized 1108 * with the detailed DTD in operations-cars.dtd 1109 * 1110 * @param e Car XML element 1111 */ 1112 public Car(org.jdom2.Element e) { 1113 super(e); 1114 loaded = true; 1115 org.jdom2.Attribute a; 1116 if ((a = e.getAttribute(Xml.PASSENGER)) != null) { 1117 _passenger = a.getValue().equals(Xml.TRUE); 1118 } 1119 if ((a = e.getAttribute(Xml.HAZARDOUS)) != null) { 1120 _hazardous = a.getValue().equals(Xml.TRUE); 1121 } 1122 if ((a = e.getAttribute(Xml.CABOOSE)) != null) { 1123 _caboose = a.getValue().equals(Xml.TRUE); 1124 } 1125 if ((a = e.getAttribute(Xml.FRED)) != null) { 1126 _fred = a.getValue().equals(Xml.TRUE); 1127 } 1128 if ((a = e.getAttribute(Xml.UTILITY)) != null) { 1129 _utility = a.getValue().equals(Xml.TRUE); 1130 } 1131 if ((a = e.getAttribute(Xml.CLONE)) != null) { 1132 _clone = a.getValue().equals(Xml.TRUE); 1133 } 1134 if ((a = e.getAttribute(Xml.KERNEL)) != null) { 1135 Kernel k = InstanceManager.getDefault(KernelManager.class).getKernelByName(a.getValue()); 1136 if (k != null) { 1137 setKernel(k); 1138 if ((a = e.getAttribute(Xml.LEAD_KERNEL)) != null && a.getValue().equals(Xml.TRUE)) { 1139 _kernel.setLead(this); 1140 } 1141 } else { 1142 log.error("Kernel {} does not exist", a.getValue()); 1143 } 1144 } 1145 if ((a = e.getAttribute(Xml.LOAD)) != null) { 1146 _loadName = a.getValue(); 1147 } 1148 if ((a = e.getAttribute(Xml.LOAD_FROM_STAGING)) != null && a.getValue().equals(Xml.TRUE)) { 1149 setLoadGeneratedFromStaging(true); 1150 } 1151 if ((a = e.getAttribute(Xml.WAIT)) != null) { 1152 try { 1153 _wait = Integer.parseInt(a.getValue()); 1154 } catch (NumberFormatException nfe) { 1155 log.error("Wait count ({}) for car ({}) isn't a valid number!", a.getValue(), toString()); 1156 } 1157 } 1158 if ((a = e.getAttribute(Xml.PICKUP_SCHEDULE_ID)) != null) { 1159 _pickupScheduleId = a.getValue(); 1160 } 1161 if ((a = e.getAttribute(Xml.SCHEDULE_ID)) != null) { 1162 _scheduleId = a.getValue(); 1163 } 1164 // for backwards compatibility before version 5.1.4 1165 if ((a = e.getAttribute(Xml.NEXT_LOAD)) != null) { 1166 _nextLoadName = a.getValue(); 1167 } 1168 if ((a = e.getAttribute(Xml.NEXT_DEST_ID)) != null) { 1169 setFinalDestination(InstanceManager.getDefault(LocationManager.class).getLocationById(a.getValue())); 1170 } 1171 if (getFinalDestination() != null && (a = e.getAttribute(Xml.NEXT_DEST_TRACK_ID)) != null) { 1172 setFinalDestinationTrack(getFinalDestination().getTrackById(a.getValue())); 1173 } 1174 if ((a = e.getAttribute(Xml.PREVIOUS_NEXT_DEST_ID)) != null) { 1175 setPreviousFinalDestination( 1176 InstanceManager.getDefault(LocationManager.class).getLocationById(a.getValue())); 1177 } 1178 if (getPreviousFinalDestination() != null && (a = e.getAttribute(Xml.PREVIOUS_NEXT_DEST_TRACK_ID)) != null) { 1179 setPreviousFinalDestinationTrack(getPreviousFinalDestination().getTrackById(a.getValue())); 1180 } 1181 if ((a = e.getAttribute(Xml.PREVIOUS_SCHEDULE_ID)) != null) { 1182 setPreviousScheduleId(a.getValue()); 1183 } 1184 if ((a = e.getAttribute(Xml.RWE_DEST_ID)) != null) { 1185 _rweDestination = InstanceManager.getDefault(LocationManager.class).getLocationById(a.getValue()); 1186 } 1187 if (_rweDestination != null && (a = e.getAttribute(Xml.RWE_DEST_TRACK_ID)) != null) { 1188 _rweDestTrack = _rweDestination.getTrackById(a.getValue()); 1189 } 1190 if ((a = e.getAttribute(Xml.RWE_LOAD)) != null) { 1191 _rweLoadName = a.getValue(); 1192 } 1193 if ((a = e.getAttribute(Xml.RWL_DEST_ID)) != null) { 1194 _rwlDestination = InstanceManager.getDefault(LocationManager.class).getLocationById(a.getValue()); 1195 } 1196 if (_rwlDestination != null && (a = e.getAttribute(Xml.RWL_DEST_TRACK_ID)) != null) { 1197 _rwlDestTrack = _rwlDestination.getTrackById(a.getValue()); 1198 } 1199 if ((a = e.getAttribute(Xml.RWL_LOAD)) != null) { 1200 _rwlLoadName = a.getValue(); 1201 } 1202 if ((a = e.getAttribute(Xml.ROUTE_PATH)) != null) { 1203 _routePath = a.getValue(); 1204 } 1205 addPropertyChangeListeners(); 1206 } 1207 1208 /** 1209 * Create an XML element to represent this Entry. This member has to remain 1210 * synchronized with the detailed DTD in operations-cars.dtd. 1211 * 1212 * @return Contents in a JDOM Element 1213 */ 1214 public org.jdom2.Element store() { 1215 org.jdom2.Element e = new org.jdom2.Element(Xml.CAR); 1216 super.store(e); 1217 if (isPassenger()) { 1218 e.setAttribute(Xml.PASSENGER, isPassenger() ? Xml.TRUE : Xml.FALSE); 1219 } 1220 if (isCarHazardous()) { 1221 e.setAttribute(Xml.HAZARDOUS, isCarHazardous() ? Xml.TRUE : Xml.FALSE); 1222 } 1223 if (isCaboose()) { 1224 e.setAttribute(Xml.CABOOSE, isCaboose() ? Xml.TRUE : Xml.FALSE); 1225 } 1226 if (hasFred()) { 1227 e.setAttribute(Xml.FRED, hasFred() ? Xml.TRUE : Xml.FALSE); 1228 } 1229 if (isUtility()) { 1230 e.setAttribute(Xml.UTILITY, isUtility() ? Xml.TRUE : Xml.FALSE); 1231 } 1232 if (isClone()) { 1233 e.setAttribute(Xml.CLONE, isClone() ? Xml.TRUE : Xml.FALSE); 1234 } 1235 if (getKernel() != null) { 1236 e.setAttribute(Xml.KERNEL, getKernelName()); 1237 if (isLead()) { 1238 e.setAttribute(Xml.LEAD_KERNEL, Xml.TRUE); 1239 } 1240 } 1241 1242 e.setAttribute(Xml.LOAD, getLoadName()); 1243 1244 if (isLoadGeneratedFromStaging()) { 1245 e.setAttribute(Xml.LOAD_FROM_STAGING, Xml.TRUE); 1246 } 1247 1248 if (getWait() != 0) { 1249 e.setAttribute(Xml.WAIT, Integer.toString(getWait())); 1250 } 1251 1252 if (!getPickupScheduleId().equals(NONE)) { 1253 e.setAttribute(Xml.PICKUP_SCHEDULE_ID, getPickupScheduleId()); 1254 } 1255 1256 if (!getScheduleItemId().equals(NONE)) { 1257 e.setAttribute(Xml.SCHEDULE_ID, getScheduleItemId()); 1258 } 1259 1260 // for backwards compatibility before version 5.1.4 1261 if (!getNextLoadName().equals(NONE)) { 1262 e.setAttribute(Xml.NEXT_LOAD, getNextLoadName()); 1263 } 1264 1265 if (getFinalDestination() != null) { 1266 e.setAttribute(Xml.NEXT_DEST_ID, getFinalDestination().getId()); 1267 if (getFinalDestinationTrack() != null) { 1268 e.setAttribute(Xml.NEXT_DEST_TRACK_ID, getFinalDestinationTrack().getId()); 1269 } 1270 } 1271 1272 if (getPreviousFinalDestination() != null) { 1273 e.setAttribute(Xml.PREVIOUS_NEXT_DEST_ID, getPreviousFinalDestination().getId()); 1274 if (getPreviousFinalDestinationTrack() != null) { 1275 e.setAttribute(Xml.PREVIOUS_NEXT_DEST_TRACK_ID, getPreviousFinalDestinationTrack().getId()); 1276 } 1277 } 1278 1279 if (!getPreviousScheduleId().equals(NONE)) { 1280 e.setAttribute(Xml.PREVIOUS_SCHEDULE_ID, getPreviousScheduleId()); 1281 } 1282 1283 if (getReturnWhenEmptyDestination() != null) { 1284 e.setAttribute(Xml.RWE_DEST_ID, getReturnWhenEmptyDestination().getId()); 1285 if (getReturnWhenEmptyDestTrack() != null) { 1286 e.setAttribute(Xml.RWE_DEST_TRACK_ID, getReturnWhenEmptyDestTrack().getId()); 1287 } 1288 } 1289 if (!getReturnWhenEmptyLoadName().equals(carLoads.getDefaultEmptyName())) { 1290 e.setAttribute(Xml.RWE_LOAD, getReturnWhenEmptyLoadName()); 1291 } 1292 1293 if (getReturnWhenLoadedDestination() != null) { 1294 e.setAttribute(Xml.RWL_DEST_ID, getReturnWhenLoadedDestination().getId()); 1295 if (getReturnWhenLoadedDestTrack() != null) { 1296 e.setAttribute(Xml.RWL_DEST_TRACK_ID, getReturnWhenLoadedDestTrack().getId()); 1297 } 1298 } 1299 if (!getReturnWhenLoadedLoadName().equals(carLoads.getDefaultLoadName())) { 1300 e.setAttribute(Xml.RWL_LOAD, getReturnWhenLoadedLoadName()); 1301 } 1302 1303 if (!getRoutePath().isEmpty()) { 1304 e.setAttribute(Xml.ROUTE_PATH, getRoutePath()); 1305 } 1306 1307 return e; 1308 } 1309 1310 @Override 1311 protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) { 1312 // Set dirty 1313 InstanceManager.getDefault(CarManagerXml.class).setDirty(true); 1314 super.setDirtyAndFirePropertyChange(p, old, n); 1315 } 1316 1317 private void addPropertyChangeListeners() { 1318 InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this); 1319 InstanceManager.getDefault(CarLengths.class).addPropertyChangeListener(this); 1320 } 1321 1322 @Override 1323 public void propertyChange(PropertyChangeEvent e) { 1324 super.propertyChange(e); 1325 if (e.getPropertyName().equals(CarTypes.CARTYPES_NAME_CHANGED_PROPERTY)) { 1326 if (e.getOldValue().equals(getTypeName())) { 1327 log.debug("Car ({}) sees type name change old: ({}) new: ({})", toString(), e.getOldValue(), 1328 e.getNewValue()); // NOI18N 1329 setTypeName((String) e.getNewValue()); 1330 } 1331 } 1332 if (e.getPropertyName().equals(CarLengths.CARLENGTHS_NAME_CHANGED_PROPERTY)) { 1333 if (e.getOldValue().equals(getLength())) { 1334 log.debug("Car ({}) sees length name change old: ({}) new: ({})", toString(), e.getOldValue(), 1335 e.getNewValue()); // NOI18N 1336 setLength((String) e.getNewValue()); 1337 } 1338 } 1339 if (e.getPropertyName().equals(Location.DISPOSE_CHANGED_PROPERTY)) { 1340 if (e.getSource() == getFinalDestination()) { 1341 log.debug("delete final destination for car: ({})", toString()); 1342 setFinalDestination(null); 1343 } 1344 } 1345 if (e.getPropertyName().equals(Track.DISPOSE_CHANGED_PROPERTY)) { 1346 if (e.getSource() == getFinalDestinationTrack()) { 1347 log.debug("delete final destination for car: ({})", toString()); 1348 setFinalDestinationTrack(null); 1349 } 1350 } 1351 } 1352 1353 private final static Logger log = LoggerFactory.getLogger(Car.class); 1354 1355}