001package jmri.jmrit.operations.locations.schedules; 002 003import java.awt.Color; 004import java.beans.PropertyChangeEvent; 005import java.beans.PropertyChangeListener; 006import java.text.MessageFormat; 007import java.util.ArrayList; 008import java.util.List; 009 010import javax.swing.*; 011import javax.swing.table.TableCellEditor; 012 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016import jmri.InstanceManager; 017import jmri.jmrit.operations.OperationsTableModel; 018import jmri.jmrit.operations.locations.*; 019import jmri.jmrit.operations.rollingstock.cars.*; 020import jmri.jmrit.operations.setup.Control; 021import jmri.jmrit.operations.trains.schedules.TrainSchedule; 022import jmri.jmrit.operations.trains.schedules.TrainScheduleManager; 023import jmri.util.swing.XTableColumnModel; 024import jmri.util.table.ButtonEditor; 025import jmri.util.table.ButtonRenderer; 026 027/** 028 * Table Model for edit of a schedule used by operations 029 * 030 * @author Daniel Boudreau Copyright (C) 2009, 2014 031 */ 032public class ScheduleTableModel extends OperationsTableModel implements PropertyChangeListener { 033 034 protected static final String POINTER = " -->"; 035 036 // Defines the columns 037 private static final int ID_COLUMN = 0; 038 private static final int CURRENT_COLUMN = ID_COLUMN + 1; 039 private static final int TYPE_COLUMN = CURRENT_COLUMN + 1; 040 private static final int RANDOM_COLUMN = TYPE_COLUMN + 1; 041 private static final int SETOUT_DAY_COLUMN = RANDOM_COLUMN + 1; 042 private static final int ROAD_COLUMN = SETOUT_DAY_COLUMN + 1; 043 private static final int LOAD_COLUMN = ROAD_COLUMN + 1; 044 private static final int SHIP_COLUMN = LOAD_COLUMN + 1; 045 private static final int DEST_COLUMN = SHIP_COLUMN + 1; 046 private static final int TRACK_COLUMN = DEST_COLUMN + 1; 047 private static final int PICKUP_DAY_COLUMN = TRACK_COLUMN + 1; 048 private static final int COUNT_COLUMN = PICKUP_DAY_COLUMN + 1; 049 private static final int HIT_COLUMN = COUNT_COLUMN + 1; 050 private static final int WAIT_COLUMN = HIT_COLUMN + 1; 051 private static final int UP_COLUMN = WAIT_COLUMN + 1; 052 private static final int DOWN_COLUMN = UP_COLUMN + 1; 053 private static final int DELETE_COLUMN = DOWN_COLUMN + 1; 054 055 private static final int HIGHEST_COLUMN = DELETE_COLUMN + 1; 056 057 public ScheduleTableModel() { 058 super(); 059 } 060 061 Schedule _schedule; 062 Location _location; 063 Track _track; 064 JTable _table; 065 ScheduleEditFrame _frame; 066 boolean _matchMode = false; 067 068 private void updateList() { 069 if (_schedule == null) { 070 return; 071 } 072 // first, remove listeners from the individual objects 073 removePropertyChangeScheduleItems(); 074 _list = _schedule.getItemsBySequenceList(); 075 // and add them back in 076 for (ScheduleItem si : _list) { 077 si.addPropertyChangeListener(this); 078 // TODO the following two property changes could be moved to ScheduleItem 079 // covers the cases where destination or track is deleted 080 if (si.getDestination() != null) { 081 si.getDestination().addPropertyChangeListener(this); 082 } 083 if (si.getDestinationTrack() != null) { 084 si.getDestinationTrack().addPropertyChangeListener(this); 085 } 086 } 087 } 088 089 List<ScheduleItem> _list = new ArrayList<>(); 090 091 protected void initTable(ScheduleEditFrame frame, JTable table, Schedule schedule, Location location, Track track) { 092 super.initTable(table); 093 _schedule = schedule; 094 _location = location; 095 _track = track; 096 _table = table; 097 _frame = frame; 098 099 // add property listeners 100 if (_schedule != null) { 101 _schedule.addPropertyChangeListener(this); 102 } 103 _location.addPropertyChangeListener(this); 104 _track.addPropertyChangeListener(this); 105 initTable(); 106 } 107 108 private void initTable() { 109 // Use XTableColumnModel so we can control which columns are visible 110 XTableColumnModel tcm = new XTableColumnModel(); 111 _table.setColumnModel(tcm); 112 _table.createDefaultColumnsFromModel(); 113 114 // Install the button handlers 115 ButtonRenderer buttonRenderer = new ButtonRenderer(); 116 TableCellEditor buttonEditor = new ButtonEditor(new javax.swing.JButton()); 117 tcm.getColumn(UP_COLUMN).setCellRenderer(buttonRenderer); 118 tcm.getColumn(UP_COLUMN).setCellEditor(buttonEditor); 119 tcm.getColumn(DOWN_COLUMN).setCellRenderer(buttonRenderer); 120 tcm.getColumn(DOWN_COLUMN).setCellEditor(buttonEditor); 121 tcm.getColumn(DELETE_COLUMN).setCellRenderer(buttonRenderer); 122 tcm.getColumn(DELETE_COLUMN).setCellEditor(buttonEditor); 123 _table.setDefaultRenderer(JComboBox.class, new jmri.jmrit.symbolicprog.ValueRenderer()); 124 _table.setDefaultEditor(JComboBox.class, new jmri.jmrit.symbolicprog.ValueEditor()); 125 126 // set column preferred widths 127 _table.getColumnModel().getColumn(ID_COLUMN).setPreferredWidth(35); 128 _table.getColumnModel().getColumn(CURRENT_COLUMN).setPreferredWidth(50); 129 _table.getColumnModel().getColumn(TYPE_COLUMN).setPreferredWidth(90); 130 _table.getColumnModel().getColumn(RANDOM_COLUMN).setPreferredWidth(60); 131 _table.getColumnModel().getColumn(SETOUT_DAY_COLUMN).setPreferredWidth(90); 132 _table.getColumnModel().getColumn(ROAD_COLUMN).setPreferredWidth(90); 133 _table.getColumnModel().getColumn(LOAD_COLUMN).setPreferredWidth(90); 134 _table.getColumnModel().getColumn(SHIP_COLUMN).setPreferredWidth(90); 135 _table.getColumnModel().getColumn(DEST_COLUMN).setPreferredWidth(130); 136 _table.getColumnModel().getColumn(TRACK_COLUMN).setPreferredWidth(130); 137 _table.getColumnModel().getColumn(PICKUP_DAY_COLUMN).setPreferredWidth(90); 138 _table.getColumnModel().getColumn(COUNT_COLUMN).setPreferredWidth(45); 139 _table.getColumnModel().getColumn(HIT_COLUMN).setPreferredWidth(45); 140 _table.getColumnModel().getColumn(WAIT_COLUMN).setPreferredWidth(40); 141 _table.getColumnModel().getColumn(UP_COLUMN).setPreferredWidth(60); 142 _table.getColumnModel().getColumn(DOWN_COLUMN).setPreferredWidth(70); 143 _table.getColumnModel().getColumn(DELETE_COLUMN).setPreferredWidth(70); 144 145 _frame.loadTableDetails(_table); 146 // setup columns 147 tcm.setColumnVisible(tcm.getColumnByModelIndex(HIT_COLUMN), _matchMode); 148 tcm.setColumnVisible(tcm.getColumnByModelIndex(COUNT_COLUMN), !_matchMode); 149 150 // does not use a table sorter 151 _table.setRowSorter(null); 152 153 updateList(); 154 } 155 156 @Override 157 public int getRowCount() { 158 return _list.size(); 159 } 160 161 @Override 162 public int getColumnCount() { 163 return HIGHEST_COLUMN; 164 } 165 166 @Override 167 public String getColumnName(int col) { 168 switch (col) { 169 case ID_COLUMN: 170 return Bundle.getMessage("Id"); 171 case CURRENT_COLUMN: 172 return Bundle.getMessage("Current"); 173 case TYPE_COLUMN: 174 return Bundle.getMessage("Type"); 175 case RANDOM_COLUMN: 176 return Bundle.getMessage("Random"); 177 case SETOUT_DAY_COLUMN: 178 return Bundle.getMessage("Delivery"); 179 case ROAD_COLUMN: 180 return Bundle.getMessage("Road"); 181 case LOAD_COLUMN: 182 return Bundle.getMessage("Receive"); 183 case SHIP_COLUMN: 184 return Bundle.getMessage("Ship"); 185 case DEST_COLUMN: 186 return Bundle.getMessage("Destination"); 187 case TRACK_COLUMN: 188 return Bundle.getMessage("Track"); 189 case PICKUP_DAY_COLUMN: 190 return Bundle.getMessage("Pickup"); 191 case COUNT_COLUMN: 192 return Bundle.getMessage("Count"); 193 case HIT_COLUMN: 194 return Bundle.getMessage("Hits"); 195 case WAIT_COLUMN: 196 return Bundle.getMessage("Wait"); 197 case UP_COLUMN: 198 return Bundle.getMessage("Up"); 199 case DOWN_COLUMN: 200 return Bundle.getMessage("Down"); 201 case DELETE_COLUMN: 202 return Bundle.getMessage("ButtonDelete"); 203 default: 204 return "unknown"; // NOI18N 205 } 206 } 207 208 @Override 209 public Class<?> getColumnClass(int col) { 210 switch (col) { 211 case ID_COLUMN: 212 case CURRENT_COLUMN: 213 case TYPE_COLUMN: 214 return String.class; 215 case RANDOM_COLUMN: 216 case SETOUT_DAY_COLUMN: 217 case ROAD_COLUMN: 218 case LOAD_COLUMN: 219 case SHIP_COLUMN: 220 case DEST_COLUMN: 221 case TRACK_COLUMN: 222 case PICKUP_DAY_COLUMN: 223 return JComboBox.class; 224 case COUNT_COLUMN: 225 case HIT_COLUMN: 226 case WAIT_COLUMN: 227 return Integer.class; 228 case UP_COLUMN: 229 case DOWN_COLUMN: 230 case DELETE_COLUMN: 231 return JButton.class; 232 default: 233 return null; 234 } 235 } 236 237 @Override 238 public boolean isCellEditable(int row, int col) { 239 switch (col) { 240 case CURRENT_COLUMN: 241 case RANDOM_COLUMN: 242 case SETOUT_DAY_COLUMN: 243 case ROAD_COLUMN: 244 case LOAD_COLUMN: 245 case DEST_COLUMN: 246 case TRACK_COLUMN: 247 case PICKUP_DAY_COLUMN: 248 case COUNT_COLUMN: 249 case HIT_COLUMN: 250 case WAIT_COLUMN: 251 case UP_COLUMN: 252 case DOWN_COLUMN: 253 case DELETE_COLUMN: 254 return true; 255 case SHIP_COLUMN: 256 return !_track.isDisableLoadChangeEnabled(); 257 default: 258 return false; 259 } 260 } 261 262 @Override 263 public Object getValueAt(int row, int col) { 264 if (row >= getRowCount()) { 265 return "ERROR row " + row; // NOI18N 266 } 267 ScheduleItem si = _list.get(row); 268 if (si == null) { 269 return "ERROR schedule item unknown " + row; // NOI18N 270 } 271 switch (col) { 272 case ID_COLUMN: 273 return si.getId(); 274 case CURRENT_COLUMN: 275 return getCurrentPointer(si); 276 case TYPE_COLUMN: 277 return getType(si); 278 case RANDOM_COLUMN: 279 return getRandomComboBox(si); 280 case SETOUT_DAY_COLUMN: 281 return getSetoutDayComboBox(si); 282 case ROAD_COLUMN: 283 return getRoadComboBox(si); 284 case LOAD_COLUMN: 285 return getLoadComboBox(si); 286 case SHIP_COLUMN: 287 return getShipComboBox(si); 288 case DEST_COLUMN: 289 return getDestComboBox(si); 290 case TRACK_COLUMN: 291 return getTrackComboBox(si); 292 case PICKUP_DAY_COLUMN: 293 return getPickupDayComboBox(si); 294 case COUNT_COLUMN: 295 return si.getCount(); 296 case HIT_COLUMN: 297 return si.getHits(); 298 case WAIT_COLUMN: 299 return si.getWait(); 300 case UP_COLUMN: 301 return Bundle.getMessage("Up"); 302 case DOWN_COLUMN: 303 return Bundle.getMessage("Down"); 304 case DELETE_COLUMN: 305 return Bundle.getMessage("ButtonDelete"); 306 default: 307 return "unknown " + col; // NOI18N 308 } 309 } 310 311 @Override 312 public void setValueAt(Object value, int row, int col) { 313 if (value == null) { 314 log.debug("Warning schedule table row {} still in edit", row); 315 return; 316 } 317 switch (col) { 318 case CURRENT_COLUMN: 319 setCurrent(row); 320 break; 321 case RANDOM_COLUMN: 322 setRandom(value, row); 323 break; 324 case SETOUT_DAY_COLUMN: 325 setSetoutDay(value, row); 326 break; 327 case ROAD_COLUMN: 328 setRoad(value, row); 329 break; 330 case LOAD_COLUMN: 331 setLoad(value, row); 332 break; 333 case SHIP_COLUMN: 334 setShip(value, row); 335 break; 336 case DEST_COLUMN: 337 setDestination(value, row); 338 break; 339 case TRACK_COLUMN: 340 setTrack(value, row); 341 break; 342 case PICKUP_DAY_COLUMN: 343 setPickupDay(value, row); 344 break; 345 case COUNT_COLUMN: 346 setCount(value, row); 347 break; 348 case HIT_COLUMN: 349 setHit(value, row); 350 break; 351 case WAIT_COLUMN: 352 setWait(value, row); 353 break; 354 case UP_COLUMN: 355 moveUpScheduleItem(row); 356 break; 357 case DOWN_COLUMN: 358 moveDownScheduleItem(row); 359 break; 360 case DELETE_COLUMN: 361 deleteScheduleItem(row); 362 break; 363 default: 364 break; 365 } 366 } 367 368 @Override 369 protected Color getForegroundColor(int row) { 370 ScheduleItem si = _list.get(row); 371 if (!_schedule.checkScheduleItemValid(si, _track).equals(Schedule.SCHEDULE_OKAY)) { 372 return Color.red; 373 } 374 return super.getForegroundColor(row); 375 } 376 377 private String getCurrentPointer(ScheduleItem si) { 378 if (_track.getCurrentScheduleItem() == si) { 379 if (_track.getScheduleMode() == Track.SEQUENTIAL && si.getCount() > 1) { 380 return " " + _track.getScheduleCount() + POINTER; // NOI18N 381 } else { 382 return POINTER; // NOI18N 383 } 384 } else { 385 return ""; 386 } 387 } 388 389 private String getType(ScheduleItem si) { 390 if (_track.isTypeNameAccepted(si.getTypeName())) { 391 return si.getTypeName(); 392 } else { 393 return Bundle.getMessage("NotValid", si.getTypeName()); 394 } 395 } 396 397 private JComboBox<String> getRoadComboBox(ScheduleItem si) { 398 // log.debug("getRoadComboBox for ScheduleItem "+si.getType()); 399 JComboBox<String> cb = new JComboBox<>(); 400 cb.addItem(ScheduleItem.NONE); 401 for (String roadName : InstanceManager.getDefault(CarRoads.class).getNames()) { 402 if (_track.isRoadNameAccepted(roadName) && 403 InstanceManager.getDefault(CarManager.class).getByTypeAndRoad(si.getTypeName(), roadName) != null) { 404 cb.addItem(roadName); 405 } 406 } 407 cb.setSelectedItem(si.getRoadName()); 408 if (!cb.getSelectedItem().equals(si.getRoadName())) { 409 String notValid = Bundle.getMessage("NotValid", si.getRoadName()); 410 cb.addItem(notValid); 411 cb.setSelectedItem(notValid); 412 } 413 return cb; 414 } 415 416 String[] randomValues = {ScheduleItem.NONE, "50", "30", "25", "20", "15", "10", "5", "2", "1"}; // NOI18N 417 418 protected JComboBox<String> getRandomComboBox(ScheduleItem si) { 419 JComboBox<String> cb = new JComboBox<>(); 420 for (String item : randomValues) { 421 cb.addItem(item); 422 } 423 cb.setSelectedItem(si.getRandom()); 424 return cb; 425 } 426 427 private JComboBox<TrainSchedule> getSetoutDayComboBox(ScheduleItem si) { 428 JComboBox<TrainSchedule> cb = InstanceManager.getDefault(TrainScheduleManager.class).getSelectComboBox(); 429 TrainSchedule sch = 430 InstanceManager.getDefault(TrainScheduleManager.class).getScheduleById(si.getSetoutTrainScheduleId()); 431 if (sch != null) { 432 cb.setSelectedItem(sch); 433 } else if (!si.getSetoutTrainScheduleId().equals(ScheduleItem.NONE)) { 434 // error user deleted this set out day 435 String notValid = Bundle.getMessage("NotValid", si.getSetoutTrainScheduleId()); 436 TrainSchedule errorSchedule = new TrainSchedule(si.getSetoutTrainScheduleId(), notValid); 437 cb.addItem(errorSchedule); 438 cb.setSelectedItem(errorSchedule); 439 } 440 return cb; 441 } 442 443 private JComboBox<TrainSchedule> getPickupDayComboBox(ScheduleItem si) { 444 JComboBox<TrainSchedule> cb = InstanceManager.getDefault(TrainScheduleManager.class).getSelectComboBox(); 445 TrainSchedule sch = 446 InstanceManager.getDefault(TrainScheduleManager.class).getScheduleById(si.getPickupTrainScheduleId()); 447 if (sch != null) { 448 cb.setSelectedItem(sch); 449 } else if (!si.getPickupTrainScheduleId().equals(ScheduleItem.NONE)) { 450 // error user deleted this pick up day 451 String notValid = Bundle.getMessage("NotValid", si.getPickupTrainScheduleId()); 452 TrainSchedule errorSchedule = new TrainSchedule(si.getSetoutTrainScheduleId(), notValid); 453 cb.addItem(errorSchedule); 454 cb.setSelectedItem(errorSchedule); 455 } 456 return cb; 457 } 458 459 protected JComboBox<String> getLoadComboBox(ScheduleItem si) { 460 // log.debug("getLoadComboBox for ScheduleItem "+si.getType()); 461 JComboBox<String> cb = InstanceManager.getDefault(CarLoads.class).getSelectComboBox(si.getTypeName()); 462 filterLoads(si, cb); // remove loads not accepted by this track 463 cb.setSelectedItem(si.getReceiveLoadName()); 464 if (!cb.getSelectedItem().equals(si.getReceiveLoadName())) { 465 String notValid = Bundle.getMessage("NotValid", si.getReceiveLoadName()); 466 cb.addItem(notValid); 467 cb.setSelectedItem(notValid); 468 } 469 return cb; 470 } 471 472 protected JComboBox<String> getShipComboBox(ScheduleItem si) { 473 // log.debug("getShipComboBox for ScheduleItem "+si.getType()); 474 JComboBox<String> cb = InstanceManager.getDefault(CarLoads.class).getSelectComboBox(si.getTypeName()); 475 cb.setSelectedItem(si.getShipLoadName()); 476 if (!cb.getSelectedItem().equals(si.getShipLoadName())) { 477 String notValid = MessageFormat 478 .format(Bundle.getMessage("NotValid"), new Object[]{si.getShipLoadName()}); 479 cb.addItem(notValid); 480 cb.setSelectedItem(notValid); 481 } 482 return cb; 483 } 484 485 protected JComboBox<Location> getDestComboBox(ScheduleItem si) { 486 // log.debug("getDestComboBox for ScheduleItem "+si.getType()); 487 JComboBox<Location> cb = InstanceManager.getDefault(LocationManager.class).getComboBox(); 488 filterDestinations(cb, si.getTypeName()); 489 cb.setSelectedItem(si.getDestination()); 490 if (si.getDestination() != null && cb.getSelectedIndex() == -1) { 491 // user deleted destination, this is self correcting, when user restarts program, destination 492 // assignment will be gone. 493 cb.addItem(si.getDestination()); 494 cb.setSelectedItem(si.getDestination()); 495 } 496 return cb; 497 } 498 499 protected JComboBox<Track> getTrackComboBox(ScheduleItem si) { 500 // log.debug("getTrackComboBox for ScheduleItem "+si.getType()); 501 JComboBox<Track> cb = new JComboBox<>(); 502 if (si.getDestination() != null) { 503 Location dest = si.getDestination(); 504 dest.updateComboBox(cb); 505 filterTracks(dest, cb, si.getTypeName(), si.getRoadName(), si.getShipLoadName()); 506 cb.setSelectedItem(si.getDestinationTrack()); 507 if (si.getDestinationTrack() != null && cb.getSelectedIndex() == -1) { 508 // user deleted track at destination, this is self correcting, when user restarts program, track 509 // assignment will be gone. 510 cb.addItem(si.getDestinationTrack()); 511 cb.setSelectedItem(si.getDestinationTrack()); 512 } 513 } 514 return cb; 515 } 516 517 private void setCurrent(int row) { 518 ScheduleItem si = _list.get(row); 519 _track.setScheduleItemId(si.getId()); 520 } 521 522 // set the count or hits if in match mode 523 private void setCount(Object value, int row) { 524 ScheduleItem si = _list.get(row); 525 int count; 526 try { 527 count = Integer.parseInt(value.toString()); 528 } catch (NumberFormatException e) { 529 log.error("Schedule count must be a number"); 530 return; 531 } 532 if (count < 1) { 533 log.error("Schedule count must be greater than 0"); 534 return; 535 } 536 if (count > 100) { 537 log.warn("Schedule count must be 100 or less"); 538 count = 100; 539 } 540 si.setCount(count); 541 } 542 543 // set the count or hits if in match mode 544 private void setHit(Object value, int row) { 545 ScheduleItem si = _list.get(row); 546 int count; 547 try { 548 count = Integer.parseInt(value.toString()); 549 } catch (NumberFormatException e) { 550 log.error("Schedule hits must be a number"); 551 return; 552 } 553 // we don't care what value the user sets the hit count 554 si.setHits(count); 555 } 556 557 private void setWait(Object value, int row) { 558 ScheduleItem si = _list.get(row); 559 int wait; 560 try { 561 wait = Integer.parseInt(value.toString()); 562 } catch (NumberFormatException e) { 563 log.error("Schedule wait must be a number"); 564 return; 565 } 566 if (wait < 0) { 567 log.error("Schedule wait must be a positive number"); 568 return; 569 } 570 if (wait > 100) { 571 log.warn("Schedule wait must be 100 or less"); 572 wait = 100; 573 } 574 si.setWait(wait); 575 } 576 577 private void setRandom(Object value, int row) { 578 ScheduleItem si = _list.get(row); 579 String random = (String) ((JComboBox<?>) value).getSelectedItem(); 580 si.setRandom(random); 581 582 } 583 584 private void setSetoutDay(Object value, int row) { 585 ScheduleItem si = _list.get(row); 586 Object obj = ((JComboBox<?>) value).getSelectedItem(); 587 if (obj == null) { 588 si.setSetoutTrainScheduleId(ScheduleItem.NONE); 589 } else if (obj.getClass().equals(TrainSchedule.class)) { 590 si.setSetoutTrainScheduleId(((TrainSchedule) obj).getId()); 591 } 592 } 593 594 private void setPickupDay(Object value, int row) { 595 ScheduleItem si = _list.get(row); 596 Object obj = ((JComboBox<?>) value).getSelectedItem(); 597 if (obj == null) { 598 si.setPickupTrainScheduleId(ScheduleItem.NONE); 599 } else if (obj.getClass().equals(TrainSchedule.class)) { 600 si.setPickupTrainScheduleId(((TrainSchedule) obj).getId()); 601 } 602 } 603 604 // note this method looks for String "Not Valid <>" 605 private void setRoad(Object value, int row) { 606 ScheduleItem si = _list.get(row); 607 String road = (String) ((JComboBox<?>) value).getSelectedItem(); 608 if (checkForNotValidString(road)) { 609 si.setRoadName(road); 610 } 611 } 612 613 // note this method looks for String "Not Valid <>" 614 private void setLoad(Object value, int row) { 615 ScheduleItem si = _list.get(row); 616 String load = (String) ((JComboBox<?>) value).getSelectedItem(); 617 if (checkForNotValidString(load)) { 618 si.setReceiveLoadName(load); 619 } 620 } 621 622 // note this method looks for String "Not Valid <>" 623 private void setShip(Object value, int row) { 624 ScheduleItem si = _list.get(row); 625 String load = (String) ((JComboBox<?>) value).getSelectedItem(); 626 if (checkForNotValidString(load)) { 627 si.setShipLoadName(load); 628 } 629 } 630 631 /* 632 * Returns true if string is okay, doesn't have the string "Not Valid <>". 633 */ 634 private boolean checkForNotValidString(String s) { 635 if (s.length() < 12) { 636 return true; 637 } 638 String test = s.substring(0, 11); 639 if (test.equals(Bundle.getMessage("NotValid").substring(0, 11))) { 640 return false; 641 } 642 return true; 643 } 644 645 private void setDestination(Object value, int row) { 646 ScheduleItem si = _list.get(row); 647 si.setDestinationTrack(null); 648 Location dest = (Location) ((JComboBox<?>) value).getSelectedItem(); 649 si.setDestination(dest); 650 fireTableCellUpdated(row, TRACK_COLUMN); 651 } 652 653 private void setTrack(Object value, int row) { 654 ScheduleItem si = _list.get(row); 655 Track track = (Track) ((JComboBox<?>) value).getSelectedItem(); 656 si.setDestinationTrack(track); 657 } 658 659 private void moveUpScheduleItem(int row) { 660 log.debug("move schedule item up"); 661 _schedule.moveItemUp(_list.get(row)); 662 } 663 664 private void moveDownScheduleItem(int row) { 665 log.debug("move schedule item down"); 666 _schedule.moveItemDown(_list.get(row)); 667 } 668 669 private void deleteScheduleItem(int row) { 670 log.debug("Delete schedule item"); 671 _schedule.deleteItem(_list.get(row)); 672 } 673 674 // remove destinations that don't service the car's type 675 private void filterDestinations(JComboBox<Location> cb, String carType) { 676 for (int i = 1; i < cb.getItemCount(); i++) { 677 Location dest = cb.getItemAt(i); 678 if (!dest.acceptsTypeName(carType)) { 679 cb.removeItem(dest); 680 i--; 681 } 682 } 683 } 684 685 // remove destination tracks that don't service the car's type, road, or load 686 private void filterTracks(Location loc, JComboBox<Track> cb, String carType, String carRoad, String carLoad) { 687 List<Track> tracks = loc.getTracksList(); 688 for (Track track : tracks) { 689 if (!track.isTypeNameAccepted(carType) || 690 track.isStaging() || 691 (!carRoad.equals(ScheduleItem.NONE) && !track.isRoadNameAccepted(carRoad)) || 692 (!carLoad.equals(ScheduleItem.NONE) && !track.isLoadNameAndCarTypeAccepted(carLoad, carType))) { 693 cb.removeItem(track); 694 } 695 } 696 } 697 698 // remove receive loads not serviced by track 699 private void filterLoads(ScheduleItem si, JComboBox<String> cb) { 700 for (int i = cb.getItemCount() - 1; i > 0; i--) { 701 String loadName = cb.getItemAt(i); 702 if (!loadName.equals(CarLoads.NONE) && !_track.isLoadNameAndCarTypeAccepted(loadName, si.getTypeName())) { 703 cb.removeItem(loadName); 704 } 705 } 706 } 707 708 public void setMatchMode(boolean mode) { 709 if (mode != _matchMode) { 710 _matchMode = mode; 711 XTableColumnModel tcm = (XTableColumnModel) _table.getColumnModel(); 712 tcm.setColumnVisible(tcm.getColumnByModelIndex(HIT_COLUMN), mode); 713 tcm.setColumnVisible(tcm.getColumnByModelIndex(COUNT_COLUMN), !mode); 714 } 715 } 716 717 // this table listens for changes to a schedule and its car types 718 @Override 719 public void propertyChange(PropertyChangeEvent e) { 720 if (Control.SHOW_PROPERTY) { 721 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e 722 .getNewValue()); 723 } 724 if (e.getPropertyName().equals(Schedule.LISTCHANGE_CHANGED_PROPERTY)) { 725 updateList(); 726 fireTableDataChanged(); 727 } 728 if (e.getPropertyName().equals(Track.TYPES_CHANGED_PROPERTY) || 729 e.getPropertyName().equals(Track.ROADS_CHANGED_PROPERTY) || 730 e.getPropertyName().equals(Track.LOADS_CHANGED_PROPERTY) || 731 e.getPropertyName().equals(Track.SCHEDULE_CHANGED_PROPERTY) || 732 e.getPropertyName().equals(Location.TYPES_CHANGED_PROPERTY) || 733 e.getPropertyName().equals(Location.DISPOSE_CHANGED_PROPERTY)) { 734 fireTableDataChanged(); 735 } 736 // update hit count or other schedule item? 737 if (e.getSource().getClass().equals(ScheduleItem.class)) { 738 ScheduleItem item = (ScheduleItem) e.getSource(); 739 int row = _list.indexOf(item); 740 if (Control.SHOW_PROPERTY) { 741 log.debug("Update schedule item table row: {}", row); 742 } 743 if (row >= 0) { 744 fireTableRowsUpdated(row, row); 745 } 746 } 747 } 748 749 private void removePropertyChangeScheduleItems() { 750 for (ScheduleItem si : _list) { 751 si.removePropertyChangeListener(this); 752 if (si.getDestination() != null) { 753 si.getDestination().removePropertyChangeListener(this); 754 } 755 if (si.getDestinationTrack() != null) { 756 si.getDestinationTrack().removePropertyChangeListener(this); 757 } 758 } 759 } 760 761 public void dispose() { 762 if (_schedule != null) { 763 removePropertyChangeScheduleItems(); 764 _schedule.removePropertyChangeListener(this); 765 } 766 _location.removePropertyChangeListener(this); 767 _track.removePropertyChangeListener(this); 768 769 } 770 771 private final static Logger log = LoggerFactory.getLogger(ScheduleTableModel.class); 772}