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