001package jmri.jmrit.operations.routes.gui; 002 003import java.awt.BorderLayout; 004import java.awt.FlowLayout; 005import java.awt.event.ActionEvent; 006import java.awt.event.ActionListener; 007import java.beans.PropertyChangeEvent; 008import java.beans.PropertyChangeListener; 009import java.util.ArrayList; 010import java.util.List; 011 012import javax.swing.*; 013import javax.swing.colorchooser.AbstractColorChooserPanel; 014import javax.swing.table.TableCellEditor; 015 016import jmri.jmrit.operations.routes.Route; 017import jmri.jmrit.operations.routes.RouteLocation; 018import jmri.jmrit.operations.setup.Control; 019import jmri.jmrit.operations.setup.Setup; 020import jmri.util.swing.*; 021import jmri.util.table.ButtonEditor; 022import jmri.util.table.ButtonRenderer; 023 024/** 025 * Table Model for edit of route locations used by operations 026 * 027 * @author Daniel Boudreau Copyright (C) 2008, 2013, 2025 028 */ 029public class RouteEditTableModel extends javax.swing.table.AbstractTableModel implements PropertyChangeListener { 030 031 // Defines the columns 032 private static final int ID_COLUMN = 0; 033 private static final int NAME_COLUMN = ID_COLUMN + 1; 034 private static final int TRAIN_DIRECTION_COLUMN = NAME_COLUMN + 1; 035 private static final int MAXMOVES_COLUMN = TRAIN_DIRECTION_COLUMN + 1; 036 private static final int RANDOM_CONTROL_COLUMN = MAXMOVES_COLUMN + 1; 037 private static final int PICKUP_COLUMN = RANDOM_CONTROL_COLUMN + 1; 038 private static final int DROP_COLUMN = PICKUP_COLUMN + 1; 039 private static final int LOCAL_COLUMN = DROP_COLUMN + 1; 040 private static final int TRAVEL_COLUMN = LOCAL_COLUMN + 1; 041 private static final int TIME_COLUMN = TRAVEL_COLUMN + 1; 042 private static final int MAXLENGTH_COLUMN = TIME_COLUMN + 1; 043 private static final int GRADE = MAXLENGTH_COLUMN + 1; 044 private static final int TRAINICONX = GRADE + 1; 045 private static final int TRAINICONY = TRAINICONX + 1; 046 private static final int COMMENT_COLUMN = TRAINICONY + 1; 047 private static final int UP_COLUMN = COMMENT_COLUMN + 1; 048 private static final int DOWN_COLUMN = UP_COLUMN + 1; 049 private static final int DELETE_COLUMN = DOWN_COLUMN + 1; 050 051 private static final int HIGHEST_COLUMN = DELETE_COLUMN + 1; 052 053 private JTable _table; 054 private Route _route; 055 private RouteEditFrame _frame; 056 List<RouteLocation> _routeList = new ArrayList<>(); 057 058 public RouteEditTableModel() { 059 super(); 060 } 061 062 public void setWait(boolean showWait) { 063 XTableColumnModel tcm = (XTableColumnModel) _table.getColumnModel(); 064 tcm.setColumnVisible(tcm.getColumnByModelIndex(TRAVEL_COLUMN), showWait); 065 tcm.setColumnVisible(tcm.getColumnByModelIndex(TIME_COLUMN), !showWait); 066 } 067 068 private void updateList() { 069 if (_route == null) { 070 return; 071 } 072 // first, remove listeners from the individual objects 073 removePropertyChangeRouteLocations(); 074 _routeList = _route.getLocationsBySequenceList(); 075 // and add them back in 076 for (RouteLocation rl : _routeList) { 077 rl.addPropertyChangeListener(this); 078 } 079 } 080 081 protected void initTable(RouteEditFrame frame, JTable table, Route route) { 082 _frame = frame; 083 _table = table; 084 _route = route; 085 if (_route != null) { 086 _route.addPropertyChangeListener(this); 087 } 088 Setup.getDefault().addPropertyChangeListener(this); 089 initTable(table); 090 } 091 092 private void initTable(JTable table) { 093 // Use XTableColumnModel so we can control which columns are visible 094 XTableColumnModel tcm = new XTableColumnModel(); 095 _table.setColumnModel(tcm); 096 _table.createDefaultColumnsFromModel(); 097 // Install the button handlers 098 ButtonRenderer buttonRenderer = new ButtonRenderer(); 099 TableCellEditor buttonEditor = new ButtonEditor(new javax.swing.JButton()); 100 tcm.getColumn(COMMENT_COLUMN).setCellRenderer(buttonRenderer); 101 tcm.getColumn(COMMENT_COLUMN).setCellEditor(buttonEditor); 102 tcm.getColumn(UP_COLUMN).setCellRenderer(buttonRenderer); 103 tcm.getColumn(UP_COLUMN).setCellEditor(buttonEditor); 104 tcm.getColumn(DOWN_COLUMN).setCellRenderer(buttonRenderer); 105 tcm.getColumn(DOWN_COLUMN).setCellEditor(buttonEditor); 106 tcm.getColumn(DELETE_COLUMN).setCellRenderer(buttonRenderer); 107 tcm.getColumn(DELETE_COLUMN).setCellEditor(buttonEditor); 108 table.setDefaultRenderer(JComboBox.class, new jmri.jmrit.symbolicprog.ValueRenderer()); 109 table.setDefaultEditor(JComboBox.class, new jmri.jmrit.symbolicprog.ValueEditor()); 110 111 // set column preferred widths 112 table.getColumnModel().getColumn(ID_COLUMN).setPreferredWidth(40); 113 table.getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(150); 114 table.getColumnModel().getColumn(TRAIN_DIRECTION_COLUMN).setPreferredWidth(95); 115 table.getColumnModel().getColumn(MAXMOVES_COLUMN).setPreferredWidth(50); 116 table.getColumnModel().getColumn(RANDOM_CONTROL_COLUMN).setPreferredWidth(65); 117 table.getColumnModel().getColumn(PICKUP_COLUMN).setPreferredWidth(65); 118 table.getColumnModel().getColumn(DROP_COLUMN).setPreferredWidth(65); 119 table.getColumnModel().getColumn(LOCAL_COLUMN).setPreferredWidth(75); 120 table.getColumnModel().getColumn(TRAVEL_COLUMN).setPreferredWidth(65); 121 table.getColumnModel().getColumn(TIME_COLUMN).setPreferredWidth(65); 122 table.getColumnModel().getColumn(MAXLENGTH_COLUMN).setPreferredWidth(75); 123 table.getColumnModel().getColumn(GRADE).setPreferredWidth(50); 124 table.getColumnModel().getColumn(TRAINICONX).setPreferredWidth(35); 125 table.getColumnModel().getColumn(TRAINICONY).setPreferredWidth(35); 126 table.getColumnModel().getColumn(COMMENT_COLUMN).setPreferredWidth(70); 127 table.getColumnModel().getColumn(UP_COLUMN).setPreferredWidth(60); 128 table.getColumnModel().getColumn(DOWN_COLUMN).setPreferredWidth(70); 129 table.getColumnModel().getColumn(DELETE_COLUMN).setPreferredWidth(80); 130 131 _frame.loadTableDetails(table); 132 // does not use a table sorter 133 table.setRowSorter(null); 134 135 // turn off columns 136 tcm.setColumnVisible(tcm.getColumnByModelIndex(TIME_COLUMN), false); 137 138 updateList(); 139 } 140 141 @Override 142 public int getRowCount() { 143 return _routeList.size(); 144 } 145 146 @Override 147 public int getColumnCount() { 148 return HIGHEST_COLUMN; 149 } 150 151 @Override 152 public String getColumnName(int col) { 153 switch (col) { 154 case ID_COLUMN: 155 return Bundle.getMessage("Id"); 156 case NAME_COLUMN: 157 return Bundle.getMessage("Location"); 158 case TRAIN_DIRECTION_COLUMN: 159 return Bundle.getMessage("TrainDirection"); 160 case MAXMOVES_COLUMN: 161 return Bundle.getMessage("MaxMoves"); 162 case RANDOM_CONTROL_COLUMN: 163 return Bundle.getMessage("Random"); 164 case PICKUP_COLUMN: 165 return Bundle.getMessage("Pickups"); 166 case DROP_COLUMN: 167 return Bundle.getMessage("Drops"); 168 case LOCAL_COLUMN: 169 return Bundle.getMessage("LocalMoves"); 170 case TRAVEL_COLUMN: 171 return Bundle.getMessage("Travel"); 172 case TIME_COLUMN: 173 return Bundle.getMessage("Time"); 174 case MAXLENGTH_COLUMN: 175 return Bundle.getMessage("MaxLength"); 176 case GRADE: 177 return Bundle.getMessage("Grade"); 178 case TRAINICONX: 179 return Bundle.getMessage("X"); 180 case TRAINICONY: 181 return Bundle.getMessage("Y"); 182 case COMMENT_COLUMN: 183 return Bundle.getMessage("Comment"); 184 case UP_COLUMN: 185 return Bundle.getMessage("Up"); 186 case DOWN_COLUMN: 187 return Bundle.getMessage("Down"); 188 case DELETE_COLUMN: 189 return Bundle.getMessage("ButtonDelete"); // titles above all columns 190 default: 191 return "unknown"; // NOI18N 192 } 193 } 194 195 @Override 196 public Class<?> getColumnClass(int col) { 197 switch (col) { 198 case ID_COLUMN: 199 case NAME_COLUMN: 200 return String.class; 201 case TRAVEL_COLUMN: 202 case MAXLENGTH_COLUMN: 203 case MAXMOVES_COLUMN: 204 case TRAINICONX: 205 case TRAINICONY: 206 return Integer.class; 207 case GRADE: 208 return Double.class; 209 case TRAIN_DIRECTION_COLUMN: 210 case RANDOM_CONTROL_COLUMN: 211 case PICKUP_COLUMN: 212 case DROP_COLUMN: 213 case LOCAL_COLUMN: 214 case TIME_COLUMN: 215 return JComboBox.class; 216 case COMMENT_COLUMN: 217 case UP_COLUMN: 218 case DOWN_COLUMN: 219 case DELETE_COLUMN: 220 return JButton.class; 221 default: 222 return null; 223 } 224 } 225 226 @Override 227 public boolean isCellEditable(int row, int col) { 228 switch (col) { 229 case DELETE_COLUMN: 230 case TRAIN_DIRECTION_COLUMN: 231 case MAXMOVES_COLUMN: 232 case RANDOM_CONTROL_COLUMN: 233 case PICKUP_COLUMN: 234 case DROP_COLUMN: 235 case LOCAL_COLUMN: 236 case TRAVEL_COLUMN: 237 case TIME_COLUMN: 238 case MAXLENGTH_COLUMN: 239 case GRADE: 240 case TRAINICONX: 241 case TRAINICONY: 242 case COMMENT_COLUMN: 243 case UP_COLUMN: 244 case DOWN_COLUMN: 245 return true; 246 default: 247 return false; 248 } 249 } 250 251 @Override 252 public Object getValueAt(int row, int col) { 253 if (row >= getRowCount()) { 254 return "ERROR unknown " + row; // NOI18N 255 } 256 RouteLocation rl = _routeList.get(row); 257 if (rl == null) { 258 return "ERROR unknown route location " + row; // NOI18N 259 } 260 switch (col) { 261 case ID_COLUMN: 262 return rl.getId(); 263 case NAME_COLUMN: 264 return rl.getName(); 265 case TRAIN_DIRECTION_COLUMN: { 266 JComboBox<String> cb = Setup.getTrainDirectionComboBox(); 267 cb.setSelectedItem(rl.getTrainDirectionString()); 268 return cb; 269 } 270 case MAXMOVES_COLUMN: 271 return rl.getMaxCarMoves(); 272 case RANDOM_CONTROL_COLUMN: { 273 JComboBox<String> cb = getRandomControlComboBox(); 274 cb.setSelectedItem(rl.getRandomControl()); 275 return cb; 276 } 277 case PICKUP_COLUMN: { 278 JComboBox<String> cb = getYesNoComboBox(); 279 cb.setSelectedItem(rl.isPickUpAllowed() ? Bundle.getMessage("yes") : Bundle.getMessage("no")); 280 return cb; 281 } 282 case DROP_COLUMN: { 283 JComboBox<String> cb = getYesNoComboBox(); 284 cb.setSelectedItem(rl.isDropAllowed() ? Bundle.getMessage("yes") : Bundle.getMessage("no")); 285 return cb; 286 } 287 case LOCAL_COLUMN: { 288 JComboBox<String> cb = getYesNoComboBox(); 289 cb.setSelectedItem(rl.isLocalMovesAllowed() ? Bundle.getMessage("yes") : Bundle.getMessage("no")); 290 return cb; 291 } 292 case TRAVEL_COLUMN: { 293 return rl.getWait() + Setup.getTravelTime(); 294 } 295 case TIME_COLUMN: { 296 JComboBox<String> cb = getTimeComboBox(); 297 cb.setSelectedItem(rl.getDepartureTime()); 298 return cb; 299 } 300 case MAXLENGTH_COLUMN: 301 return rl.getMaxTrainLength(); 302 case GRADE: 303 return rl.getGrade(); 304 case TRAINICONX: 305 return rl.getTrainIconX(); 306 case TRAINICONY: 307 return rl.getTrainIconY(); 308 case COMMENT_COLUMN: { 309 if (rl.getComment().equals(RouteLocation.NONE)) { 310 return Bundle.getMessage("Add"); 311 } else { 312 return Bundle.getMessage("ButtonEdit"); 313 } 314 } 315 case UP_COLUMN: 316 return Bundle.getMessage("Up"); 317 case DOWN_COLUMN: 318 return Bundle.getMessage("Down"); 319 case DELETE_COLUMN: 320 return Bundle.getMessage("ButtonDelete"); 321 default: 322 return "unknown " + col; // NOI18N 323 } 324 } 325 326 @Override 327 public void setValueAt(Object value, int row, int col) { 328 if (value == null) { 329 log.debug("Warning route table row {} still in edit", row); 330 return; 331 } 332 RouteLocation rl = _routeList.get(row); 333 if (rl == null) { 334 log.error("ERROR unknown route location for row: {}", row); // NOI18N 335 } 336 switch (col) { 337 case COMMENT_COLUMN: 338 setComment(rl); 339 break; 340 case UP_COLUMN: 341 moveUpRouteLocation(rl); 342 break; 343 case DOWN_COLUMN: 344 moveDownRouteLocation(rl); 345 break; 346 case DELETE_COLUMN: 347 deleteRouteLocation(rl); 348 break; 349 case TRAIN_DIRECTION_COLUMN: 350 setTrainDirection(value, rl); 351 break; 352 case MAXMOVES_COLUMN: 353 setMaxTrainMoves(value, rl); 354 break; 355 case RANDOM_CONTROL_COLUMN: 356 setRandomControlValue(value, rl); 357 break; 358 case PICKUP_COLUMN: 359 setPickup(value, rl); 360 break; 361 case DROP_COLUMN: 362 setDrop(value, rl); 363 break; 364 case LOCAL_COLUMN: 365 setLocal(value, rl); 366 break; 367 case TRAVEL_COLUMN: 368 setTravel(value, rl); 369 break; 370 case TIME_COLUMN: 371 setDepartureTime(value, rl); 372 break; 373 case MAXLENGTH_COLUMN: 374 setMaxTrainLength(value, rl); 375 break; 376 case GRADE: 377 setGrade(value, rl); 378 break; 379 case TRAINICONX: 380 setTrainIconX(value, rl); 381 break; 382 case TRAINICONY: 383 setTrainIconY(value, rl); 384 break; 385 default: 386 break; 387 } 388 } 389 390 private void moveUpRouteLocation(RouteLocation rl) { 391 log.debug("move location up"); 392 _route.moveLocationUp(rl); 393 } 394 395 private void moveDownRouteLocation(RouteLocation rl) { 396 log.debug("move location down"); 397 _route.moveLocationDown(rl); 398 } 399 400 private void deleteRouteLocation(RouteLocation rl) { 401 log.debug("Delete location"); 402 _route.deleteLocation(rl); 403 } 404 405 private int _trainDirection = Setup.getDirectionInt(Setup.getTrainDirectionList().get(0)); 406 407 public int getLastTrainDirection() { 408 return _trainDirection; 409 } 410 411 private void setTrainDirection(Object value, RouteLocation rl) { 412 _trainDirection = Setup.getDirectionInt((String) ((JComboBox<?>) value).getSelectedItem()); 413 rl.setTrainDirection(_trainDirection); 414 // update train icon 415 rl.setTrainIconCoordinates(); 416 } 417 418 private int _maxTrainMoves = Setup.getCarMoves(); 419 420 public int getLastMaxTrainMoves() { 421 return _maxTrainMoves; 422 } 423 424 private void setMaxTrainMoves(Object value, RouteLocation rl) { 425 int moves = (int) value; 426 if (moves <= 500) { 427 rl.setMaxCarMoves(moves); 428 _maxTrainMoves = moves; 429 } else { 430 JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("MaximumLocationMoves"), Bundle 431 .getMessage("CanNotChangeMoves"), JmriJOptionPane.ERROR_MESSAGE); 432 } 433 } 434 435 private void setRandomControlValue(Object value, RouteLocation rl) { 436 rl.setRandomControl((String) ((JComboBox<?>) value).getSelectedItem()); 437 } 438 439 private void setDrop(Object value, RouteLocation rl) { 440 rl.setDropAllowed( 441 ((String) ((JComboBox<?>) value).getSelectedItem()).equals(Bundle.getMessage("yes"))); 442 } 443 444 private void setPickup(Object value, RouteLocation rl) { 445 rl.setPickUpAllowed( 446 ((String) ((JComboBox<?>) value).getSelectedItem()).equals(Bundle.getMessage("yes"))); 447 } 448 449 private void setLocal(Object value, RouteLocation rl) { 450 rl.setLocalMovesAllowed( 451 ((String) ((JComboBox<?>) value).getSelectedItem()).equals(Bundle.getMessage("yes"))); 452 } 453 454 private int _maxTrainLength = Setup.getMaxTrainLength(); 455 456 public int getLastMaxTrainLength() { 457 return _maxTrainLength; 458 } 459 460 private void setTravel(Object value, RouteLocation rl) { 461 int wait = (int) value; 462 rl.setWait(wait - Setup.getTravelTime()); 463 } 464 465 private void setDepartureTime(Object value, RouteLocation rl) { 466 rl.setDepartureTime(((String) ((JComboBox<?>) value).getSelectedItem())); 467 } 468 469 private void setMaxTrainLength(Object value, RouteLocation rl) { 470 int length = (int) value; 471 if (length < 0) { 472 log.error("Maximum departure length must be a postive number"); 473 return; 474 } 475 if (length > Setup.getMaxTrainLength()) { 476 log.error("Maximum departure length can not exceed maximum train length"); 477 JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("DepartureLengthNotExceed", 478 length, Setup.getMaxTrainLength()), Bundle.getMessage("CanNotChangeMaxLength"), 479 JmriJOptionPane.ERROR_MESSAGE); 480 return; 481 } 482 if (rl != _route.getTerminatesRouteLocation() && 483 (length < 500 && Setup.getLengthUnit().equals(Setup.FEET) || 484 length < 160 && Setup.getLengthUnit().equals(Setup.METER))) { 485 // warn that train length might be too short 486 if (JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("LimitTrainLength", 487 length, Setup.getLengthUnit().toLowerCase(), rl.getName()), 488 Bundle.getMessage("WarningTooShort"), 489 JmriJOptionPane.OK_CANCEL_OPTION) != JmriJOptionPane.OK_OPTION) { 490 return; 491 } 492 } 493 rl.setMaxTrainLength(length); 494 _maxTrainLength = length; 495 } 496 497 private void setGrade(Object value, RouteLocation rl) { 498 double grade = (Double) value; 499 if (grade <= 6 && grade >= -6) { 500 rl.setGrade(grade); 501 } else { 502 log.error("Maximum grade is 6 percent"); 503 JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("MaxGrade"), 504 Bundle.getMessage("CanNotChangeGrade"), 505 JmriJOptionPane.ERROR_MESSAGE); 506 } 507 } 508 509 private void setTrainIconX(Object value, RouteLocation rl) { 510 int x = (int) value; 511 rl.setTrainIconX(x); 512 } 513 514 private void setTrainIconY(Object value, RouteLocation rl) { 515 int y = (int) value; 516 rl.setTrainIconY(y); 517 } 518 519 private void setComment(RouteLocation rl) { 520 // Create comment panel 521 final JDialog dialog = new JDialog(); 522 dialog.setLayout(new BorderLayout()); 523 dialog.setTitle(Bundle.getMessage("Comment") + " " + rl.getName()); 524 final JTextArea commentTextArea = new JTextArea(5, 100); 525 JScrollPane commentScroller = new JScrollPane(commentTextArea); 526 dialog.add(commentScroller, BorderLayout.CENTER); 527 commentTextArea.setText(rl.getComment()); 528 529 JPanel buttonPane = new JPanel(); 530 buttonPane.setLayout(new FlowLayout(FlowLayout.CENTER)); 531 dialog.add(buttonPane, BorderLayout.SOUTH); 532 533 // text color chooser 534 JPanel pTextColor = new JPanel(); 535 pTextColor.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TextColor"))); 536 JColorChooser commentColorChooser = new JColorChooser(rl.getCommentColor()); 537 AbstractColorChooserPanel commentColorPanels[] = {new SplitButtonColorChooserPanel()}; 538 commentColorChooser.setChooserPanels(commentColorPanels); 539 commentColorChooser.setPreviewPanel(new JPanel()); 540 pTextColor.add(commentColorChooser); 541 buttonPane.add(pTextColor); 542 543 JButton okayButton = new JButton(Bundle.getMessage("ButtonOK")); 544 okayButton.addActionListener(new ActionListener() { 545 @Override 546 public void actionPerformed(ActionEvent arg0) { 547 rl.setComment(commentTextArea.getText()); 548 rl.setCommentColor(commentColorChooser.getColor()); 549 dialog.dispose(); 550 return; 551 } 552 }); 553 buttonPane.add(okayButton); 554 555 JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel")); 556 cancelButton.addActionListener(new ActionListener() { 557 @Override 558 public void actionPerformed(ActionEvent arg0) { 559 dialog.dispose(); 560 return; 561 } 562 }); 563 buttonPane.add(cancelButton); 564 565 dialog.setModal(true); 566 dialog.pack(); 567 dialog.setVisible(true); 568 } 569 570 private JComboBox<String> getYesNoComboBox() { 571 JComboBox<String> cb = new JComboBox<>(); 572 cb.addItem(Bundle.getMessage("yes")); 573 cb.addItem(Bundle.getMessage("no")); 574 return cb; 575 } 576 577 private JComboBox<String> getRandomControlComboBox() { 578 JComboBox<String> cb = new JComboBox<>(); 579 cb.addItem(RouteLocation.DISABLED); 580 // 10 to 100 by 10 581 for (int i = 10; i < 101; i = i + 10) { 582 cb.addItem(Integer.toString(i)); 583 } 584 return cb; 585 } 586 587 protected JComboBox<String> getTimeComboBox() { 588 JComboBox<String> timeBox = new JComboBox<>(); 589 String hour; 590 String minute; 591 timeBox.addItem(""); 592 for (int i = 0; i < 24; i++) { 593 if (i < 10) { 594 hour = "0" + Integer.toString(i); 595 } else { 596 hour = Integer.toString(i); 597 } 598 for (int j = 0; j < 60; j += 1) { 599 if (j < 10) { 600 minute = "0" + Integer.toString(j); 601 } else { 602 minute = Integer.toString(j); 603 } 604 605 timeBox.addItem(hour + ":" + minute); 606 } 607 } 608 return timeBox; 609 } 610 611 // this table listens for changes to a route and it's locations 612 @Override 613 public void propertyChange(PropertyChangeEvent e) { 614 if (Control.SHOW_PROPERTY) { 615 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e 616 .getNewValue()); 617 } 618 if (e.getPropertyName().equals(Route.LISTCHANGE_CHANGED_PROPERTY)) { 619 updateList(); 620 fireTableDataChanged(); 621 } 622 if (e.getPropertyName().equals(Setup.TRAIN_DIRECTION_PROPERTY_CHANGE) || 623 e.getPropertyName().equals(Setup.TRAVEL_TIME_PROPERTY_CHANGE)) { 624 fireTableDataChanged(); 625 } 626 if (e.getSource().getClass().equals(RouteLocation.class)) { 627 RouteLocation rl = (RouteLocation) e.getSource(); 628 int row = _routeList.indexOf(rl); 629 if (Control.SHOW_PROPERTY) { 630 log.debug("Update route table row: {} id: {}", row, rl.getId()); 631 } 632 if (row >= 0) { 633 fireTableRowsUpdated(row, row); 634 } 635 } 636 } 637 638 private void removePropertyChangeRouteLocations() { 639 for (RouteLocation rl : _routeList) { 640 rl.removePropertyChangeListener(this); 641 } 642 } 643 644 public void dispose() { 645 removePropertyChangeRouteLocations(); 646 if (_route != null) { 647 _route.removePropertyChangeListener(this); 648 } 649 Setup.getDefault().removePropertyChangeListener(this); 650 _routeList.clear(); 651 fireTableDataChanged(); 652 } 653 654 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RouteEditTableModel.class); 655}