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