001package jmri.jmrit.operations.rollingstock.cars.gui; 002 003import java.awt.Color; 004import java.beans.PropertyChangeEvent; 005import java.beans.PropertyChangeListener; 006import java.util.List; 007 008import javax.swing.*; 009import javax.swing.table.TableCellEditor; 010 011import org.slf4j.Logger; 012import org.slf4j.LoggerFactory; 013 014import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 015import jmri.InstanceManager; 016import jmri.jmrit.operations.OperationsTableModel; 017import jmri.jmrit.operations.rollingstock.cars.*; 018import jmri.jmrit.operations.setup.Control; 019import jmri.jmrit.operations.setup.Setup; 020import jmri.jmrit.operations.trains.trainbuilder.TrainCommon; 021import jmri.util.swing.XTableColumnModel; 022import jmri.util.table.ButtonEditor; 023import jmri.util.table.ButtonRenderer; 024 025/** 026 * Table Model for edit of cars used by operations 027 * 028 * @author Daniel Boudreau Copyright (C) 2008, 2011, 2012, 2016 029 */ 030public class CarsTableModel extends OperationsTableModel implements PropertyChangeListener { 031 032 CarManager carManager = InstanceManager.getDefault(CarManager.class); // There is only one manager 033 034 // Defines the columns 035 private static final int SELECT_COLUMN = 0; 036 private static final int NUMBER_COLUMN = 1; 037 private static final int ROAD_COLUMN = 2; 038 private static final int TYPE_COLUMN = 3; 039 private static final int LENGTH_COLUMN = 4; 040 private static final int LOAD_COLUMN = 5; 041 private static final int RWE_LOAD_COLUMN = 6; 042 private static final int RWL_LOAD_COLUMN = 7; 043 private static final int COLOR_COLUMN = 8; 044 private static final int KERNEL_COLUMN = 9; 045 private static final int LOCATION_COLUMN = 10; 046 private static final int RFID_WHERE_LAST_SEEN_COLUMN = 11; 047 private static final int RFID_WHEN_LAST_SEEN_COLUMN = 12; 048 private static final int DESTINATION_COLUMN = 13; 049 private static final int FINAL_DESTINATION_COLUMN = 14; 050 private static final int RWE_DESTINATION_COLUMN = 15; 051 private static final int RWL_DESTINATION_COLUMN = 16; 052 private static final int ROUTE_COLUMN = 17; 053 private static final int LAST_LOCATION_COLUMN = 18; 054 private static final int DIVISION_COLUMN = 19; 055 private static final int TRAIN_COLUMN = 20; 056 private static final int LAST_TRAIN_COLUMN = 21; 057 private static final int MOVES_COLUMN = 22; 058 private static final int BUILT_COLUMN = 23; 059 private static final int OWNER_COLUMN = 24; 060 private static final int VALUE_COLUMN = 25; 061 private static final int RFID_COLUMN = 26; 062 private static final int WAIT_COLUMN = 27; 063 private static final int PICKUP_COLUMN = 28; 064 private static final int SETOUT_COLUMN = 29; 065 private static final int LAST_COLUMN = 30; 066 private static final int COMMENT_COLUMN = 31; 067 private static final int SET_COLUMN = 32; 068 private static final int EDIT_COLUMN = 33; 069 070 private static final int HIGHESTCOLUMN = EDIT_COLUMN + 1; 071 072 public final int SORTBY_NUMBER = 0; 073 public final int SORTBY_ROAD = 1; 074 public final int SORTBY_TYPE = 2; 075 public final int SORTBY_LOCATION = 3; 076 public final int SORTBY_DESTINATION = 4; 077 public final int SORTBY_TRAIN = 5; 078 public final int SORTBY_MOVES = 6; 079 public final int SORTBY_KERNEL = 7; 080 public final int SORTBY_LOAD = 8; 081 public final int SORTBY_COLOR = 9; 082 public final int SORTBY_BUILT = 10; 083 public final int SORTBY_OWNER = 11; 084 public final int SORTBY_RFID = 12; 085 public final int SORTBY_RWE = 13; // return when empty 086 public final int SORTBY_RWL = 14; // return when loaded 087 public final int SORTBY_ROUTE = 15; 088 public final int SORTBY_DIVISION = 16; 089 public final int SORTBY_FINALDESTINATION = 17; 090 public final int SORTBY_VALUE = 18; 091 public final int SORTBY_WAIT = 19; 092 public final int SORTBY_PICKUP = 20; 093 public final int SORTBY_LAST = 21; 094 public final int SORTBY_COMMENT = 22; // also used by PrintCarRosterAction 095 096 private int _sort = SORTBY_NUMBER; 097 098 List<Car> carList = null; // list of cars 099 boolean showAllCars = true; // when true show all cars 100 public String locationName = null; // only show cars with this location 101 public String trackName = null; // only show cars with this track 102 JTable _table; 103 CarsTableFrame _frame; 104 105 public CarsTableModel(boolean showAllCars, String locationName, String trackName) { 106 super(); 107 this.showAllCars = showAllCars; 108 this.locationName = locationName; 109 this.trackName = trackName; 110 carManager.addPropertyChangeListener(this); 111 updateList(); 112 } 113 114 /** 115 * Not all columns in the Cars table are shown. This was done to limit the 116 * width of the table. Only one column from the following groups is shown at 117 * any one time. 118 * <p> 119 * Load, Color, and RWE Load are grouped together. 120 * <p> 121 * Destination, Final Destination, and RWE Destination are grouped together. 122 * <p> 123 * Moves, Built, Owner, Value, RFID, Wait, Pickup, and Last are grouped 124 * together. 125 * 126 * @param sort The integer sort to use. 127 */ 128 public void setSort(int sort) { 129 _sort = sort; 130 updateList(); 131 XTableColumnModel tcm = (XTableColumnModel) _table.getColumnModel(); 132 if (sort == SORTBY_COLOR || sort == SORTBY_LOAD || sort == SORTBY_RWE || sort == SORTBY_RWL) { 133 tcm.setColumnVisible(tcm.getColumnByModelIndex(LOAD_COLUMN), sort == SORTBY_LOAD); 134 tcm.setColumnVisible(tcm.getColumnByModelIndex(COLOR_COLUMN), sort == SORTBY_COLOR); 135 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWE_LOAD_COLUMN), sort == SORTBY_RWE); 136 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWL_LOAD_COLUMN), sort == SORTBY_RWL); 137 } 138 if (sort == SORTBY_DIVISION) { 139 tcm.setColumnVisible(tcm.getColumnByModelIndex(DIVISION_COLUMN), true); 140 } 141 if (sort == SORTBY_TRAIN) { 142 tcm.setColumnVisible(tcm.getColumnByModelIndex(TRAIN_COLUMN), true); 143 tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_TRAIN_COLUMN), false); 144 } 145 if (sort == SORTBY_DESTINATION || 146 sort == SORTBY_FINALDESTINATION || 147 sort == SORTBY_RWE || 148 sort == SORTBY_RWL || 149 sort == SORTBY_ROUTE) { 150 tcm.setColumnVisible(tcm.getColumnByModelIndex(DESTINATION_COLUMN), sort == SORTBY_DESTINATION); 151 tcm.setColumnVisible(tcm.getColumnByModelIndex(FINAL_DESTINATION_COLUMN), sort == SORTBY_FINALDESTINATION); 152 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWE_DESTINATION_COLUMN), sort == SORTBY_RWE); 153 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWL_DESTINATION_COLUMN), sort == SORTBY_RWL); 154 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWE_LOAD_COLUMN), sort == SORTBY_RWE); 155 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWL_LOAD_COLUMN), sort == SORTBY_RWL); 156 tcm.setColumnVisible(tcm.getColumnByModelIndex(ROUTE_COLUMN), sort == SORTBY_ROUTE); 157 158 // show load column if color column isn't visible. 159 tcm.setColumnVisible(tcm.getColumnByModelIndex(LOAD_COLUMN), 160 sort != SORTBY_RWE && 161 sort != SORTBY_RWL && 162 !tcm.isColumnVisible(tcm.getColumnByModelIndex(COLOR_COLUMN))); 163 } else if (sort == SORTBY_MOVES || 164 sort == SORTBY_BUILT || 165 sort == SORTBY_OWNER || 166 sort == SORTBY_VALUE || 167 sort == SORTBY_RFID || 168 sort == SORTBY_WAIT || 169 sort == SORTBY_PICKUP || 170 sort == SORTBY_LAST || 171 sort == SORTBY_COMMENT) { 172 tcm.setColumnVisible(tcm.getColumnByModelIndex(MOVES_COLUMN), sort == SORTBY_MOVES); 173 tcm.setColumnVisible(tcm.getColumnByModelIndex(BUILT_COLUMN), sort == SORTBY_BUILT); 174 tcm.setColumnVisible(tcm.getColumnByModelIndex(OWNER_COLUMN), sort == SORTBY_OWNER); 175 tcm.setColumnVisible(tcm.getColumnByModelIndex(VALUE_COLUMN), sort == SORTBY_VALUE); 176 tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_COLUMN), sort == SORTBY_RFID); 177 tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_WHEN_LAST_SEEN_COLUMN), sort == SORTBY_RFID); 178 tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_WHERE_LAST_SEEN_COLUMN), sort == SORTBY_RFID); 179 tcm.setColumnVisible(tcm.getColumnByModelIndex(WAIT_COLUMN), sort == SORTBY_WAIT); 180 tcm.setColumnVisible(tcm.getColumnByModelIndex(PICKUP_COLUMN), sort == SORTBY_PICKUP); 181 tcm.setColumnVisible(tcm.getColumnByModelIndex(SETOUT_COLUMN), sort == SORTBY_PICKUP); 182 tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_LOCATION_COLUMN), sort == SORTBY_LAST); 183 tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_COLUMN), sort == SORTBY_LAST); 184 tcm.setColumnVisible(tcm.getColumnByModelIndex(TRAIN_COLUMN), sort != SORTBY_LAST); 185 tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_TRAIN_COLUMN), sort == SORTBY_LAST); 186 tcm.setColumnVisible(tcm.getColumnByModelIndex(COMMENT_COLUMN), sort == SORTBY_COMMENT); 187 } 188 fireTableDataChanged(); 189 } 190 191 public String getSortByName() { 192 return getSortByName(_sort); 193 } 194 195 public String getSortByName(int sort) { 196 switch (sort) { 197 case SORTBY_NUMBER: 198 return Bundle.getMessage("Number"); 199 case SORTBY_ROAD: 200 return Bundle.getMessage("Road"); 201 case SORTBY_TYPE: 202 return Bundle.getMessage("Type"); 203 case SORTBY_COLOR: 204 return Bundle.getMessage("Color"); 205 case SORTBY_LOAD: 206 return Bundle.getMessage("Load"); 207 case SORTBY_KERNEL: 208 return Bundle.getMessage("Kernel"); 209 case SORTBY_LOCATION: 210 return Bundle.getMessage("Location"); 211 case SORTBY_DESTINATION: 212 return Bundle.getMessage("Destination"); 213 case SORTBY_DIVISION: 214 return Bundle.getMessage("HomeDivision"); 215 case SORTBY_TRAIN: 216 return Bundle.getMessage("Train"); 217 case SORTBY_FINALDESTINATION: 218 return Bundle.getMessage("FinalDestination"); 219 case SORTBY_RWE: 220 return Bundle.getMessage("ReturnWhenEmpty"); 221 case SORTBY_RWL: 222 return Bundle.getMessage("ReturnWhenLoaded"); 223 case SORTBY_ROUTE: 224 return Bundle.getMessage("Route"); 225 case SORTBY_MOVES: 226 return Bundle.getMessage("Moves"); 227 case SORTBY_BUILT: 228 return Bundle.getMessage("Built"); 229 case SORTBY_OWNER: 230 return Bundle.getMessage("Owner"); 231 case SORTBY_VALUE: 232 return Setup.getValueLabel(); 233 case SORTBY_RFID: 234 return Setup.getRfidLabel(); 235 case SORTBY_WAIT: 236 return Bundle.getMessage("Wait"); 237 case SORTBY_PICKUP: 238 return Bundle.getMessage("Pickup"); 239 case SORTBY_LAST: 240 return Bundle.getMessage("Last"); 241 case SORTBY_COMMENT: 242 return Bundle.getMessage("Comment"); 243 default: 244 return "Error"; // NOI18N 245 } 246 } 247 248 @Override 249 protected Color getForegroundColor(int row) { 250 Car car = carList.get(row); 251 if (car.getLocation() != null && car.getTrack() == null) { 252 return Color.red; 253 } 254 return super.getForegroundColor(row); 255 } 256 257 public void toggleSelectVisible() { 258 XTableColumnModel tcm = (XTableColumnModel) _table.getColumnModel(); 259 tcm.setColumnVisible(tcm.getColumnByModelIndex(SELECT_COLUMN), 260 !tcm.isColumnVisible(tcm.getColumnByModelIndex(SELECT_COLUMN))); 261 } 262 263 public void resetCheckboxes() { 264 for (Car car : carList) { 265 car.setSelected(false); 266 } 267 } 268 269 String _roadNumber = ""; 270 int _index = 0; 271 272 /** 273 * Search for car by road number 274 * 275 * @param roadNumber The string road number to search for. 276 * @return -1 if not found, table row number if found 277 */ 278 public int findCarByRoadNumber(String roadNumber) { 279 if (carList != null) { 280 if (!roadNumber.equals(_roadNumber)) { 281 return getIndex(0, roadNumber); 282 } 283 int index = getIndex(_index, roadNumber); 284 if (index > 0) { 285 return index; 286 } 287 return getIndex(0, roadNumber); 288 } 289 return -1; 290 } 291 292 private int getIndex(int start, String roadNumber) { 293 for (int index = start; index < carList.size(); index++) { 294 Car car = carList.get(index); 295 if (car != null) { 296 String[] number = car.getNumber().split(TrainCommon.HYPHEN); 297 // check for wild card '*' 298 if (roadNumber.startsWith("*") && roadNumber.endsWith("*")) { 299 String rN = roadNumber.substring(1, roadNumber.length() - 1); 300 if (car.getNumber().contains(rN)) { 301 _roadNumber = roadNumber; 302 _index = index + 1; 303 return index; 304 } 305 } else if (roadNumber.startsWith("*")) { 306 String rN = roadNumber.substring(1); 307 if (car.getNumber().endsWith(rN) || number[0].endsWith(rN)) { 308 _roadNumber = roadNumber; 309 _index = index + 1; 310 return index; 311 } 312 } else if (roadNumber.endsWith("*")) { 313 String rN = roadNumber.substring(0, roadNumber.length() - 1); 314 if (car.getNumber().startsWith(rN)) { 315 _roadNumber = roadNumber; 316 _index = index + 1; 317 return index; 318 } 319 } else if (car.getNumber().equals(roadNumber) || number[0].equals(roadNumber)) { 320 _roadNumber = roadNumber; 321 _index = index + 1; 322 return index; 323 } 324 } 325 } 326 _roadNumber = ""; 327 return -1; 328 } 329 330 public Car getCarAtIndex(int index) { 331 return carList.get(index); 332 } 333 334 private void updateList() { 335 // first, remove listeners from the individual objects 336 removePropertyChangeCars(); 337 carList = getSelectedCarList(); 338 // and add listeners back in 339 addPropertyChangeCars(); 340 } 341 342 public List<Car> getSelectedCarList() { 343 return getCarList(_sort); 344 } 345 346 @SuppressFBWarnings(value = "DB_DUPLICATE_SWITCH_CLAUSES", justification = "default case is sort by number") // NOI18N 347 public List<Car> getCarList(int sort) { 348 List<Car> list; 349 switch (sort) { 350 case SORTBY_NUMBER: 351 list = carManager.getByNumberList(); 352 break; 353 case SORTBY_ROAD: 354 list = carManager.getByRoadNameList(); 355 break; 356 case SORTBY_TYPE: 357 list = carManager.getByTypeList(); 358 break; 359 case SORTBY_COLOR: 360 list = carManager.getByColorList(); 361 break; 362 case SORTBY_LOAD: 363 list = carManager.getByLoadList(); 364 break; 365 case SORTBY_KERNEL: 366 list = carManager.getByKernelList(); 367 break; 368 case SORTBY_LOCATION: 369 list = carManager.getByLocationList(); 370 break; 371 case SORTBY_DESTINATION: 372 list = carManager.getByDestinationList(); 373 break; 374 case SORTBY_TRAIN: 375 list = carManager.getByTrainList(); 376 break; 377 case SORTBY_FINALDESTINATION: 378 list = carManager.getByFinalDestinationList(); 379 break; 380 case SORTBY_RWE: 381 list = carManager.getByRweList(); 382 break; 383 case SORTBY_RWL: 384 list = carManager.getByRwlList(); 385 break; 386 case SORTBY_ROUTE: 387 list = carManager.getByRouteList(); 388 break; 389 case SORTBY_DIVISION: 390 list = carManager.getByDivisionList(); 391 break; 392 case SORTBY_MOVES: 393 list = carManager.getByMovesList(); 394 break; 395 case SORTBY_BUILT: 396 list = carManager.getByBuiltList(); 397 break; 398 case SORTBY_OWNER: 399 list = carManager.getByOwnerList(); 400 break; 401 case SORTBY_VALUE: 402 list = carManager.getByValueList(); 403 break; 404 case SORTBY_RFID: 405 list = carManager.getByRfidList(); 406 break; 407 case SORTBY_WAIT: 408 list = carManager.getByWaitList(); 409 break; 410 case SORTBY_PICKUP: 411 list = carManager.getByPickupList(); 412 break; 413 case SORTBY_LAST: 414 list = carManager.getByLastDateList(); 415 break; 416 case SORTBY_COMMENT: 417 list = carManager.getByCommentList(); 418 break; 419 default: 420 list = carManager.getByNumberList(); 421 } 422 filterList(list); 423 return list; 424 } 425 426 private void filterList(List<Car> list) { 427 if (showAllCars) { 428 return; 429 } 430 for (int i = 0; i < list.size(); i++) { 431 Car car = list.get(i); 432 if (car.getLocation() == null) { 433 list.remove(i--); 434 continue; 435 } 436 // filter out cars that don't have a location name that matches 437 if (locationName != null) { 438 if (!car.getLocationName().equals(locationName)) { 439 list.remove(i--); 440 continue; 441 } 442 if (trackName != null) { 443 if (!car.getTrackName().equals(trackName)) { 444 list.remove(i--); 445 } 446 } 447 } 448 } 449 } 450 451 void initTable(JTable table, CarsTableFrame frame) { 452 super.initTable(table); 453 _table = table; 454 _frame = frame; 455 initTable(); 456 } 457 458 // Cars frame table column widths, starts with Select column and ends with Edit 459 private final int[] tableColumnWidths = {60, 60, 60, 65, 35, 75, 75, 75, 75, 65, 190, 190, 140, 190, 190, 190, 190, 460 190, 190, 190, 65, 90, 50, 50, 50, 50, 100, 50, 100, 60, 100, 100, 65, 70}; 461 462 void initTable() { 463 // Use XTableColumnModel so we can control which columns are visible 464 XTableColumnModel tcm = new XTableColumnModel(); 465 _table.setColumnModel(tcm); 466 _table.createDefaultColumnsFromModel(); 467 468 // Install the button handlers 469 ButtonRenderer buttonRenderer = new ButtonRenderer(); 470 tcm.getColumn(SET_COLUMN).setCellRenderer(buttonRenderer); 471 TableCellEditor buttonEditor = new ButtonEditor(new javax.swing.JButton()); 472 tcm.getColumn(SET_COLUMN).setCellEditor(buttonEditor); 473 tcm.getColumn(EDIT_COLUMN).setCellRenderer(buttonRenderer); 474 tcm.getColumn(EDIT_COLUMN).setCellEditor(buttonEditor); 475 476 // set column preferred widths 477 for (int i = 0; i < tcm.getColumnCount(); i++) { 478 tcm.getColumn(i).setPreferredWidth(tableColumnWidths[i]); 479 } 480 _frame.loadTableDetails(_table); 481 482 // turn off columns 483 tcm.setColumnVisible(tcm.getColumnByModelIndex(COLOR_COLUMN), false); 484 tcm.setColumnVisible(tcm.getColumnByModelIndex(FINAL_DESTINATION_COLUMN), false); 485 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWE_DESTINATION_COLUMN), false); 486 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWE_LOAD_COLUMN), false); 487 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWL_DESTINATION_COLUMN), false); 488 tcm.setColumnVisible(tcm.getColumnByModelIndex(RWL_LOAD_COLUMN), false); 489 tcm.setColumnVisible(tcm.getColumnByModelIndex(ROUTE_COLUMN), false); 490 tcm.setColumnVisible(tcm.getColumnByModelIndex(BUILT_COLUMN), false); 491 tcm.setColumnVisible(tcm.getColumnByModelIndex(OWNER_COLUMN), false); 492 tcm.setColumnVisible(tcm.getColumnByModelIndex(VALUE_COLUMN), false); 493 tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_COLUMN), false); 494 tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_WHEN_LAST_SEEN_COLUMN), false); 495 tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_WHERE_LAST_SEEN_COLUMN), false); 496 tcm.setColumnVisible(tcm.getColumnByModelIndex(WAIT_COLUMN), false); 497 tcm.setColumnVisible(tcm.getColumnByModelIndex(PICKUP_COLUMN), false); 498 tcm.setColumnVisible(tcm.getColumnByModelIndex(SETOUT_COLUMN), false); 499 tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_LOCATION_COLUMN), false); 500 tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_COLUMN), false); 501 tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_TRAIN_COLUMN), false); 502 tcm.setColumnVisible(tcm.getColumnByModelIndex(COMMENT_COLUMN), false); 503 504 // turn on defaults 505 tcm.setColumnVisible(tcm.getColumnByModelIndex(LOAD_COLUMN), true); 506 tcm.setColumnVisible(tcm.getColumnByModelIndex(DESTINATION_COLUMN), true); 507 tcm.setColumnVisible(tcm.getColumnByModelIndex(MOVES_COLUMN), true); 508 tcm.setColumnVisible(tcm.getColumnByModelIndex(TRAIN_COLUMN), true); 509 510 tcm.setColumnVisible(tcm.getColumnByModelIndex(DIVISION_COLUMN), carManager.isThereDivisions()); 511 } 512 513 @Override 514 public int getRowCount() { 515 return carList.size(); 516 } 517 518 @Override 519 public int getColumnCount() { 520 return HIGHESTCOLUMN; 521 } 522 523 @Override 524 public String getColumnName(int col) { 525 switch (col) { 526 case SELECT_COLUMN: 527 return Bundle.getMessage("ButtonSelect"); 528 case NUMBER_COLUMN: 529 return Bundle.getMessage("Number"); 530 case ROAD_COLUMN: 531 return Bundle.getMessage("Road"); 532 case LOAD_COLUMN: 533 return Bundle.getMessage("Load"); 534 case COLOR_COLUMN: 535 return Bundle.getMessage("Color"); 536 case TYPE_COLUMN: 537 return Bundle.getMessage("Type"); 538 case LENGTH_COLUMN: 539 return Bundle.getMessage("Len"); 540 case KERNEL_COLUMN: 541 return Bundle.getMessage("Kernel"); 542 case LOCATION_COLUMN: 543 return Bundle.getMessage("Location"); 544 case RFID_WHERE_LAST_SEEN_COLUMN: 545 return Bundle.getMessage("WhereLastSeen"); 546 case RFID_WHEN_LAST_SEEN_COLUMN: 547 return Bundle.getMessage("WhenLastSeen"); 548 case DESTINATION_COLUMN: 549 return Bundle.getMessage("Destination"); 550 case FINAL_DESTINATION_COLUMN: 551 return Bundle.getMessage("FinalDestination"); 552 case RWE_DESTINATION_COLUMN: 553 return Bundle.getMessage("RWELocation"); 554 case RWE_LOAD_COLUMN: 555 return Bundle.getMessage("RWELoad"); 556 case RWL_DESTINATION_COLUMN: 557 return Bundle.getMessage("RWLLocation"); 558 case RWL_LOAD_COLUMN: 559 return Bundle.getMessage("RWLLoad"); 560 case ROUTE_COLUMN: 561 return Bundle.getMessage("Route"); 562 case LAST_LOCATION_COLUMN: 563 return Bundle.getMessage("LastLocation"); 564 case DIVISION_COLUMN: 565 return Bundle.getMessage("HomeDivision"); 566 case TRAIN_COLUMN: 567 return Bundle.getMessage("Train"); 568 case LAST_TRAIN_COLUMN: 569 return Bundle.getMessage("LastTrain"); 570 case MOVES_COLUMN: 571 return Bundle.getMessage("Moves"); 572 case BUILT_COLUMN: 573 return Bundle.getMessage("Built"); 574 case OWNER_COLUMN: 575 return Bundle.getMessage("Owner"); 576 case VALUE_COLUMN: 577 return Setup.getValueLabel(); 578 case RFID_COLUMN: 579 return Setup.getRfidLabel(); 580 case WAIT_COLUMN: 581 return Bundle.getMessage("Wait"); 582 case PICKUP_COLUMN: 583 return Bundle.getMessage("Pickup"); 584 case SETOUT_COLUMN: 585 return Bundle.getMessage("SetOut"); 586 case LAST_COLUMN: 587 return Bundle.getMessage("LastMoved"); 588 case COMMENT_COLUMN: 589 return Bundle.getMessage("Comment"); 590 case SET_COLUMN: 591 return Bundle.getMessage("Set"); 592 case EDIT_COLUMN: 593 return Bundle.getMessage("ButtonEdit"); // titles above all columns 594 default: 595 return "unknown"; // NOI18N 596 } 597 } 598 599 @Override 600 public Class<?> getColumnClass(int col) { 601 switch (col) { 602 case SELECT_COLUMN: 603 return Boolean.class; 604 case SET_COLUMN: 605 case EDIT_COLUMN: 606 return JButton.class; 607 case LENGTH_COLUMN: 608 case MOVES_COLUMN: 609 case WAIT_COLUMN: 610 return Integer.class; 611 default: 612 return String.class; 613 } 614 } 615 616 @Override 617 public boolean isCellEditable(int row, int col) { 618 Car car = carList.get(row); 619 if (car.isClone()) { 620 return false; 621 } 622 switch (col) { 623 case SELECT_COLUMN: 624 case SET_COLUMN: 625 case EDIT_COLUMN: 626 case MOVES_COLUMN: 627 case WAIT_COLUMN: 628 case VALUE_COLUMN: 629 case RFID_COLUMN: 630 return true; 631 default: 632 return false; 633 } 634 } 635 636 @Override 637 public Object getValueAt(int row, int col) { 638 if (row >= getRowCount()) { 639 return "ERROR row " + row; // NOI18N 640 } 641 Car car = carList.get(row); 642 if (car == null) { 643 return "ERROR car unknown " + row; // NOI18N 644 } 645 switch (col) { 646 case SELECT_COLUMN: 647 return car.isSelected(); 648 case NUMBER_COLUMN: 649 return car.getNumber(); 650 case ROAD_COLUMN: 651 return car.getRoadName(); 652 case LOAD_COLUMN: 653 return getLoadNameString(car); 654 case COLOR_COLUMN: 655 return car.getColor(); 656 case LENGTH_COLUMN: 657 return car.getLengthInteger(); 658 case TYPE_COLUMN: 659 return car.getTypeName() + car.getTypeExtensions(); 660 case KERNEL_COLUMN: 661 if (car.isLead()) { 662 return car.getKernelName() + "*"; 663 } 664 return car.getKernelName(); 665 case LOCATION_COLUMN: 666 if (car.getLocation() != null) { 667 return car.getStatus() + car.getLocationName() + " (" + car.getTrackName() + ")"; 668 } 669 return car.getStatus(); 670 case RFID_WHERE_LAST_SEEN_COLUMN: 671 return car.getWhereLastSeenName() + 672 (car.getTrackLastSeenName().equals(Car.NONE) ? "" : " (" + car.getTrackLastSeenName() + ")"); 673 case RFID_WHEN_LAST_SEEN_COLUMN: { 674 return car.getWhenLastSeenDate(); 675 } 676 case DESTINATION_COLUMN: 677 case FINAL_DESTINATION_COLUMN: { 678 String s = ""; 679 if (car.getDestination() != null) { 680 s = car.getDestinationName() + " (" + car.getDestinationTrackName() + ")"; 681 } 682 if (car.getFinalDestination() != null) { 683 s = s + "->" + car.getFinalDestinationName(); // NOI18N 684 } 685 if (car.getFinalDestinationTrack() != null) { 686 s = s + " (" + car.getFinalDestinationTrackName() + ")"; 687 } 688 if (log.isDebugEnabled() && 689 car.getFinalDestinationTrack() != null && 690 car.getFinalDestinationTrack().getSchedule() != null) { 691 s = s + " " + car.getScheduleItemId(); 692 } 693 return s; 694 } 695 case RWE_DESTINATION_COLUMN: { 696 String s = car.getReturnWhenEmptyDestinationName(); 697 if (car.getReturnWhenEmptyDestTrack() != null) { 698 s = s + " (" + car.getReturnWhenEmptyDestTrackName() + ")"; 699 } 700 return s; 701 } 702 case RWE_LOAD_COLUMN: 703 return car.getReturnWhenEmptyLoadName(); 704 case RWL_DESTINATION_COLUMN: { 705 String s = car.getReturnWhenLoadedDestinationName(); 706 if (car.getReturnWhenLoadedDestTrack() != null) { 707 s = s + " (" + car.getReturnWhenLoadedDestTrackName() + ")"; 708 } 709 return s; 710 } 711 case RWL_LOAD_COLUMN: 712 return car.getReturnWhenLoadedLoadName(); 713 case ROUTE_COLUMN: 714 return car.getRoutePath(); 715 case DIVISION_COLUMN: 716 return car.getDivisionName(); 717 case LAST_LOCATION_COLUMN: { 718 String s = ""; 719 if (!car.getLastLocationName().equals(Car.NONE)) { 720 s = car.getLastLocationName() + " (" + car.getLastTrackName() + ")"; 721 } 722 return s; 723 } 724 case TRAIN_COLUMN: { 725 // if train was manually set by user add an asterisk 726 if (car.getTrain() != null && car.getRouteLocation() == null) { 727 return car.getTrainName() + "*"; 728 } 729 return car.getTrainName(); 730 } 731 case LAST_TRAIN_COLUMN: 732 return car.getLastTrainName(); 733 case MOVES_COLUMN: 734 return car.getMoves(); 735 case BUILT_COLUMN: 736 return car.getBuilt(); 737 case OWNER_COLUMN: 738 return car.getOwnerName(); 739 case VALUE_COLUMN: 740 return car.getValue(); 741 case RFID_COLUMN: 742 return car.getRfid(); 743 case WAIT_COLUMN: 744 return car.getWait(); 745 case PICKUP_COLUMN: 746 return car.getPickupScheduleName(); 747 case SETOUT_COLUMN: 748 return car.getSetoutTime(); 749 case LAST_COLUMN: 750 return car.getSortDate(); 751 case COMMENT_COLUMN: 752 return car.getComment(); 753 case SET_COLUMN: 754 return Bundle.getMessage("Set"); 755 case EDIT_COLUMN: 756 return Bundle.getMessage("ButtonEdit"); 757 default: 758 return "unknown " + col; // NOI18N 759 } 760 } 761 762 private String getLoadNameString(Car car) { 763 StringBuffer sb = new StringBuffer(car.getLoadName()); 764 if (car.getLoadPriority().equals(CarLoad.PRIORITY_HIGH)) { 765 sb.append(" " + Bundle.getMessage("(P)")); 766 } else if (car.getLoadPriority().equals(CarLoad.PRIORITY_MEDIUM)) { 767 sb.append(" " + Bundle.getMessage("(M)")); 768 } 769 if (car.isCarLoadHazardous()) { 770 sb.append(" " + Bundle.getMessage("(H)")); 771 } 772 return sb.toString(); 773 } 774 775 CarEditFrame cef = null; 776 CarSetFrame csf = null; 777 778 @Override 779 public void setValueAt(Object value, int row, int col) { 780 Car car = carList.get(row); 781 switch (col) { 782 case SELECT_COLUMN: 783 car.setSelected(((Boolean) value).booleanValue()); 784 break; 785 case SET_COLUMN: 786 log.debug("Set car"); 787 if (csf != null) { 788 csf.dispose(); 789 } 790 // use invokeLater so new window appears on top 791 SwingUtilities.invokeLater(() -> { 792 csf = new CarSetFrame(); 793 csf.initComponents(); 794 csf.load(car); 795 }); 796 break; 797 case EDIT_COLUMN: 798 log.debug("Edit car"); 799 if (cef != null) { 800 cef.dispose(); 801 } 802 // use invokeLater so new window appears on top 803 SwingUtilities.invokeLater(() -> { 804 cef = new CarEditFrame(); 805 cef.initComponents(); 806 cef.load(car); 807 }); 808 break; 809 case MOVES_COLUMN: 810 try { 811 car.setMoves(Integer.parseInt(value.toString())); 812 } catch (NumberFormatException e) { 813 log.error("move count must be a number"); 814 } 815 break; 816 case VALUE_COLUMN: 817 car.setValue(value.toString()); 818 break; 819 case RFID_COLUMN: 820 car.setRfid(value.toString()); 821 break; 822 case WAIT_COLUMN: 823 try { 824 car.setWait(Integer.parseInt(value.toString())); 825 } catch (NumberFormatException e) { 826 log.error("wait count must be a number"); 827 } 828 break; 829 default: 830 break; 831 } 832 } 833 834 public void dispose() { 835 carManager.removePropertyChangeListener(this); 836 removePropertyChangeCars(); 837 if (csf != null) { 838 csf.dispose(); 839 } 840 if (cef != null) { 841 cef.dispose(); 842 } 843 } 844 845 private void addPropertyChangeCars() { 846 for (Car car : carManager.getList()) { 847 car.addPropertyChangeListener(this); 848 } 849 } 850 851 private void removePropertyChangeCars() { 852 for (Car car : carManager.getList()) { 853 car.removePropertyChangeListener(this); 854 } 855 } 856 857 @Override 858 public void propertyChange(PropertyChangeEvent e) { 859 if (Control.SHOW_PROPERTY) { 860 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), 861 e.getNewValue()); 862 } 863 if (e.getPropertyName().equals(CarManager.LISTLENGTH_CHANGED_PROPERTY)) { 864 updateList(); 865 fireTableDataChanged(); 866 } // must be a car change 867 else if (e.getSource().getClass().equals(Car.class)) { 868 Car car = (Car) e.getSource(); 869 int row = carList.indexOf(car); 870 if (Control.SHOW_PROPERTY) { 871 log.debug("Update car table row: {}", row); 872 } 873 if (row >= 0) { 874 fireTableRowsUpdated(row, row); 875 // next is needed when only showing cars at a location or track 876 } else if (e.getPropertyName().equals(Car.TRACK_CHANGED_PROPERTY)) { 877 updateList(); 878 fireTableDataChanged(); 879 } 880 } 881 } 882 883 private final static Logger log = LoggerFactory.getLogger(CarsTableModel.class); 884}