001package jmri.jmrit.operations.rollingstock.cars; 002 003import java.util.*; 004 005import javax.swing.JComboBox; 006 007import org.jdom2.Attribute; 008import org.jdom2.Element; 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012import jmri.InstanceManager; 013import jmri.InstanceManagerAutoDefault; 014import jmri.jmrit.operations.OperationsPanel; 015import jmri.jmrit.operations.rollingstock.RollingStockAttribute; 016import jmri.jmrit.operations.trains.TrainManifestHeaderText; 017import jmri.jmrit.operations.trains.trainbuilder.TrainCommon; 018 019/** 020 * Represents the loads that cars can have. 021 * 022 * @author Daniel Boudreau Copyright (C) 2008, 2014 023 */ 024public class CarLoads extends RollingStockAttribute implements InstanceManagerAutoDefault { 025 026 protected Hashtable<String, List<CarLoad>> listCarLoads = new Hashtable<>(); 027 protected String _emptyName = Bundle.getMessage("EmptyCar"); 028 protected String _loadName = Bundle.getMessage("LoadedCar"); 029 030 public static final String NONE = ""; // NOI18N 031 032 // for property change 033 public static final String LOAD_CHANGED_PROPERTY = "CarLoads_Load"; // NOI18N 034 public static final String LOAD_TYPE_CHANGED_PROPERTY = "CarLoads_Load_Type"; // NOI18N 035 public static final String LOAD_PRIORITY_CHANGED_PROPERTY = "CarLoads_Load_Priority"; // NOI18N 036 public static final String LOAD_NAME_CHANGED_PROPERTY = "CarLoads_Name"; // NOI18N 037 public static final String LOAD_COMMENT_CHANGED_PROPERTY = "CarLoads_Load_Comment"; // NOI18N 038 public static final String LOAD_HAZARDOUS_CHANGED_PROPERTY = "CarLoads_Load_Hazardous"; // NOI18N 039 040 public CarLoads() { 041 } 042 043 /** 044 * Add a car type with specific loads 045 * 046 * @param type car type 047 */ 048 public void addType(String type) { 049 listCarLoads.put(type, new ArrayList<>()); 050 } 051 052 /** 053 * Replace a car type. Transfers load type, priority, isHardous, drop and 054 * load comments. 055 * 056 * @param oldType old car type 057 * @param newType new car type 058 */ 059 public void replaceType(String oldType, String newType) { 060 List<String> names = getNames(oldType); 061 addType(newType); 062 for (String name : names) { 063 addName(newType, name); 064 setLoadType(newType, name, getLoadType(oldType, name)); 065 setPriority(newType, name, getPriority(oldType, name)); 066 setHazardous(newType, name, isHazardous(oldType, name)); 067 setDropComment(newType, name, getDropComment(oldType, name)); 068 setPickupComment(newType, name, getPickupComment(oldType, name)); 069 } 070 listCarLoads.remove(oldType); 071 } 072 073 /** 074 * Gets the appropriate car loads for the car's type. 075 * 076 * @param type Car type 077 * @return JComboBox with car loads starting with empty string. 078 */ 079 public JComboBox<String> getSelectComboBox(String type) { 080 JComboBox<String> box = new JComboBox<>(); 081 box.addItem(NONE); 082 for (String load : getNames(type)) { 083 box.addItem(load); 084 } 085 return box; 086 } 087 088 /** 089 * Gets the appropriate car loads for the car's type. 090 * 091 * @param type Car type 092 * @return JComboBox with car loads. 093 */ 094 public JComboBox<String> getComboBox(String type) { 095 JComboBox<String> box = new JComboBox<>(); 096 updateComboBox(type, box); 097 return box; 098 099 } 100 101 /** 102 * Gets a ComboBox with the available priorities 103 * 104 * @return JComboBox with car priorities. 105 */ 106 public JComboBox<String> getPriorityComboBox() { 107 JComboBox<String> box = new JComboBox<>(); 108 box.addItem(CarLoad.PRIORITY_LOW); 109 box.addItem(CarLoad.PRIORITY_MEDIUM); 110 box.addItem(CarLoad.PRIORITY_HIGH); 111 return box; 112 } 113 114 public JComboBox<String> getHazardousComboBox() { 115 JComboBox<String> box = new JComboBox<>(); 116 box.addItem(Bundle.getMessage("ButtonNo")); 117 box.addItem(Bundle.getMessage("ButtonYes")); 118 return box; 119 } 120 121 /** 122 * Gets a ComboBox with the available load types: empty and load 123 * 124 * @return JComboBox with load types: LOAD_TYPE_EMPTY and LOAD_TYPE_LOAD 125 */ 126 public JComboBox<String> getLoadTypesComboBox() { 127 JComboBox<String> box = new JComboBox<>(); 128 box.addItem(CarLoad.LOAD_TYPE_EMPTY); 129 box.addItem(CarLoad.LOAD_TYPE_LOAD); 130 OperationsPanel.padComboBox(box); 131 return box; 132 } 133 134 /** 135 * Gets a sorted list of load names for a given car type 136 * 137 * @param type car type 138 * @return list of load names 139 */ 140 public List<String> getNames(String type) { 141 List<String> names = new ArrayList<>(); 142 if (type == null) { 143 names.add(getDefaultEmptyName()); 144 names.add(getDefaultLoadName()); 145 return names; 146 } 147 List<CarLoad> loads = listCarLoads.get(type); 148 if (loads == null) { 149 addType(type); 150 loads = listCarLoads.get(type); 151 } 152 if (loads.isEmpty()) { 153 loads.add(new CarLoad(getDefaultEmptyName())); 154 loads.add(new CarLoad(getDefaultLoadName())); 155 } 156 for (CarLoad carLoad : loads) { 157 names.add(carLoad.getName()); 158 } 159 java.util.Collections.sort(names); 160 return names; 161 } 162 163 /** 164 * Add a load name for the car type. 165 * 166 * @param type car type. 167 * @param name load name. 168 */ 169 public void addName(String type, String name) { 170 // don't add if name already exists 171 if (containsName(type, name)) { 172 return; 173 } 174 List<CarLoad> loads = listCarLoads.get(type); 175 if (loads == null) { 176 log.debug("car type ({}) does not exist", type); 177 return; 178 } 179 loads.add(new CarLoad(name)); 180 maxNameLength = 0; // reset maximum name length 181 setDirtyAndFirePropertyChange(LOAD_CHANGED_PROPERTY, null, name); 182 } 183 184 public void deleteName(String type, String name) { 185 List<CarLoad> loads = listCarLoads.get(type); 186 if (loads == null) { 187 log.debug("car type ({}) does not exist", type); 188 return; 189 } 190 for (CarLoad cl : loads) { 191 if (cl.getName().equals(name)) { 192 loads.remove(cl); 193 break; 194 } 195 } 196 maxNameLength = 0; // reset maximum name length 197 setDirtyAndFirePropertyChange(LOAD_CHANGED_PROPERTY, name, null); 198 } 199 200 /** 201 * Determines if a car type can have a specific load name. 202 * 203 * @param type car type. 204 * @param name load name. 205 * @return true if car can have this load name. 206 */ 207 public boolean containsName(String type, String name) { 208 List<String> names = getNames(type); 209 return names.contains(name); 210 } 211 212 public void updateComboBox(String type, JComboBox<String> box) { 213 box.removeAllItems(); 214 List<String> names = getNames(type); 215 for (String name : names) { 216 box.addItem(name); 217 } 218 OperationsPanel.padComboBox(box, getMaxNameLength() + 1); 219 } 220 221 /** 222 * Update a JComboBox with all load names for every type of car. 223 * 224 * @param box the combo box to update 225 */ 226 @Override 227 public void updateComboBox(JComboBox<String> box) { 228 box.removeAllItems(); 229 List<String> names = new ArrayList<>(); 230 for (String type : InstanceManager.getDefault(CarTypes.class).getNames()) { 231 for (String load : getNames(type)) { 232 if (!names.contains(load)) { 233 names.add(load); 234 } 235 } 236 } 237 java.util.Collections.sort(names); 238 for (String load : names) { 239 box.addItem(load); 240 } 241 } 242 243 public void updateRweComboBox(String type, JComboBox<String> box) { 244 box.removeAllItems(); 245 List<String> loads = getNames(type); 246 for (String name : loads) { 247 if (getLoadType(type, name).equals(CarLoad.LOAD_TYPE_EMPTY)) { 248 box.addItem(name); 249 } 250 } 251 } 252 253 public void updateRwlComboBox(String type, JComboBox<String> box) { 254 box.removeAllItems(); 255 List<String> loads = getNames(type); 256 for (String name : loads) { 257 if (getLoadType(type, name).equals(CarLoad.LOAD_TYPE_LOAD)) { 258 box.addItem(name); 259 } 260 } 261 } 262 263 public void replaceName(String type, String oldName, String newName) { 264 addName(type, newName); 265 deleteName(type, oldName); 266 setDirtyAndFirePropertyChange(LOAD_NAME_CHANGED_PROPERTY, oldName, newName); 267 } 268 269 public String getDefaultLoadName() { 270 return _loadName; 271 } 272 273 public void setDefaultLoadName(String name) { 274 String old = _loadName; 275 _loadName = name; 276 setDirtyAndFirePropertyChange(LOAD_NAME_CHANGED_PROPERTY, old, name); 277 } 278 279 public String getDefaultEmptyName() { 280 return _emptyName; 281 } 282 283 public void setDefaultEmptyName(String name) { 284 String old = _emptyName; 285 _emptyName = name; 286 setDirtyAndFirePropertyChange(LOAD_NAME_CHANGED_PROPERTY, old, name); 287 } 288 289 /** 290 * Sets the load type, empty or load. 291 * 292 * @param type car type. 293 * @param name load name. 294 * @param loadType load type: LOAD_TYPE_EMPTY or LOAD_TYPE_LOAD. 295 */ 296 public void setLoadType(String type, String name, String loadType) { 297 List<CarLoad> loads = listCarLoads.get(type); 298 if (loads != null) { 299 for (CarLoad cl : loads) { 300 if (cl.getName().equals(name)) { 301 String oldType = cl.getLoadType(); 302 cl.setLoadType(loadType); 303 if (!oldType.equals(loadType)) { 304 setDirtyAndFirePropertyChange(LOAD_TYPE_CHANGED_PROPERTY, oldType, loadType); 305 } 306 } 307 } 308 } 309 } 310 311 /** 312 * Get the load type, empty or load. 313 * 314 * @param type car type. 315 * @param name load name. 316 * @return load type, LOAD_TYPE_EMPTY or LOAD_TYPE_LOAD. 317 */ 318 public String getLoadType(String type, String name) { 319 if (!containsName(type, name)) { 320 if (name != null && name.equals(getDefaultEmptyName())) { 321 return CarLoad.LOAD_TYPE_EMPTY; 322 } 323 return CarLoad.LOAD_TYPE_LOAD; 324 } 325 List<CarLoad> loads = listCarLoads.get(type); 326 for (CarLoad cl : loads) { 327 if (cl.getName().equals(name)) { 328 return cl.getLoadType(); 329 } 330 } 331 return Bundle.getMessage("ErrorTitle"); // NOI18N 332 } 333 334 /** 335 * Sets a loads priority. 336 * 337 * @param type car type. 338 * @param name load name. 339 * @param priority load priority, PRIORITY_LOW, PRIORITY_MEDIUM or 340 * PRIORITY_HIGH. 341 */ 342 public void setPriority(String type, String name, String priority) { 343 List<CarLoad> loads = listCarLoads.get(type); 344 if (loads != null) { 345 for (CarLoad cl : loads) { 346 if (cl.getName().equals(name)) { 347 String oldPriority = cl.getPriority(); 348 cl.setPriority(priority); 349 if (!oldPriority.equals(priority)) { 350 setDirtyAndFirePropertyChange(LOAD_PRIORITY_CHANGED_PROPERTY, oldPriority, priority); 351 } 352 } 353 } 354 } 355 } 356 357 /** 358 * Get's a load's priority. 359 * 360 * @param type car type. 361 * @param name load name. 362 * @return load priority, PRIORITY_LOW, PRIORITY_MEDIUM or PRIORITY_HIGH. 363 */ 364 public String getPriority(String type, String name) { 365 if (!containsName(type, name)) { 366 return CarLoad.PRIORITY_LOW; 367 } 368 List<CarLoad> loads = listCarLoads.get(type); 369 if (loads != null) { 370 for (CarLoad cl : loads) { 371 if (cl.getName().equals(name)) { 372 return cl.getPriority(); 373 } 374 } 375 } 376 return Bundle.getMessage("ErrorTitle"); // NOI18N 377 } 378 379 public void setHazardous(String type, String name, boolean isHazardous) { 380 List<CarLoad> loads = listCarLoads.get(type); 381 if (loads != null) { 382 for (CarLoad cl : loads) { 383 if (cl.getName().equals(name)) { 384 boolean oldIsHazardous = cl.isHazardous(); 385 cl.setHazardous(isHazardous); 386 if (oldIsHazardous != isHazardous) { 387 setDirtyAndFirePropertyChange(LOAD_HAZARDOUS_CHANGED_PROPERTY, oldIsHazardous, isHazardous); 388 } 389 } 390 } 391 } 392 } 393 394 public boolean isHazardous(String type, String name) { 395 if (!containsName(type, name)) { 396 return false; 397 } 398 List<CarLoad> loads = listCarLoads.get(type); 399 for (CarLoad cl : loads) { 400 if (cl.getName().equals(name)) { 401 return cl.isHazardous(); 402 } 403 } 404 return false; 405 } 406 407 /** 408 * Sets the comment for a car type's load 409 * 410 * @param type the car type 411 * @param name the load name 412 * @param comment the comment 413 */ 414 public void setPickupComment(String type, String name, String comment) { 415 if (!containsName(type, name)) { 416 return; 417 } 418 List<CarLoad> loads = listCarLoads.get(type); 419 if (loads != null) { 420 for (CarLoad cl : loads) { 421 if (cl.getName().equals(name)) { 422 String oldComment = cl.getPickupComment(); 423 cl.setPickupComment(comment); 424 if (!oldComment.equals(comment)) { 425 maxCommentLength = 0; 426 setDirtyAndFirePropertyChange(LOAD_COMMENT_CHANGED_PROPERTY, oldComment, comment); 427 } 428 } 429 } 430 } 431 } 432 433 public String getPickupComment(String type, String name) { 434 if (!containsName(type, name)) { 435 return NONE; 436 } 437 List<CarLoad> loads = listCarLoads.get(type); 438 for (CarLoad cl : loads) { 439 if (cl.getName().equals(name)) { 440 return cl.getPickupComment(); 441 } 442 } 443 return NONE; 444 } 445 446 public void setDropComment(String type, String name, String comment) { 447 if (!containsName(type, name)) { 448 return; 449 } 450 List<CarLoad> loads = listCarLoads.get(type); 451 if (loads != null) { 452 for (CarLoad cl : loads) { 453 if (cl.getName().equals(name)) { 454 String oldComment = cl.getDropComment(); 455 cl.setDropComment(comment); 456 if (!oldComment.equals(comment)) { 457 maxCommentLength = 0; 458 setDirtyAndFirePropertyChange(LOAD_COMMENT_CHANGED_PROPERTY, oldComment, comment); 459 } 460 } 461 } 462 } 463 } 464 465 public String getDropComment(String type, String name) { 466 if (!containsName(type, name)) { 467 return NONE; 468 } 469 List<CarLoad> loads = listCarLoads.get(type); 470 for (CarLoad cl : loads) { 471 if (cl.getName().equals(name)) { 472 return cl.getDropComment(); 473 } 474 } 475 return NONE; 476 } 477 478 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "SLF4J_FORMAT_SHOULD_BE_CONST", 479 justification = "I18N of Info Message") 480 @Override 481 public int getMaxNameLength() { 482 if (maxNameLength == 0) { 483 maxName = ""; 484 maxNameLength = MIN_NAME_LENGTH; 485 String carTypeName = ""; 486 Enumeration<String> en = listCarLoads.keys(); 487 while (en.hasMoreElements()) { 488 String cartype = en.nextElement(); 489 List<CarLoad> loads = listCarLoads.get(cartype); 490 for (CarLoad load : loads) { 491 if (load.getName().split(TrainCommon.HYPHEN)[0].length() > maxNameLength) { 492 maxName = load.getName().split(TrainCommon.HYPHEN)[0]; 493 maxNameLength = load.getName().split(TrainCommon.HYPHEN)[0].length(); 494 carTypeName = cartype; 495 } 496 } 497 } 498 log.info(Bundle.getMessage("InfoMaxLoad", maxName, maxNameLength, carTypeName)); 499 } 500 return maxNameLength; 501 } 502 503 int maxCommentLength = 0; 504 505 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "SLF4J_FORMAT_SHOULD_BE_CONST", 506 justification = "I18N of Info Message") 507 public int getMaxLoadCommentLength() { 508 if (maxCommentLength == 0) { 509 String maxComment = ""; 510 String carTypeName = ""; 511 String carLoadName = ""; 512 Enumeration<String> en = listCarLoads.keys(); 513 while (en.hasMoreElements()) { 514 String carType = en.nextElement(); 515 List<CarLoad> loads = listCarLoads.get(carType); 516 for (CarLoad load : loads) { 517 if (load.getDropComment().length() > maxCommentLength) { 518 maxComment = load.getDropComment(); 519 maxCommentLength = load.getDropComment().length(); 520 carTypeName = carType; 521 carLoadName = load.getName(); 522 } 523 if (load.getPickupComment().length() > maxCommentLength) { 524 maxComment = load.getPickupComment(); 525 maxCommentLength = load.getPickupComment().length(); 526 carTypeName = carType; 527 carLoadName = load.getName(); 528 } 529 } 530 } 531 if (maxCommentLength < TrainManifestHeaderText.getStringHeader_Drop_Comment().length()) { 532 maxCommentLength = TrainManifestHeaderText.getStringHeader_Drop_Comment().length(); 533 } 534 if (maxCommentLength < TrainManifestHeaderText.getStringHeader_Pickup_Comment().length()) { 535 maxCommentLength = TrainManifestHeaderText.getStringHeader_Pickup_Comment().length(); 536 } 537 if (!maxComment.isBlank()) { 538 log.info(Bundle.getMessage("InfoMaxLoadMessage", maxComment, maxCommentLength, 539 carTypeName, carLoadName)); 540 } 541 } 542 return maxCommentLength; 543 } 544 545 private List<CarLoad> getSortedList(String type) { 546 List<CarLoad> loads = listCarLoads.get(type); 547 List<String> names = getNames(type); 548 List<CarLoad> out = new ArrayList<>(); 549 550 // return a list sorted by load name 551 for (String name : names) { 552 for (CarLoad carLoad : loads) { 553 if (name.equals(carLoad.getName())) { 554 out.add(carLoad); 555 break; 556 } 557 } 558 } 559 return out; 560 } 561 562 @SuppressWarnings("unchecked") 563 public Hashtable<String, List<CarLoad>> getList() { 564 return (Hashtable<String, List<CarLoad>>) listCarLoads.clone(); 565 } 566 567 @Override 568 public void dispose() { 569 listCarLoads.clear(); 570 setDefaultEmptyName(Bundle.getMessage("EmptyCar")); 571 setDefaultLoadName(Bundle.getMessage("LoadedCar")); 572 super.dispose(); 573 } 574 575 /** 576 * Create an XML element to represent this Entry. This member has to remain 577 * synchronized with the detailed DTD in operations-cars.dtd. 578 * 579 * @param root The common Element for operations-cars.dtd. 580 */ 581 public void store(Element root) { 582 Element values = new Element(Xml.LOADS); 583 // store default load and empty 584 Element defaults = new Element(Xml.DEFAULTS); 585 defaults.setAttribute(Xml.EMPTY, getDefaultEmptyName()); 586 defaults.setAttribute(Xml.LOAD, getDefaultLoadName()); 587 values.addContent(defaults); 588 // store loads based on car types 589 String[] carTypeNames = InstanceManager.getDefault(CarTypes.class).getNames(); 590 for (String carType : carTypeNames) { 591 if (!listCarLoads.containsKey(carType)) { 592 continue; 593 } 594 List<CarLoad> loads = getSortedList(carType); 595 Element xmlLoad = new Element(Xml.LOAD); 596 xmlLoad.setAttribute(Xml.TYPE, carType); 597 boolean mustStore = false; // only store loads that aren't the defaults 598 for (CarLoad load : loads) { 599 // don't store the defaults / low priority / not hazardous / no comment 600 if ((load.getName().equals(getDefaultEmptyName()) || load.getName().equals(getDefaultLoadName())) && 601 load.getPriority().equals(CarLoad.PRIORITY_LOW) && 602 !load.isHazardous() && 603 load.getPickupComment().equals(CarLoad.NONE) && 604 load.getDropComment().equals(CarLoad.NONE)) { 605 continue; 606 } 607 Element xmlCarLoad = new Element(Xml.CAR_LOAD); 608 xmlCarLoad.setAttribute(Xml.NAME, load.getName()); 609 if (!load.getPriority().equals(CarLoad.PRIORITY_LOW)) { 610 xmlCarLoad.setAttribute(Xml.PRIORITY, load.getPriority()); 611 mustStore = true; // must store 612 } 613 if (load.isHazardous()) { 614 xmlCarLoad.setAttribute(Xml.HAZARDOUS, load.isHazardous() ? Xml.TRUE : Xml.FALSE); 615 mustStore = true; // must store 616 } 617 if (!load.getPickupComment().equals(CarLoad.NONE)) { 618 xmlCarLoad.setAttribute(Xml.PICKUP_COMMENT, load.getPickupComment()); 619 mustStore = true; // must store 620 } 621 if (!load.getDropComment().equals(CarLoad.NONE)) { 622 xmlCarLoad.setAttribute(Xml.DROP_COMMENT, load.getDropComment()); 623 mustStore = true; // must store 624 } 625 xmlCarLoad.setAttribute(Xml.LOAD_TYPE, load.getLoadType()); 626 xmlLoad.addContent(xmlCarLoad); 627 } 628 if (loads.size() > 2 || mustStore) { 629 values.addContent(xmlLoad); 630 } 631 } 632 root.addContent(values); 633 } 634 635 public void load(Element e) { 636 if (e.getChild(Xml.LOADS) == null) { 637 return; 638 } 639 Attribute a; 640 Element defaults = e.getChild(Xml.LOADS).getChild(Xml.DEFAULTS); 641 if (defaults != null) { 642 if ((a = defaults.getAttribute(Xml.LOAD)) != null) { 643 _loadName = a.getValue(); 644 } 645 if ((a = defaults.getAttribute(Xml.EMPTY)) != null) { 646 _emptyName = a.getValue(); 647 } 648 } 649 List<Element> eLoads = e.getChild(Xml.LOADS).getChildren(Xml.LOAD); 650 log.debug("readFile sees {} car loads", eLoads.size()); 651 for (Element eLoad : eLoads) { 652 if ((a = eLoad.getAttribute(Xml.TYPE)) != null) { 653 String type = a.getValue(); 654 addType(type); 655 // old style had a list of names 656 if ((a = eLoad.getAttribute(Xml.NAMES)) != null) { 657 String names = a.getValue(); 658 String[] loadNames = names.split("%%");// NOI18N 659 Arrays.sort(loadNames); 660 log.debug("Car load type: {} loads: {}", type, names); 661 // addName puts new items at the start, so reverse load 662 for (int j = loadNames.length; j > 0;) { 663 addName(type, loadNames[--j]); 664 } 665 } 666 // new style load and comments 667 List<Element> eCarLoads = eLoad.getChildren(Xml.CAR_LOAD); 668 log.debug("{} car loads for type: {}", eCarLoads.size(), type); 669 for (Element eCarLoad : eCarLoads) { 670 if ((a = eCarLoad.getAttribute(Xml.NAME)) != null) { 671 String name = a.getValue(); 672 if (name.trim().equals(TrainCommon.HYPHEN)) { 673 log.error("Illegal load name ({}) for type ({})", name, type); 674 } else { 675 addName(type, name); 676 } 677 if ((a = eCarLoad.getAttribute(Xml.PRIORITY)) != null) { 678 setPriority(type, name, a.getValue()); 679 } 680 if ((a = eCarLoad.getAttribute(Xml.HAZARDOUS)) != null) { 681 setHazardous(type, name, a.getValue().equals(Xml.TRUE)); 682 } 683 if ((a = eCarLoad.getAttribute(Xml.PICKUP_COMMENT)) != null) { 684 setPickupComment(type, name, a.getValue()); 685 } 686 if ((a = eCarLoad.getAttribute(Xml.DROP_COMMENT)) != null) { 687 setDropComment(type, name, a.getValue()); 688 } 689 if ((a = eCarLoad.getAttribute(Xml.LOAD_TYPE)) != null) { 690 setLoadType(type, name, a.getValue()); 691 } 692 } 693 } 694 } 695 } 696 } 697 698 protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) { 699 // Set dirty 700 InstanceManager.getDefault(CarManagerXml.class).setDirty(true); 701 super.firePropertyChange(p, old, n); 702 } 703 704 private static final Logger log = LoggerFactory.getLogger(CarLoads.class); 705 706}