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