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