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