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