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