001package jmri.jmrit.operations.locations.gui; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.util.*; 006 007import javax.swing.*; 008import javax.swing.event.*; 009import javax.swing.table.TableColumn; 010 011import org.slf4j.Logger; 012import org.slf4j.LoggerFactory; 013 014import jmri.InstanceManager; 015import jmri.jmrit.operations.OperationsPanel; 016import jmri.jmrit.operations.OperationsTableModel; 017import jmri.jmrit.operations.locations.*; 018import jmri.jmrit.operations.locations.tools.TrackEditCommentsFrame; 019import jmri.jmrit.operations.setup.Control; 020import jmri.jmrit.operations.setup.Setup; 021import jmri.util.swing.XTableColumnModel; 022import jmri.util.table.ButtonEditor; 023import jmri.util.table.ButtonRenderer; 024 025/** 026 * Table Model for edit of tracks used by operations 027 * 028 * @author Daniel Boudreau Copyright (C) 2008, 2011, 2012, 2025 029 */ 030public abstract class TrackTableModel extends OperationsTableModel implements PropertyChangeListener, TableColumnModelListener { 031 032 protected Location _location; 033 protected List<Track> _tracksList = new ArrayList<>(); 034 protected String _trackType; 035 protected boolean _dirty = false; 036 037 // Defines the columns 038 protected static final int ID_COLUMN = 0; 039 protected static final int NAME_COLUMN = 1; 040 protected static final int LENGTH_COLUMN = 2; 041 protected static final int USED_LENGTH_COLUMN = 3; 042 protected static final int RESERVED_COLUMN = 4; 043 protected static final int MOVES_COLUMN = 5; 044 protected static final int CARS_COLUMN = 6; 045 protected static final int LOCOS_COLUMN = 7; 046 protected static final int PICKUPS_COLUMN = 8; 047 protected static final int SETOUT_COLUMN = 9; 048 protected static final int SCHEDULE_COLUMN = 10; 049 protected static final int ROAD_COLUMN = 11; 050 protected static final int LOAD_COLUMN = 12; 051 protected static final int DEFAULT_LOAD_COLUMN = 13; 052 protected static final int CUSTOM_LOAD_COLUMN = 14; 053 protected static final int DISABLE_LOAD_CHANGE_COLUMN = 15; 054 protected static final int QUICK_SERVICE_COLUMN = 16; 055 protected static final int SHIP_COLUMN = 17; 056 protected static final int RESTRICTION_COLUMN = 18; 057 protected static final int DESTINATION_COLUMN = 19; 058 protected static final int ROUTED_COLUMN = 20; 059 protected static final int HOLD_COLUMN = 21; 060 protected static final int POOL_COLUMN = 22; 061 protected static final int PLANPICKUP_COLUMN = 23; 062 protected static final int ALT_TRACK_COLUMN = 24; 063 protected static final int TRACK_PRIORITY_COLUMN = 25; 064 protected static final int ORDER_COLUMN = 26; 065 protected static final int TRAIN_DIRECTION_COLUMN = 27; 066 protected static final int REPORTER_COLUMN = 28; 067 protected static final int COMMENT_COLUMN = 29; 068 protected static final int EDIT_COLUMN = 30; 069 070 protected static final int HIGHESTCOLUMN = EDIT_COLUMN + 1; 071 072 public TrackTableModel() { 073 super(); 074 } 075 076 protected void initTable(JTable table, Location location, String trackType) { 077 _table = table; 078 _location = location; 079 _trackType = trackType; 080 if (_location != null) { 081 _location.addPropertyChangeListener(this); 082 } 083 Setup.getDefault().addPropertyChangeListener(this); 084 updateList(); 085 initTable(); 086 } 087 088 private void updateList() { 089 if (_location == null) { 090 return; 091 } 092 // first, remove listeners from the individual objects 093 removePropertyChangeTracks(); 094 095 _tracksList = _location.getTracksByNameList(_trackType); 096 // and add them back in 097 for (Track track : _tracksList) { 098 track.addPropertyChangeListener(this); 099 } 100 } 101 102 private void initTable() { 103 // Use XTableColumnModel so we can control which columns are visible 104 XTableColumnModel tcm = new XTableColumnModel(); 105 _table.setColumnModel(tcm); 106 _table.createDefaultColumnsFromModel(); 107 108 // set column preferred widths 109 tcm.getColumn(ID_COLUMN).setPreferredWidth(40); 110 tcm.getColumn(NAME_COLUMN).setPreferredWidth(200); 111 tcm.getColumn(LENGTH_COLUMN).setPreferredWidth( 112 Math.max(50, new JLabel(getColumnName(LENGTH_COLUMN)).getPreferredSize().width + 10)); 113 tcm.getColumn(USED_LENGTH_COLUMN).setPreferredWidth(50); 114 tcm.getColumn(RESERVED_COLUMN).setPreferredWidth( 115 Math.max(65, new JLabel(getColumnName(RESERVED_COLUMN)).getPreferredSize().width + 10)); 116 tcm.getColumn(MOVES_COLUMN).setPreferredWidth(60); 117 tcm.getColumn(LOCOS_COLUMN).setPreferredWidth(60); 118 tcm.getColumn(CARS_COLUMN).setPreferredWidth(60); 119 tcm.getColumn(PICKUPS_COLUMN).setPreferredWidth( 120 Math.max(60, new JLabel(getColumnName(PICKUPS_COLUMN)).getPreferredSize().width + 10)); 121 tcm.getColumn(SETOUT_COLUMN).setPreferredWidth( 122 Math.max(60, new JLabel(getColumnName(SETOUT_COLUMN)).getPreferredSize().width + 10)); 123 tcm.getColumn(SCHEDULE_COLUMN).setPreferredWidth( 124 Math.max(90, new JLabel(getColumnName(SCHEDULE_COLUMN)).getPreferredSize().width + 10)); 125 tcm.getColumn(RESTRICTION_COLUMN).setPreferredWidth(90); 126 tcm.getColumn(LOAD_COLUMN).setPreferredWidth(50); 127 tcm.getColumn(DEFAULT_LOAD_COLUMN).setPreferredWidth(60); 128 tcm.getColumn(CUSTOM_LOAD_COLUMN).setPreferredWidth(90); 129 tcm.getColumn(DISABLE_LOAD_CHANGE_COLUMN).setPreferredWidth(50); 130 tcm.getColumn(QUICK_SERVICE_COLUMN).setPreferredWidth(50); 131 tcm.getColumn(SHIP_COLUMN).setPreferredWidth(50); 132 tcm.getColumn(ROAD_COLUMN).setPreferredWidth(50); 133 tcm.getColumn(DESTINATION_COLUMN).setPreferredWidth(50); 134 tcm.getColumn(ROUTED_COLUMN).setPreferredWidth(50); 135 tcm.getColumn(HOLD_COLUMN).setPreferredWidth(50); 136 tcm.getColumn(POOL_COLUMN).setPreferredWidth(70); 137 tcm.getColumn(PLANPICKUP_COLUMN).setPreferredWidth(70); 138 tcm.getColumn(ALT_TRACK_COLUMN).setPreferredWidth(120); 139 tcm.getColumn(TRACK_PRIORITY_COLUMN).setPreferredWidth(50); 140 tcm.getColumn(ORDER_COLUMN) 141 .setPreferredWidth(Math.max(50, new JLabel(getColumnName(ORDER_COLUMN)).getPreferredSize().width + 10)); 142 tcm.getColumn(TRAIN_DIRECTION_COLUMN).setPreferredWidth(30); 143 tcm.getColumn(REPORTER_COLUMN).setPreferredWidth(70); 144 tcm.getColumn(COMMENT_COLUMN).setPreferredWidth(80); 145 tcm.getColumn(EDIT_COLUMN).setPreferredWidth(80); 146 147 tcm.getColumn(COMMENT_COLUMN).setCellRenderer(new ButtonRenderer()); 148 tcm.getColumn(COMMENT_COLUMN).setCellEditor(new ButtonEditor(new JButton())); 149 tcm.getColumn(EDIT_COLUMN).setCellRenderer(new ButtonRenderer()); 150 tcm.getColumn(EDIT_COLUMN).setCellEditor(new ButtonEditor(new JButton())); 151 152 OperationsPanel.loadTableDetails(_table, "Location"); 153 setColumnsVisible(); 154 addTableColumnListeners(); 155 } 156 157 // only show columns if they are needed 158 private void setColumnsVisible() { 159 XTableColumnModel tcm = (XTableColumnModel) _table.getColumnModel(); 160 tcm.setColumnVisible(tcm.getColumnByModelIndex(ID_COLUMN), 161 InstanceManager.getDefault(LocationManager.class).isShowIdEnabled()); 162 tcm.setColumnVisible(tcm.getColumnByModelIndex(SCHEDULE_COLUMN), 163 _location.hasSchedules() && _trackType.equals(Track.SPUR)); 164 tcm.setColumnVisible(tcm.getColumnByModelIndex(RESTRICTION_COLUMN), 165 _location.hasServiceRestrictions() && !_trackType.equals(Track.YARD)); 166 tcm.setColumnVisible(tcm.getColumnByModelIndex(LOAD_COLUMN), _location.hasLoadRestrictions()); 167 tcm.setColumnVisible(tcm.getColumnByModelIndex(DEFAULT_LOAD_COLUMN), _trackType.equals(Track.STAGING)); 168 tcm.setColumnVisible(tcm.getColumnByModelIndex(CUSTOM_LOAD_COLUMN), _trackType.equals(Track.STAGING)); 169 tcm.setColumnVisible(tcm.getColumnByModelIndex(DISABLE_LOAD_CHANGE_COLUMN), 170 _location.hasDisableLoadChange() && _trackType.equals(Track.SPUR)); 171 tcm.setColumnVisible(tcm.getColumnByModelIndex(QUICK_SERVICE_COLUMN), 172 _location.hasQuickService() && (_trackType.equals(Track.SPUR) || _trackType.equals(Track.INTERCHANGE))); 173 tcm.setColumnVisible(tcm.getColumnByModelIndex(SHIP_COLUMN), _location.hasShipLoadRestrictions()); 174 tcm.setColumnVisible(tcm.getColumnByModelIndex(ROAD_COLUMN), _location.hasRoadRestrictions()); 175 tcm.setColumnVisible(tcm.getColumnByModelIndex(DESTINATION_COLUMN), _location.hasDestinationRestrictions() && 176 (_trackType.equals(Track.INTERCHANGE) || _trackType.equals(Track.STAGING))); 177 tcm.setColumnVisible(tcm.getColumnByModelIndex(ROUTED_COLUMN), _trackType.equals(Track.INTERCHANGE) || 178 _trackType.equals(Track.STAGING)); 179 tcm.setColumnVisible(tcm.getColumnByModelIndex(HOLD_COLUMN), 180 _location.hasSchedules() && _location.hasAlternateTracks() && _trackType.equals(Track.SPUR)); 181 tcm.setColumnVisible(tcm.getColumnByModelIndex(PLANPICKUP_COLUMN), _location.hasPlannedPickups()); 182 tcm.setColumnVisible(tcm.getColumnByModelIndex(POOL_COLUMN), _location.hasPools()); 183 tcm.setColumnVisible(tcm.getColumnByModelIndex(ALT_TRACK_COLUMN), _location.hasAlternateTracks()); 184 tcm.setColumnVisible(tcm.getColumnByModelIndex(TRACK_PRIORITY_COLUMN), _location.hasTrackPriortyChanges()); 185 tcm.setColumnVisible(tcm.getColumnByModelIndex(ORDER_COLUMN), 186 _location.hasOrderRestrictions() && !_trackType.equals(Track.SPUR)); 187 tcm.setColumnVisible(tcm.getColumnByModelIndex(TRAIN_DIRECTION_COLUMN), 188 _location.hasTracksWithRestrictedTrainDirections()); 189 tcm.setColumnVisible(tcm.getColumnByModelIndex(REPORTER_COLUMN), 190 Setup.isRfidEnabled() && _location.hasReporters()); 191 tcm.setColumnVisible(tcm.getColumnByModelIndex(MOVES_COLUMN), Setup.isShowTrackMovesEnabled()); 192 tcm.setColumnVisible(tcm.getColumnByModelIndex(COMMENT_COLUMN), _location.hasTrackMessages()); 193 } 194 195 /* 196 * Persisting using JmriJTablePersistenceManager doesn't quite work since 197 * the same table name is used for each track type; spur, yard, interchange, 198 * and staging. Plus multiple edit locations can be open at the same time, 199 * again using the same table name. The goal is to have a single change 200 * affect every table for all edit locations. Therefore any changes to 201 * column width or position is saved when the edit location window is 202 * closed. 203 */ 204 private void addTableColumnListeners() { 205 Enumeration<TableColumn> e = _table.getColumnModel().getColumns(); 206 while (e.hasMoreElements()) { 207 TableColumn column = e.nextElement(); 208 column.addPropertyChangeListener(this); 209 } 210 _table.getColumnModel().addColumnModelListener(this); 211 } 212 213 /** 214 * Table is dirty when a column is moved or width is changed. 215 * 216 * @param dirty set true if dirty 217 */ 218 private void setDirty(boolean dirty) { 219 _dirty = dirty; 220 } 221 222 private boolean isDirty() { 223 return _dirty; 224 } 225 226 @Override 227 public int getRowCount() { 228 return _tracksList.size(); 229 } 230 231 @Override 232 public int getColumnCount() { 233 return HIGHESTCOLUMN; 234 } 235 236 @Override 237 public String getColumnName(int col) { 238 switch (col) { 239 case ID_COLUMN: 240 return Bundle.getMessage("Id"); 241 case NAME_COLUMN: 242 return Bundle.getMessage("TrackName"); 243 case LENGTH_COLUMN: 244 return Bundle.getMessage("Length"); 245 case USED_LENGTH_COLUMN: 246 return Bundle.getMessage("Used"); 247 case RESERVED_COLUMN: 248 return Bundle.getMessage("Reserved"); 249 case MOVES_COLUMN: 250 return Bundle.getMessage("Moves"); 251 case LOCOS_COLUMN: 252 return Bundle.getMessage("Engines"); 253 case CARS_COLUMN: 254 return Bundle.getMessage("Cars"); 255 case PICKUPS_COLUMN: 256 return Bundle.getMessage("Pickups"); 257 case SETOUT_COLUMN: 258 return Bundle.getMessage("Drop"); 259 case SCHEDULE_COLUMN: 260 return Bundle.getMessage("Schedule"); 261 case RESTRICTION_COLUMN: 262 return Bundle.getMessage("Restrictions"); 263 case LOAD_COLUMN: 264 return Bundle.getMessage("Load"); 265 case DEFAULT_LOAD_COLUMN: 266 return Bundle.getMessage("LoadDefaultAbv"); 267 case CUSTOM_LOAD_COLUMN: 268 return Bundle.getMessage("LoadCustomAbv"); 269 case DISABLE_LOAD_CHANGE_COLUMN: 270 return Bundle.getMessage("DisableLoadChange"); 271 case QUICK_SERVICE_COLUMN: 272 return Bundle.getMessage("QuickService"); 273 case SHIP_COLUMN: 274 return Bundle.getMessage("Ship"); 275 case ROAD_COLUMN: 276 return Bundle.getMessage("Road"); 277 case DESTINATION_COLUMN: 278 return Bundle.getMessage("Dest"); 279 case ROUTED_COLUMN: 280 return Bundle.getMessage("Routed"); 281 case HOLD_COLUMN: 282 return Bundle.getMessage("Hold"); 283 case POOL_COLUMN: 284 return Bundle.getMessage("Pool"); 285 case PLANPICKUP_COLUMN: 286 return Bundle.getMessage("PlanPickUp"); 287 case ALT_TRACK_COLUMN: 288 return Bundle.getMessage("AlternateTrack"); 289 case TRACK_PRIORITY_COLUMN: 290 return Bundle.getMessage("Priority"); 291 case ORDER_COLUMN: 292 return Bundle.getMessage("ServiceOrder"); 293 case TRAIN_DIRECTION_COLUMN: 294 return Bundle.getMessage("AbbrevationDirection"); 295 case REPORTER_COLUMN: 296 return Bundle.getMessage("Reporters"); 297 case COMMENT_COLUMN: 298 return Bundle.getMessage("Comment"); 299 case EDIT_COLUMN: 300 return Bundle.getMessage("ButtonEdit"); 301 default: 302 return "unknown"; // NOI18N 303 } 304 } 305 306 @Override 307 public Class<?> getColumnClass(int col) { 308 switch (col) { 309 case ID_COLUMN: 310 case NAME_COLUMN: 311 case SCHEDULE_COLUMN: 312 case RESTRICTION_COLUMN: 313 case LOAD_COLUMN: 314 case DEFAULT_LOAD_COLUMN: 315 case CUSTOM_LOAD_COLUMN: 316 case SHIP_COLUMN: 317 case ROAD_COLUMN: 318 case DESTINATION_COLUMN: 319 case POOL_COLUMN: 320 case PLANPICKUP_COLUMN: 321 case ALT_TRACK_COLUMN: 322 case TRACK_PRIORITY_COLUMN: 323 case ORDER_COLUMN: 324 case TRAIN_DIRECTION_COLUMN: 325 case REPORTER_COLUMN: 326 return String.class; 327 case LENGTH_COLUMN: 328 case USED_LENGTH_COLUMN: 329 case RESERVED_COLUMN: 330 case MOVES_COLUMN: 331 case LOCOS_COLUMN: 332 case CARS_COLUMN: 333 case PICKUPS_COLUMN: 334 case SETOUT_COLUMN: 335 return Integer.class; 336 case COMMENT_COLUMN: 337 case EDIT_COLUMN: 338 return JButton.class; 339 case DISABLE_LOAD_CHANGE_COLUMN: 340 case QUICK_SERVICE_COLUMN: 341 case ROUTED_COLUMN: 342 case HOLD_COLUMN: 343 return Boolean.class; 344 default: 345 return null; 346 } 347 } 348 349 @Override 350 public boolean isCellEditable(int row, int col) { 351 switch (col) { 352 case MOVES_COLUMN: 353 case DISABLE_LOAD_CHANGE_COLUMN: 354 case QUICK_SERVICE_COLUMN: 355 case ROUTED_COLUMN: 356 case COMMENT_COLUMN: 357 case EDIT_COLUMN: 358 return true; 359 case HOLD_COLUMN: 360 return isHoldCarEnabled(row); 361 default: 362 return false; 363 } 364 } 365 366 private boolean isHoldCarEnabled(int row) { 367 Track track = _tracksList.get(row); 368 return track.getAlternateTrack() != null && track.getSchedule() != null; 369 } 370 371 @Override 372 public Object getValueAt(int row, int col) { 373 if (row >= getRowCount()) { 374 return "ERROR row " + row; // NOI18N 375 } 376 Track track = _tracksList.get(row); 377 if (track == null) { 378 return "ERROR track unknown " + row; // NOI18N 379 } 380 switch (col) { 381 case ID_COLUMN: 382 return track.getId(); 383 case NAME_COLUMN: 384 return track.getName(); 385 case LENGTH_COLUMN: 386 return track.getLength(); 387 case USED_LENGTH_COLUMN: 388 return track.getUsedLength(); 389 case RESERVED_COLUMN: 390 return track.getReserved(); 391 case MOVES_COLUMN: 392 return track.getMoves(); 393 case LOCOS_COLUMN: 394 return track.getNumberEngines(); 395 case CARS_COLUMN: 396 return track.getNumberCars(); 397 case PICKUPS_COLUMN: 398 return track.getPickupRS(); 399 case SETOUT_COLUMN: 400 return track.getDropRS(); 401 case SCHEDULE_COLUMN: 402 return track.getScheduleName(); 403 case RESTRICTION_COLUMN: 404 return getRestrictions(track); 405 case LOAD_COLUMN: 406 return getModifiedString(track.getLoadNames().length, track.getLoadOption().equals(Track.ALL_LOADS), 407 track.getLoadOption().equals(Track.INCLUDE_LOADS)); 408 case DEFAULT_LOAD_COLUMN: 409 return getDefaultLoadString(track); 410 case CUSTOM_LOAD_COLUMN: 411 return getCustomLoadString(track); 412 case DISABLE_LOAD_CHANGE_COLUMN: 413 return track.isDisableLoadChangeEnabled(); 414 case QUICK_SERVICE_COLUMN: 415 return track.isQuickServiceEnabled(); 416 case SHIP_COLUMN: 417 return getModifiedString(track.getShipLoadNames().length, 418 track.getShipLoadOption().equals(Track.ALL_LOADS), 419 track.getShipLoadOption().equals(Track.INCLUDE_LOADS)); 420 case ROAD_COLUMN: 421 return getModifiedString(track.getRoadNames().length, track.getRoadOption().equals(Track.ALL_ROADS), 422 track.getRoadOption().equals(Track.INCLUDE_ROADS)); 423 case DESTINATION_COLUMN: { 424 return getDestinationString(track); 425 } 426 case ROUTED_COLUMN: 427 return track.isOnlyCarsWithFinalDestinationEnabled(); 428 case HOLD_COLUMN: 429 return track.isHoldCarsWithCustomLoadsEnabled(); 430 case POOL_COLUMN: 431 return track.getPoolName(); 432 case PLANPICKUP_COLUMN: 433 if (track.getIgnoreUsedLengthPercentage() > Track.IGNORE_0) { 434 return track.getIgnoreUsedLengthPercentage() + "%"; 435 } 436 return ""; 437 case ALT_TRACK_COLUMN: 438 if (track.getAlternateTrack() != null) { 439 return track.getAlternateTrack().getName(); 440 } 441 if (track.isAlternate()) { 442 return Bundle.getMessage("ButtonYes"); 443 } 444 return ""; 445 case TRACK_PRIORITY_COLUMN: 446 return track.getTrackPriority(); 447 case ORDER_COLUMN: 448 return track.getServiceOrder(); 449 case TRAIN_DIRECTION_COLUMN: 450 return getDirection(track); 451 case REPORTER_COLUMN: 452 return track.getReporterName(); 453 case COMMENT_COLUMN: 454 if (track.hasMessages()) { 455 return Bundle.getMessage("ButtonEdit"); 456 } 457 return Bundle.getMessage("Add"); 458 case EDIT_COLUMN: 459 return Bundle.getMessage("ButtonEdit"); 460 default: 461 return "unknown " + col; // NOI18N 462 } 463 } 464 465 private String getRestrictions(Track track) { 466 StringBuffer restrictions = new StringBuffer(); 467 if (!track.getDropOption().equals(Track.ANY)) { 468 String suffix = " "; 469 if (track.getDropOption().equals(Track.EXCLUDE_ROUTES) || 470 track.getDropOption().equals(Track.EXCLUDE_TRAINS)) { 471 suffix = "x"; 472 } 473 restrictions.append(Bundle.getMessage("AbbreviationSetOut") + suffix + track.getDropIds().length); 474 } 475 if (!track.getPickupOption().equals(Track.ANY)) { 476 String suffix = " "; 477 if (track.getPickupOption().equals(Track.EXCLUDE_ROUTES) || 478 track.getPickupOption().equals(Track.EXCLUDE_TRAINS)) { 479 suffix = "x"; 480 } 481 restrictions.append(" " + Bundle.getMessage("AbbreviationPickUp") + suffix + track.getPickupIds().length); 482 } 483 return restrictions.toString(); 484 } 485 486 private String getModifiedString(int number, boolean all, boolean accept) { 487 if (all) { 488 return ""; 489 } 490 if (accept) { 491 return "A " + Integer.toString(number); // NOI18N 492 } 493 return "E " + Integer.toString(number); // NOI18N 494 } 495 496 private String getDefaultLoadString(Track track) { 497 String defaultLoad = ""; 498 if (track.isLoadSwapEnabled()) { 499 defaultLoad = Bundle.getMessage("ABV_SwapDefaultLoads"); 500 } 501 if (track.isLoadEmptyEnabled()) { 502 defaultLoad = Bundle.getMessage("ABV_EmptyDefaultLoads"); 503 } 504 return defaultLoad; 505 } 506 507 private String getCustomLoadString(Track track) { 508 StringBuffer customLoad = new StringBuffer(); 509 if (track.isRemoveCustomLoadsEnabled()) { 510 customLoad.append(Bundle.getMessage("ABV_EmptyCustomLoads") + " "); 511 } 512 if (track.isAddCustomLoadsEnabled()) { 513 customLoad.append(Bundle.getMessage("ABV_GenerateCustomLoad") + " "); 514 } 515 if (track.isAddCustomLoadsAnySpurEnabled()) { 516 customLoad.append(Bundle.getMessage("ABV_GenerateCustomLoadAnySpur") + " "); 517 } 518 if (track.isAddCustomLoadsAnyStagingTrackEnabled()) { 519 customLoad.append(Bundle.getMessage("ABV_GereateCustomLoadStaging")); 520 } 521 if (track.isBlockCarsEnabled()) { 522 customLoad.append(Bundle.getMessage("ABV_CarBlocking")); 523 } 524 return customLoad.toString(); 525 } 526 527 private String getDestinationString(Track track) { 528 int size = track.getDestinationListSize(); 529 if (track.getDestinationOption().equals(Track.EXCLUDE_DESTINATIONS)) { 530 size = InstanceManager.getDefault(LocationManager.class).getNumberOfLocations() - size; 531 } else if (size == 1 && track.getDestinationOption().equals(Track.INCLUDE_DESTINATIONS)) { 532 // if there's only one destination return the destination name 533 Location loc = 534 InstanceManager.getDefault(LocationManager.class).getLocationById(track.getDestinationIds()[0]); 535 if (loc != null) { 536 return loc.getName(); 537 } 538 } 539 return getModifiedString(size, track.getDestinationOption().equals(Track.ALL_DESTINATIONS), 540 track.getDestinationOption().equals(Track.INCLUDE_DESTINATIONS)); 541 } 542 543 private String getDirection(Track track) { 544 int trainDirections = track.getLocation().getTrainDirections() & Setup.getTrainDirection(); 545 if (trainDirections != (track.getTrainDirections() & trainDirections)) { 546 switch (track.getTrainDirections() & trainDirections) { 547 case Track.EAST: 548 return Setup.EAST_DIR; 549 case Track.WEST: 550 return Setup.WEST_DIR; 551 case Track.SOUTH: 552 return Setup.SOUTH_DIR; 553 case Track.NORTH: 554 return Setup.NORTH_DIR; 555 case 0: 556 return Bundle.getMessage("None"); 557 default: 558 return "X"; 559 } 560 } 561 return ""; 562 } 563 564 @Override 565 public void setValueAt(Object value, int row, int col) { 566 switch (col) { 567 case DISABLE_LOAD_CHANGE_COLUMN: 568 setDisableLoadChange(row, value); 569 break; 570 case QUICK_SERVICE_COLUMN: 571 setQuickService(row, value); 572 break; 573 case ROUTED_COLUMN: 574 setRouted(row, value); 575 break; 576 case HOLD_COLUMN: 577 setHold(row, value); 578 break; 579 case COMMENT_COLUMN: 580 trackComment(row); 581 break; 582 case EDIT_COLUMN: 583 editTrack(row); 584 break; 585 case MOVES_COLUMN: 586 setMoves(row, value); 587 break; 588 default: 589 break; 590 } 591 } 592 593 TrackEditFrame tef = null; 594 595 abstract protected void editTrack(int row); 596 597 private void setDisableLoadChange(int row, Object value) { 598 Track track = _tracksList.get(row); 599 track.setDisableLoadChangeEnabled(((Boolean) value).booleanValue()); 600 } 601 602 private void setQuickService(int row, Object value) { 603 Track track = _tracksList.get(row); 604 track.setQuickServiceEnabled(((Boolean) value).booleanValue()); 605 } 606 607 private void setRouted(int row, Object value) { 608 Track track = _tracksList.get(row); 609 track.setOnlyCarsWithFinalDestinationEnabled(((Boolean) value).booleanValue()); 610 } 611 612 private void setHold(int row, Object value) { 613 Track track = _tracksList.get(row); 614 track.setHoldCarsWithCustomLoadsEnabled(((Boolean) value).booleanValue()); 615 } 616 617 private void setMoves(int row, Object value) { 618 Track track = _tracksList.get(row); 619 track.setMoves((int) value); 620 } 621 622 private void trackComment(int row) { 623 new TrackEditCommentsFrame(_tracksList.get(row)); 624 } 625 626 private void removePropertyChangeTracks() { 627 for (Track track : _tracksList) { 628 track.removePropertyChangeListener(this); 629 } 630 } 631 632 public void dispose() { 633 if (_table != null) { 634 _table.getRowSorter().setSortKeys(null); 635 if (isDirty()) { 636 OperationsPanel.cacheState(_table); 637 OperationsPanel.saveTableState(); 638 setDirty(false); 639 } 640 } 641 removePropertyChangeTracks(); 642 if (_location != null) { 643 _location.removePropertyChangeListener(this); 644 } 645 if (tef != null) { 646 tef.dispose(); 647 } 648 Setup.getDefault().removePropertyChangeListener(this); 649 _tracksList.clear(); 650 fireTableDataChanged(); 651 } 652 653 // this table listens for changes to a location and it's tracks 654 @Override 655 public void propertyChange(PropertyChangeEvent e) { 656 if (Control.SHOW_PROPERTY) { 657 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), 658 e.getNewValue()); 659 } 660 if (e.getPropertyName().equals(Location.TRACK_LISTLENGTH_CHANGED_PROPERTY) || 661 e.getPropertyName().equals(Location.TRAIN_DIRECTION_CHANGED_PROPERTY)) { 662 updateList(); 663 fireTableDataChanged(); 664 } 665 if (e.getPropertyName().equals(Setup.SHOW_TRACK_MOVES_PROPERTY_CHANGE) || 666 e.getPropertyName().equals(Location.TRAIN_DIRECTION_CHANGED_PROPERTY) || 667 e.getPropertyName().equals(Setup.ROUTING_STAGING_PROPERTY_CHANGE)) { 668 setColumnsVisible(); 669 } 670 if (e.getSource().getClass().equals(Track.class) && 671 (e.getPropertyName().equals(Track.DROP_CHANGED_PROPERTY) || 672 e.getPropertyName().equals(Track.PICKUP_CHANGED_PROPERTY) || 673 e.getPropertyName().equals(Track.SCHEDULE_ID_CHANGED_PROPERTY) || 674 e.getPropertyName().equals(Track.LOADS_CHANGED_PROPERTY) || 675 e.getPropertyName().equals(Track.ROADS_CHANGED_PROPERTY) || 676 e.getPropertyName().equals(Track.DESTINATION_OPTIONS_CHANGED_PROPERTY) || 677 e.getPropertyName().equals(Track.POOL_CHANGED_PROPERTY) || 678 e.getPropertyName().equals(Track.PLANNED_PICKUPS_CHANGED_PROPERTY) || 679 e.getPropertyName().equals(Track.ALTERNATE_TRACK_CHANGED_PROPERTY) || 680 e.getPropertyName().equals(Track.SERVICE_ORDER_CHANGED_PROPERTY) || 681 e.getPropertyName().equals(Track.LOAD_OPTIONS_CHANGED_PROPERTY) || 682 e.getPropertyName().equals(Track.TRAIN_DIRECTION_CHANGED_PROPERTY) || 683 e.getPropertyName().equals(Track.TRACK_COMMENT_CHANGED_PROPERTY) || 684 e.getPropertyName().equals(Track.TRACK_REPORTER_CHANGED_PROPERTY) || 685 e.getPropertyName().equals(Track.PRIORITY_CHANGED_PROPERTY))) { 686 setColumnsVisible(); 687 } 688 if (e.getSource() instanceof TableColumn && e.getPropertyName().equals("preferredWidth")) { 689 log.debug("Column width change"); 690 setDirty(true); 691 } 692 } 693 694 @Override 695 public void columnAdded(TableColumnModelEvent e) { 696 // do nothing 697 } 698 699 @Override 700 public void columnRemoved(TableColumnModelEvent e) { 701 // do nothing 702 } 703 704 @Override 705 public void columnMoved(TableColumnModelEvent e) { 706 if (e.getFromIndex() != e.getToIndex()) { 707 log.debug("Table Column Moved"); 708 setDirty(true); 709 } 710 } 711 712 @Override 713 public void columnMarginChanged(ChangeEvent e) { 714 // do nothing 715 } 716 717 @Override 718 public void columnSelectionChanged(ListSelectionEvent e) { 719 // do nothing 720 } 721 722 private final static Logger log = LoggerFactory.getLogger(TrackTableModel.class); 723}