001package jmri.jmrit.operations.routes; 002 003import java.awt.Color; 004import java.awt.Point; 005 006import org.jdom2.Attribute; 007import org.jdom2.Element; 008import org.slf4j.Logger; 009import org.slf4j.LoggerFactory; 010 011import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 012import jmri.InstanceManager; 013import jmri.beans.PropertyChangeSupport; 014import jmri.jmrit.operations.locations.Location; 015import jmri.jmrit.operations.locations.LocationManager; 016import jmri.jmrit.operations.setup.Control; 017import jmri.jmrit.operations.setup.Setup; 018import jmri.jmrit.operations.trains.trainbuilder.TrainCommon; 019import jmri.util.ColorUtil; 020 021/** 022 * Represents a location in a route, a location can appear more than once in a 023 * route. 024 * 025 * @author Daniel Boudreau Copyright (C) 2008, 2013, 2026 026 */ 027public class RouteLocation extends PropertyChangeSupport implements java.beans.PropertyChangeListener { 028 029 public static final String NONE = ""; 030 031 protected String _id = NONE; 032 protected Location _location = null; // the location in the route 033 protected String _locationId = NONE; // the location's id 034 protected int _trainDir = (Setup.getTrainDirection() == Setup.EAST + Setup.WEST) ? EAST : NORTH; // train direction 035 protected int _maxTrainLength = Setup.getMaxTrainLength(); 036 protected int _maxCarMoves = Setup.getCarMoves(); 037 protected String _randomControl = DISABLED; 038 protected boolean _drops = true; // when true set outs allowed at this location 039 protected boolean _pickups = true; // when true pick ups allowed at this location 040 protected boolean _localMoves = true; // when true local moves allowed at this location 041 protected int _sequenceNum = 0; // used to determine location order in a route 042 protected double _grade = 0; // maximum grade between locations 043 protected int _wait = 0; // wait time at this location 044 protected String _departureTime = NONE; // hh:mm departure time from this location 045 protected String _departureDay = "0"; // departure day from this location 046 protected int _trainIconX = 0; // the x & y coordinates for the train icon 047 protected int _trainIconY = 0; 048 protected int _blockingOrder = 0; 049 protected String _comment = NONE; 050 protected Color _commentColor = Color.black; 051 052 protected int _carMoves = 0; // number of moves at this location 053 protected int _trainWeight = 0; // total car weight departing this location 054 protected int _trainLength = 0; // train length departing this location 055 056 public static final int EAST = 1; // train direction 057 public static final int WEST = 2; 058 public static final int NORTH = 4; 059 public static final int SOUTH = 8; 060 061 public static final String EAST_DIR = Setup.EAST_DIR; // train directions text 062 public static final String WEST_DIR = Setup.WEST_DIR; 063 public static final String NORTH_DIR = Setup.NORTH_DIR; 064 public static final String SOUTH_DIR = Setup.SOUTH_DIR; 065 066 public static final String DISPOSE = "routeLocationDispose"; // NOI18N 067 public static final String DELETED = Bundle.getMessage("locationDeleted"); 068 069 public static final String DROP_CHANGED_PROPERTY = "dropChange"; // NOI18N 070 public static final String PICKUP_CHANGED_PROPERTY = "pickupChange"; // NOI18N 071 public static final String LOCAL_MOVES_CHANGED_PROPERTY = "localMovesChange"; // NOI18N 072 public static final String MAX_MOVES_CHANGED_PROPERTY = "maxMovesChange"; // NOI18N 073 public static final String TRAIN_DIRECTION_CHANGED_PROPERTY = "trainDirectionChange"; // NOI18N 074 public static final String DEPARTURE_TIME_CHANGED_PROPERTY = "routeDepartureTimeChange"; // NOI18N 075 public static final String MAX_LENGTH_CHANGED_PROPERTY = "maxLengthChange"; // NOI18N 076 077 public static final String DISABLED = "Off"; 078 079 public RouteLocation(String id, Location location) { 080 log.debug("New route location ({}) id: {}", location.getName(), id); 081 _location = location; 082 _id = id; 083 // listen for name change or delete 084 location.addPropertyChangeListener(this); 085 } 086 087 // for combo boxes 088 @Override 089 public String toString() { 090 return getName(); 091 } 092 093 public String getId() { 094 return _id; 095 } 096 097 public String getName() { 098 if (getLocation() != null) { 099 return getLocation().getName(); 100 } 101 return DELETED; 102 } 103 104 public String getSplitName() { 105 if (getLocation() != null) { 106 return getLocation().getSplitName(); 107 } 108 return DELETED; 109 } 110 111 private String getNameId() { 112 if (_location != null) { 113 return _location.getId(); 114 } 115 return _locationId; 116 } 117 118 public Location getLocation() { 119 return _location; 120 } 121 122 public int getSequenceNumber() { 123 return _sequenceNum; 124 } 125 126 public void setSequenceNumber(int sequence) { 127 // property change not needed 128 _sequenceNum = sequence; 129 } 130 131 public int getBlockingOrder() { 132 return _blockingOrder; 133 } 134 135 public void setBlockingOrder(int order) { 136 _blockingOrder = order; 137 } 138 139 public void setComment(String comment) { 140 String old = _comment; 141 _comment = comment; 142 if (!old.equals(_comment)) { 143 setDirtyAndFirePropertyChange("RouteLocationComment", old, comment); // NOI18N 144 } 145 } 146 147 public String getComment() { 148 return _comment; 149 } 150 151 /** 152 * Sets the text color for the route comment 153 * 154 * @param color The color of the text 155 */ 156 public void setCommentColor(Color color) { 157 Color old = _commentColor; 158 _commentColor = color; 159 if (!old.equals(_commentColor)) { 160 setDirtyAndFirePropertyChange("RouteLocationCommentColor", old, color); // NOI18N 161 } 162 } 163 164 public Color getCommentColor() { 165 return _commentColor; 166 } 167 168 public String getCommentWithColor() { 169 return TrainCommon.formatColorString(getComment(), getCommentColor()); 170 } 171 172 public void setCommentTextColor(String color) { 173 setCommentColor(ColorUtil.stringToColor(color)); 174 } 175 176 public String getCommentTextColor() { 177 return ColorUtil.colorToColorName(getCommentColor()); 178 } 179 180 public void setTrainDirection(int direction) { 181 int old = _trainDir; 182 _trainDir = direction; 183 if (old != direction) { 184 setDirtyAndFirePropertyChange(TRAIN_DIRECTION_CHANGED_PROPERTY, Integer.toString(old), Integer 185 .toString(direction)); 186 } 187 } 188 189 /** 190 * Gets the binary representation of the train's direction at this location 191 * 192 * @return int representing train direction EAST WEST NORTH SOUTH 193 */ 194 public int getTrainDirection() { 195 return _trainDir; 196 } 197 198 /** 199 * Gets the String representation of the train's direction at this location 200 * 201 * @return String representing train direction at this location 202 */ 203 public String getTrainDirectionString() { 204 return Setup.getDirectionString(getTrainDirection()); 205 } 206 207 public void setMaxTrainLength(int length) { 208 int old = _maxTrainLength; 209 _maxTrainLength = length; 210 if (old != length) { 211 setDirtyAndFirePropertyChange(MAX_LENGTH_CHANGED_PROPERTY, Integer.toString(old), Integer.toString(length)); // NOI18N 212 } 213 } 214 215 public int getMaxTrainLength() { 216 return _maxTrainLength; 217 } 218 219 /** 220 * Set the train length departing this location when building a train 221 * 222 * @param length The train's current length. 223 */ 224 public void setTrainLength(int length) { 225 int old = _trainLength; 226 _trainLength = length; 227 if (old != length) { 228 firePropertyChange("trainLength", Integer.toString(old), Integer.toString(length)); // NOI18N 229 } 230 } 231 232 public int getTrainLength() { 233 return _trainLength; 234 } 235 236 /** 237 * Set the train weight departing this location when building a train 238 * 239 * @param weight The train's current weight. 240 */ 241 public void setTrainWeight(int weight) { 242 int old = _trainWeight; 243 _trainWeight = weight; 244 if (old != weight) { 245 firePropertyChange("trainWeight", Integer.toString(old), Integer.toString(weight)); // NOI18N 246 } 247 } 248 249 public int getTrainWeight() { 250 return _trainWeight; 251 } 252 253 public void setMaxCarMoves(int moves) { 254 int old = _maxCarMoves; 255 _maxCarMoves = moves; 256 if (old != moves) { 257 setDirtyAndFirePropertyChange(MAX_MOVES_CHANGED_PROPERTY, Integer.toString(old), Integer.toString(moves)); 258 } 259 } 260 261 /** 262 * Get the maximum number of moves for this location 263 * 264 * @return maximum number of moves 265 */ 266 public int getMaxCarMoves() { 267 return _maxCarMoves; 268 } 269 270 public void setRandomControl(String value) { 271 String old = _randomControl; 272 _randomControl = value; 273 if (!old.equals(value)) { 274 setDirtyAndFirePropertyChange("randomControl", old, value); // NOI18N 275 } 276 } 277 278 public String getRandomControl() { 279 return _randomControl; 280 } 281 282 /** 283 * When true allow car drops at this location 284 * 285 * @param drops when true drops allowed at this location 286 */ 287 public void setDropAllowed(boolean drops) { 288 boolean old = _drops; 289 _drops = drops; 290 if (old != drops) { 291 setDirtyAndFirePropertyChange(DROP_CHANGED_PROPERTY, old ? "true" : "false", drops ? "true" : "false"); // NOI18N 292 } 293 } 294 295 public boolean isDropAllowed() { 296 return _drops; 297 } 298 299 /** 300 * When true allow car pick ups at this location 301 * 302 * @param pickups when true pick ups allowed at this location 303 */ 304 public void setPickUpAllowed(boolean pickups) { 305 boolean old = _pickups; 306 _pickups = pickups; 307 if (old != pickups) { 308 setDirtyAndFirePropertyChange(PICKUP_CHANGED_PROPERTY, old ? "true" : "false", pickups ? "true" : "false"); // NOI18N 309 } 310 } 311 312 public boolean isPickUpAllowed() { 313 return _pickups; 314 } 315 316 /** 317 * When true allow local car moves at this location 318 * 319 * @param local when true local moves allowed at this location 320 */ 321 public void setLocalMovesAllowed(boolean local) { 322 boolean old = _localMoves; 323 _localMoves = local; 324 if (old != local) { 325 setDirtyAndFirePropertyChange(LOCAL_MOVES_CHANGED_PROPERTY, old ? "true" : "false", 326 local ? "true" : "false"); // NOI18N 327 } 328 } 329 330 public boolean isLocalMovesAllowed() { 331 return _localMoves; 332 } 333 334 /** 335 * Set the number of moves completed when building a train 336 * 337 * @param moves An integer representing the amount of moves completed. 338 */ 339 public void setCarMoves(int moves) { 340 int old = _carMoves; 341 _carMoves = moves; 342 if (old != moves) { 343 firePropertyChange("carMoves", Integer.toString(old), Integer.toString(moves)); // NOI18N 344 } 345 } 346 347 public int getCarMoves() { 348 return _carMoves; 349 } 350 351 public void setWait(int time) { 352 int old = _wait; 353 _wait = time; 354 if (old != time) { 355 setDirtyAndFirePropertyChange("waitTime", Integer.toString(old), Integer.toString(time)); // NOI18N 356 } 357 } 358 359 public int getWait() { 360 return _wait; 361 } 362 363 /** 364 * Sets the formated departure time from this location 365 * 366 * @param time format hours:minutes 367 */ 368 public void setDepartureTimeHourMinutes(String time) { 369 String old = _departureTime; 370 _departureTime = time; 371 if (!old.equals(time)) { 372 setDirtyAndFirePropertyChange(DEPARTURE_TIME_CHANGED_PROPERTY, old, time); 373 } 374 } 375 376 public String getDepartureTimeHourMinutes() { 377 return _departureTime; 378 } 379 380 /** 381 * Sets the departure time from this route location 382 * 383 * @param time days:hours:minutes or hours:minutes or NONE 384 */ 385 public void setDepartureTime(String time) { 386 String[] t = time.split(":"); 387 if (t.length > 2) { 388 setDepartureTime(t[0], t[1], t[2]); 389 } else if (t.length > 1) { 390 setDepartureTime("0", t[0], t[1]); 391 } else { 392 setDepartureTimeHourMinutes(NONE); 393 } 394 } 395 396 public void setDepartureTime(String day, String hour, String minute) { 397 setDepartureTimeDay(day); 398 hour = String.format("%02d", Integer.parseInt(hour)); 399 minute = String.format("%02d", Integer.parseInt(minute)); 400 String time = hour + ":" + minute; 401 setDepartureTimeHourMinutes(time); 402 } 403 404 /** 405 * @return departure time day:hour:minutes 406 */ 407 public String getDepartureTime() { 408 return getDepartureTimeDay() + ":" + getDepartureTimeHourMinutes(); 409 } 410 411 /** 412 * Sets the departure day from this route location 413 * 414 * @param day the day where "0" is today, and "1, 2 .." are the following 415 * days. 416 */ 417 public void setDepartureTimeDay(String day) { 418 String old = _departureDay; 419 if (!old.equals(day)) { 420 setDirtyAndFirePropertyChange(DEPARTURE_TIME_CHANGED_PROPERTY, old, day); 421 } 422 _departureDay = day; 423 } 424 425 public String getDepartureTimeDay() { 426 return _departureDay; 427 } 428 429 public String getDepartureTimeHour() { 430 String[] time = getDepartureTime().split(":"); 431 return time[1]; 432 } 433 434 public String getDepartureTimeMinute() { 435 String[] time = getDepartureTime().split(":"); 436 return time[2]; 437 } 438 439 /** 440 * Gets the formated departure time from this route location. Provides the 441 * day at the start if day is greater than zero. Format days:hours:minutes 442 * or hours:minutes if day = 0. Optional AM or PM 12 hour format. 443 * 444 * @return days:hours:minutes or hours:minutes. Optional AM/PM 445 */ 446 public String getFormatedDepartureTime() { 447 if (getDepartureTimeHourMinutes().equals(NONE)) { 448 return NONE; 449 } 450 String sDay = ""; 451 if (!getDepartureTimeDay().equals("0")) { 452 sDay = getDepartureTimeDay() + ":"; 453 } 454 if (!Setup.is12hrFormatEnabled()) { 455 return sDay + getDepartureTimeHourMinutes(); 456 } 457 String AM_PM = TrainCommon.SPACE + Bundle.getMessage("AM"); 458 int hour = Integer.parseInt(getDepartureTimeHour()); 459 if (hour >= 12) { 460 AM_PM = TrainCommon.SPACE + Bundle.getMessage("PM"); 461 hour = hour - 12; 462 } 463 if (hour == 0) { 464 hour = 12; 465 } 466 String shour = Integer.toString(hour); 467 return sDay + shour + ":" + getDepartureTimeMinute() + AM_PM; 468 } 469 470 @SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY", justification = "firing property change doesn't matter") 471 public void setGrade(double grade) { 472 double old = _grade; 473 _grade = grade; 474 if (old != grade) { 475 setDirtyAndFirePropertyChange("grade", Double.toString(old), Double.toString(grade)); // NOI18N 476 } 477 } 478 479 public double getGrade() { 480 return _grade; 481 } 482 483 public void setTrainIconX(int x) { 484 int old = _trainIconX; 485 _trainIconX = x; 486 if (old != x) { 487 setDirtyAndFirePropertyChange("trainIconX", Integer.toString(old), Integer.toString(x)); // NOI18N 488 } 489 } 490 491 public int getTrainIconX() { 492 return _trainIconX; 493 } 494 495 public void setTrainIconY(int y) { 496 int old = _trainIconY; 497 _trainIconY = y; 498 if (old != y) { 499 setDirtyAndFirePropertyChange("trainIconY", Integer.toString(old), Integer.toString(y)); // NOI18N 500 } 501 } 502 503 public int getTrainIconY() { 504 return _trainIconY; 505 } 506 507 /** 508 * Gets the X range for detecting the manual movement of a train icon. 509 * 510 * @return the range for detection 511 */ 512 public int getTrainIconRangeX() { 513 return getLocation().getTrainIconRangeX(); 514 } 515 516 /** 517 * Gets the Y range for detecting the manual movement of a train icon. 518 * 519 * @return the range for detection 520 */ 521 public int getTrainIconRangeY() { 522 return getLocation().getTrainIconRangeY(); 523 } 524 525 /** 526 * Set the train icon panel coordinates to the location defaults. 527 * Coordinates are dependent on the train's departure direction. 528 */ 529 public void setTrainIconCoordinates() { 530 Location l = InstanceManager.getDefault(LocationManager.class).getLocationByName(getName()); 531 if ((getTrainDirection() & Location.EAST) == Location.EAST) { 532 setTrainIconX(l.getTrainIconEast().x); 533 setTrainIconY(l.getTrainIconEast().y); 534 } 535 if ((getTrainDirection() & Location.WEST) == Location.WEST) { 536 setTrainIconX(l.getTrainIconWest().x); 537 setTrainIconY(l.getTrainIconWest().y); 538 } 539 if ((getTrainDirection() & Location.NORTH) == Location.NORTH) { 540 setTrainIconX(l.getTrainIconNorth().x); 541 setTrainIconY(l.getTrainIconNorth().y); 542 } 543 if ((getTrainDirection() & Location.SOUTH) == Location.SOUTH) { 544 setTrainIconX(l.getTrainIconSouth().x); 545 setTrainIconY(l.getTrainIconSouth().y); 546 } 547 } 548 549 public Point getTrainIconCoordinates() { 550 return new Point(getTrainIconX(), getTrainIconY()); 551 } 552 553 public void dispose() { 554 if (_location != null) { 555 _location.removePropertyChangeListener(this); 556 } 557 firePropertyChange(DISPOSE, null, DISPOSE); 558 } 559 560 /** 561 * Construct this Entry from XML. This member has to remain synchronized 562 * with the detailed DTD in operations-config.xml 563 * 564 * @param e Consist XML element 565 */ 566 public RouteLocation(Element e) { 567 Attribute a; 568 if ((a = e.getAttribute(Xml.ID)) != null) { 569 _id = a.getValue(); 570 } else { 571 log.warn("no id attribute in route location element when reading operations"); 572 } 573 if ((a = e.getAttribute(Xml.LOCATION_ID)) != null) { 574 _locationId = a.getValue(); 575 _location = InstanceManager.getDefault(LocationManager.class).getLocationById(a.getValue()); 576 if (_location != null) { 577 _location.addPropertyChangeListener(this); 578 } 579 } // old way of storing a route location 580 else if ((a = e.getAttribute(Xml.NAME)) != null) { 581 _location = InstanceManager.getDefault(LocationManager.class).getLocationByName(a.getValue()); 582 if (_location != null) { 583 _location.addPropertyChangeListener(this); 584 } 585 // force rewrite of route file 586 InstanceManager.getDefault(RouteManagerXml.class).setDirty(true); 587 } 588 if ((a = e.getAttribute(Xml.TRAIN_DIRECTION)) != null) { 589 // early releases had text for train direction 590 if (Setup.getTrainDirectionList().contains(a.getValue())) { 591 _trainDir = Setup.getDirectionInt(a.getValue()); 592 log.debug("found old train direction {} new direction {}", a.getValue(), _trainDir); 593 } else { 594 try { 595 _trainDir = Integer.parseInt(a.getValue()); 596 } catch (NumberFormatException ee) { 597 log.error("Route location ({}) direction ({}) is unknown", getName(), a.getValue()); 598 } 599 } 600 } 601 if ((a = e.getAttribute(Xml.MAX_TRAIN_LENGTH)) != null) { 602 try { 603 _maxTrainLength = Integer.parseInt(a.getValue()); 604 } catch (NumberFormatException ee) { 605 log.error("Route location ({}) maximum train length ({}) isn't a valid number", getName(), 606 a.getValue()); 607 } 608 } 609 if ((a = e.getAttribute(Xml.GRADE)) != null) { 610 try { 611 _grade = Double.parseDouble(a.getValue()); 612 } catch (NumberFormatException ee) { 613 log.error("Route location ({}) grade ({}) isn't a valid number", getName(), a.getValue()); 614 } 615 } 616 if ((a = e.getAttribute(Xml.MAX_CAR_MOVES)) != null) { 617 try { 618 _maxCarMoves = Integer.parseInt(a.getValue()); 619 } catch (NumberFormatException ee) { 620 log.error("Route location ({}) maximum car moves ({}) isn't a valid number", getName(), a.getValue()); 621 } 622 } 623 if ((a = e.getAttribute(Xml.RANDOM_CONTROL)) != null) { 624 _randomControl = a.getValue(); 625 } 626 if ((a = e.getAttribute(Xml.PICKUPS)) != null) { 627 _pickups = a.getValue().equals(Xml.YES); 628 } 629 if ((a = e.getAttribute(Xml.DROPS)) != null) { 630 _drops = a.getValue().equals(Xml.YES); 631 } 632 if ((a = e.getAttribute(Xml.LOCAL_MOVES)) != null) { 633 _localMoves = a.getValue().equals(Xml.YES); 634 } else { 635 if (!isPickUpAllowed() || !isDropAllowed()) { 636 _localMoves = false; // disable local moves 637 } 638 } 639 if ((a = e.getAttribute(Xml.WAIT)) != null) { 640 try { 641 _wait = Integer.parseInt(a.getValue()); 642 } catch (NumberFormatException ee) { 643 log.error("Route location ({}) wait ({}) isn't a valid number", getName(), a.getValue()); 644 } 645 } 646 if ((a = e.getAttribute(Xml.DEPART_DAY)) != null) { 647 _departureDay = a.getValue(); 648 } 649 if ((a = e.getAttribute(Xml.DEPART_TIME)) != null) { 650 _departureTime = a.getValue(); 651 } 652 if ((a = e.getAttribute(Xml.BLOCKING_ORDER)) != null) { 653 try { 654 _blockingOrder = Integer.parseInt(a.getValue()); 655 } catch (NumberFormatException ee) { 656 log.error("Route location ({}) blocking order ({}) isn't a valid number", getName(), a.getValue()); 657 } 658 } 659 if ((a = e.getAttribute(Xml.TRAIN_ICON_X)) != null) { 660 try { 661 _trainIconX = Integer.parseInt(a.getValue()); 662 } catch (NumberFormatException ee) { 663 log.error("Route location ({}) icon x ({}) isn't a valid number", getName(), a.getValue()); 664 } 665 } 666 if ((a = e.getAttribute(Xml.TRAIN_ICON_Y)) != null) { 667 try { 668 _trainIconY = Integer.parseInt(a.getValue()); 669 } catch (NumberFormatException ee) { 670 log.error("Route location ({}) icon y ({}) isn't a valid number", getName(), a.getValue()); 671 } 672 } 673 if ((a = e.getAttribute(Xml.SEQUENCE_ID)) != null) { 674 try { 675 _sequenceNum = Integer.parseInt(a.getValue()); 676 } catch (NumberFormatException ee) { 677 log.error("Route location ({}) sequence id isn't a valid number {}", getName(), a.getValue()); 678 } 679 } 680 if ((a = e.getAttribute(Xml.COMMENT_COLOR)) != null) { 681 setCommentTextColor(a.getValue()); 682 } 683 684 if ((a = e.getAttribute(Xml.COMMENT)) != null) { 685 _comment = a.getValue(); 686 } 687 } 688 689 /** 690 * Create an XML element to represent this Entry. This member has to remain 691 * synchronized with the detailed DTD in operations-config.xml. 692 * 693 * @return Contents in a JDOM Element 694 */ 695 public Element store() { 696 Element e = new Element(Xml.LOCATION); 697 e.setAttribute(Xml.ID, getId()); 698 e.setAttribute(Xml.NAME, getName()); 699 e.setAttribute(Xml.LOCATION_ID, getNameId()); 700 e.setAttribute(Xml.SEQUENCE_ID, Integer.toString(getSequenceNumber())); 701 e.setAttribute(Xml.TRAIN_DIRECTION, Integer.toString(getTrainDirection())); 702 e.setAttribute(Xml.MAX_TRAIN_LENGTH, Integer.toString(getMaxTrainLength())); 703 e.setAttribute(Xml.GRADE, Double.toString(getGrade())); 704 e.setAttribute(Xml.MAX_CAR_MOVES, Integer.toString(getMaxCarMoves())); 705 e.setAttribute(Xml.RANDOM_CONTROL, getRandomControl()); 706 e.setAttribute(Xml.PICKUPS, isPickUpAllowed() ? Xml.YES : Xml.NO); 707 e.setAttribute(Xml.DROPS, isDropAllowed() ? Xml.YES : Xml.NO); 708 e.setAttribute(Xml.LOCAL_MOVES, isLocalMovesAllowed() ? Xml.YES : Xml.NO); 709 e.setAttribute(Xml.WAIT, Integer.toString(getWait())); 710 e.setAttribute(Xml.DEPART_DAY, getDepartureTimeDay()); 711 e.setAttribute(Xml.DEPART_TIME, getDepartureTimeHourMinutes()); 712 e.setAttribute(Xml.BLOCKING_ORDER, Integer.toString(getBlockingOrder())); 713 e.setAttribute(Xml.TRAIN_ICON_X, Integer.toString(getTrainIconX())); 714 e.setAttribute(Xml.TRAIN_ICON_Y, Integer.toString(getTrainIconY())); 715 e.setAttribute(Xml.COMMENT_COLOR, getCommentTextColor()); 716 e.setAttribute(Xml.COMMENT, getComment()); 717 718 return e; 719 } 720 721 @Override 722 public void propertyChange(java.beans.PropertyChangeEvent e) { 723 if (Control.SHOW_PROPERTY) { 724 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e 725 .getNewValue()); 726 } 727 if (e.getPropertyName().equals(Location.DISPOSE_CHANGED_PROPERTY)) { 728 if (_location != null) { 729 _location.removePropertyChangeListener(this); 730 } 731 _location = null; 732 } 733 // forward property name change 734 if (e.getPropertyName().equals(Location.NAME_CHANGED_PROPERTY)) { 735 firePropertyChange(e.getPropertyName(), e.getOldValue(), e.getNewValue()); 736 } 737 } 738 739 protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) { 740 InstanceManager.getDefault(RouteManagerXml.class).setDirty(true); 741 firePropertyChange(p, old, n); 742 } 743 744 private final static Logger log = LoggerFactory.getLogger(RouteLocation.class); 745 746}