001package jmri.jmrit.operations.rollingstock.engines.gui;
002
003import java.awt.Font;
004import java.beans.PropertyChangeEvent;
005import java.beans.PropertyChangeListener;
006import java.util.List;
007
008import javax.swing.*;
009import javax.swing.table.TableCellEditor;
010
011import jmri.InstanceManager;
012import jmri.jmrit.operations.OperationsTableModel;
013import jmri.jmrit.operations.rollingstock.RollingStock;
014import jmri.jmrit.operations.rollingstock.engines.*;
015import jmri.jmrit.operations.setup.Control;
016import jmri.jmrit.operations.setup.Setup;
017import jmri.util.swing.XTableColumnModel;
018import jmri.util.table.ButtonEditor;
019import jmri.util.table.ButtonRenderer;
020
021import org.slf4j.Logger;
022import org.slf4j.LoggerFactory;
023
024/**
025 * Table Model for edit of engines used by operations
026 *
027 * @author Daniel Boudreau Copyright (C) 2008, 2012, 2025, 2026
028 */
029public class EnginesTableModel extends OperationsTableModel implements PropertyChangeListener {
030
031    EngineManager engineManager = InstanceManager.getDefault(EngineManager.class); // There is only one manager
032
033    // Defines the columns
034    private static final int SELECT_COLUMN = 0;
035    private static final int NUM_COLUMN = 1;
036    private static final int ROAD_COLUMN = 2;
037    private static final int MODEL_COLUMN = 3;
038    private static final int HP_COLUMN = 4;
039    private static final int WEIGHT_COLUMN = 5;
040    private static final int TYPE_COLUMN = 6;
041    private static final int LENGTH_COLUMN = 7;
042    private static final int COLOR_COLUMN = 8;
043    private static final int CONSIST_COLUMN = 9;
044    private static final int LOCATION_COLUMN = 10;
045    private static final int RFID_WHERE_LAST_SEEN_COLUMN = 11;
046    private static final int RFID_WHEN_LAST_SEEN_COLUMN = 12;
047    private static final int DESTINATION_COLUMN = 13;
048    private static final int PREVIOUS_LOCATION_COLUMN = 14;
049    private static final int TRAIN_COLUMN = 15;
050    private static final int LAST_TRAIN_COLUMN = 16;
051    private static final int MOVES_COLUMN = 17;
052    private static final int BUILT_COLUMN = 18;
053    private static final int OWNER_COLUMN = 19;
054    private static final int VALUE_COLUMN = 20;
055    private static final int RFID_COLUMN = 21;
056    private static final int LAST_COLUMN = 22;
057    private static final int DCC_ADDRESS_COLUMN = 23;
058    private static final int PICKUP_COLUMN = 24;
059    private static final int SETOUT_COLUMN = 25;
060    private static final int COMMENT_COLUMN = 26;
061    private static final int SET_COLUMN = 27;
062    private static final int EDIT_COLUMN = 28;
063
064    private static final int HIGHEST_COLUMN = EDIT_COLUMN + 1;
065
066    public EnginesTableModel(boolean showAllLocos, String locationName, String trackName) {
067        super();
068        showAll = showAllLocos;
069        this.locationName = locationName;
070        this.trackName = trackName;
071        engineManager.addPropertyChangeListener(this);
072        updateList();
073    }
074
075    public final int SORTBY_NUMBER = 0;
076    public final int SORTBY_ROAD = 1;
077    public final int SORTBY_MODEL = 2;
078    public final int SORTBY_LOCATION = 3;
079    public final int SORTBY_DESTINATION = 4;
080    public final int SORTBY_TRAIN = 5;
081    public final int SORTBY_MOVES = 6;
082    public final int SORTBY_CONSIST = 7;
083    public final int SORTBY_BUILT = 8;
084    public final int SORTBY_OWNER = 9;
085    public final int SORTBY_VALUE = 10;
086    public final int SORTBY_RFID = 11;
087    public final int SORTBY_LAST = 12;
088    public final int SORTBY_HP = 13;
089    public final int SORTBY_DCC_ADDRESS = 14;
090    public final int SORTBY_PICKUP = 15;
091    public final int SORTBY_COMMENT = 16;
092
093    private int _sort = SORTBY_NUMBER;
094
095    /**
096     * Not all columns are visible at the same time.
097     *
098     * @param sort which sort is active
099     */
100    public void setSort(int sort) {
101        _sort = sort;
102        updateList();
103        if (sort == SORTBY_MOVES ||
104                sort == SORTBY_BUILT ||
105                sort == SORTBY_OWNER ||
106                sort == SORTBY_VALUE ||
107                sort == SORTBY_RFID ||
108                sort == SORTBY_LAST ||
109                sort == SORTBY_DCC_ADDRESS ||
110                sort == SORTBY_PICKUP ||
111                sort == SORTBY_COMMENT) {
112            XTableColumnModel tcm = (XTableColumnModel) _table.getColumnModel();
113            tcm.setColumnVisible(tcm.getColumnByModelIndex(MOVES_COLUMN), sort == SORTBY_MOVES);
114            tcm.setColumnVisible(tcm.getColumnByModelIndex(BUILT_COLUMN), sort == SORTBY_BUILT);
115            tcm.setColumnVisible(tcm.getColumnByModelIndex(OWNER_COLUMN), sort == SORTBY_OWNER);
116            tcm.setColumnVisible(tcm.getColumnByModelIndex(VALUE_COLUMN), sort == SORTBY_VALUE);
117            tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_COLUMN), sort == SORTBY_RFID);
118            tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_WHEN_LAST_SEEN_COLUMN), sort == SORTBY_RFID);
119            tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_WHERE_LAST_SEEN_COLUMN), sort == SORTBY_RFID);
120            tcm.setColumnVisible(tcm.getColumnByModelIndex(PREVIOUS_LOCATION_COLUMN), sort == SORTBY_LAST);
121            tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_COLUMN), sort == SORTBY_LAST);
122            tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_TRAIN_COLUMN), sort == SORTBY_LAST);
123            tcm.setColumnVisible(tcm.getColumnByModelIndex(TRAIN_COLUMN), true);
124            tcm.setColumnVisible(tcm.getColumnByModelIndex(PICKUP_COLUMN), sort == SORTBY_PICKUP);
125            tcm.setColumnVisible(tcm.getColumnByModelIndex(SETOUT_COLUMN), sort == SORTBY_PICKUP);
126            tcm.setColumnVisible(tcm.getColumnByModelIndex(DCC_ADDRESS_COLUMN), sort == SORTBY_DCC_ADDRESS);
127            tcm.setColumnVisible(tcm.getColumnByModelIndex(COMMENT_COLUMN), sort == SORTBY_COMMENT);
128        }
129        fireTableDataChanged();
130    }
131
132    public void toggleSelectVisible() {
133        XTableColumnModel tcm = (XTableColumnModel) _table.getColumnModel();
134        tcm.setColumnVisible(tcm.getColumnByModelIndex(SELECT_COLUMN),
135                !tcm.isColumnVisible(tcm.getColumnByModelIndex(SELECT_COLUMN)));
136    }
137
138    public void resetCheckboxes() {
139        for (Engine engine : engineList) {
140            engine.setSelected(false);
141        }
142    }
143
144    public String getSortByName() {
145        return getSortByName(_sort);
146    }
147
148    public String getSortByName(int sort) {
149        switch (sort) {
150            case SORTBY_NUMBER:
151                return Bundle.getMessage("Number");
152            case SORTBY_ROAD:
153                return Bundle.getMessage("Road");
154            case SORTBY_MODEL:
155                return Bundle.getMessage("Model");
156            case SORTBY_LOCATION:
157                return Bundle.getMessage("Location");
158            case SORTBY_DESTINATION:
159                return Bundle.getMessage("Destination");
160            case SORTBY_TRAIN:
161                return Bundle.getMessage("Train");
162            case SORTBY_MOVES:
163                return Bundle.getMessage("Moves");
164            case SORTBY_CONSIST:
165                return Bundle.getMessage("Consist");
166            case SORTBY_BUILT:
167                return Bundle.getMessage("Built");
168            case SORTBY_OWNER:
169                return Bundle.getMessage("Owner");
170            case SORTBY_DCC_ADDRESS:
171                return Bundle.getMessage("DccAddress");
172            case SORTBY_HP:
173                return Bundle.getMessage("HP");
174            case SORTBY_VALUE:
175                return Setup.getValueLabel();
176            case SORTBY_RFID:
177                return Setup.getRfidLabel();
178            case SORTBY_LAST:
179                return Bundle.getMessage("Last");
180            case SORTBY_COMMENT:
181                return Bundle.getMessage("Comment");
182            default:
183                return Bundle.getMessage("ErrorTitle"); // NOI18N
184        }
185    }
186
187    /**
188     * Search for engine by road number
189     * 
190     * @param roadNumber The string road number to search for.
191     * @return -1 if not found, table row number if found
192     */
193    public int findEngineByRoadNumber(String roadNumber) {
194        return findRollingStockByRoadNumber(roadNumber, engineList);
195    }
196
197    public Engine getEngineAtIndex(int index) {
198        return engineList.get(index);
199    }
200
201    private void updateList() {
202        // first, remove listeners from the individual objects
203        removePropertyChangeEngines();
204        engineList = getSelectedEngineList();
205        // and add listeners back in
206        addPropertyChangeEngines();
207    }
208
209    public List<Engine> getSelectedEngineList() {
210        return getEngineList(_sort);
211    }
212
213    public List<Engine> getEngineList(int sort) {
214        List<Engine> list;
215        switch (sort) {
216            case SORTBY_ROAD:
217                list = engineManager.getByRoadNameList();
218                break;
219            case SORTBY_MODEL:
220                list = engineManager.getByModelList();
221                break;
222            case SORTBY_LOCATION:
223                list = engineManager.getByLocationList();
224                break;
225            case SORTBY_DESTINATION:
226                list = engineManager.getByDestinationList();
227                break;
228            case SORTBY_TRAIN:
229                list = engineManager.getByTrainList();
230                break;
231            case SORTBY_MOVES:
232                list = engineManager.getByMovesList();
233                break;
234            case SORTBY_CONSIST:
235                list = engineManager.getByConsistList();
236                break;
237            case SORTBY_OWNER:
238                list = engineManager.getByOwnerList();
239                break;
240            case SORTBY_BUILT:
241                list = engineManager.getByBuiltList();
242                break;
243            case SORTBY_VALUE:
244                list = engineManager.getByValueList();
245                break;
246            case SORTBY_RFID:
247                list = engineManager.getByRfidList();
248                break;
249            case SORTBY_LAST:
250                list = engineManager.getByLastDateList();
251                break;
252            case SORTBY_PICKUP:
253                list = engineManager.getByPickupList();
254                break;
255            case SORTBY_COMMENT:
256                list = engineManager.getByCommentList();
257                break;
258            case SORTBY_NUMBER:
259            default:
260                list = engineManager.getByNumberList();
261        }
262        filterList(list);
263        return list;
264    }
265
266    List<Engine> engineList = null;
267
268    EnginesTableFrame _frame;
269
270    void initTable(JTable table, EnginesTableFrame frame) {
271        super.initTable(table);
272        _frame = frame;
273        initTable();
274    }
275
276    // Default engines frame table column widths, starts with Number column and ends with Edit
277    private final int[] _enginesTableColumnWidths =
278            {60, 60, 60, 65, 50, 65, 65, 65, 35, 75, 190, 190, 190, 140, 190, 65, 90, 50, 50, 50, 50, 100, 130, 50, 50,
279                    50, 100, 65, 70};
280
281    void initTable() {
282        // Use XTableColumnModel so we can control which columns are visible
283        XTableColumnModel tcm = new XTableColumnModel();
284        _table.setColumnModel(tcm);
285        _table.createDefaultColumnsFromModel();
286
287        // Install the button handlers
288        ButtonRenderer buttonRenderer = new ButtonRenderer();
289        tcm.getColumn(SET_COLUMN).setCellRenderer(buttonRenderer);
290        TableCellEditor buttonEditor = new ButtonEditor(new javax.swing.JButton());
291        tcm.getColumn(SET_COLUMN).setCellEditor(buttonEditor);
292        tcm.getColumn(EDIT_COLUMN).setCellRenderer(buttonRenderer);
293        tcm.getColumn(EDIT_COLUMN).setCellEditor(buttonEditor);
294
295        // set column preferred widths
296        // load defaults, xml file data not found
297        for (int i = 0; i < tcm.getColumnCount(); i++) {
298            tcm.getColumn(i).setPreferredWidth(_enginesTableColumnWidths[i]);
299        }
300        _frame.loadTableDetails(_table);
301
302        // turn off columns
303        tcm.setColumnVisible(tcm.getColumnByModelIndex(BUILT_COLUMN), false);
304        tcm.setColumnVisible(tcm.getColumnByModelIndex(OWNER_COLUMN), false);
305        tcm.setColumnVisible(tcm.getColumnByModelIndex(VALUE_COLUMN), false);
306        tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_COLUMN), false);
307        tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_WHEN_LAST_SEEN_COLUMN), false);
308        tcm.setColumnVisible(tcm.getColumnByModelIndex(RFID_WHERE_LAST_SEEN_COLUMN), false);
309        tcm.setColumnVisible(tcm.getColumnByModelIndex(PREVIOUS_LOCATION_COLUMN), false);
310        tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_COLUMN), false);
311        tcm.setColumnVisible(tcm.getColumnByModelIndex(LAST_TRAIN_COLUMN), false);
312        tcm.setColumnVisible(tcm.getColumnByModelIndex(DCC_ADDRESS_COLUMN), false);
313        tcm.setColumnVisible(tcm.getColumnByModelIndex(PICKUP_COLUMN), false);
314        tcm.setColumnVisible(tcm.getColumnByModelIndex(SETOUT_COLUMN), false);
315        tcm.setColumnVisible(tcm.getColumnByModelIndex(COMMENT_COLUMN), false);
316
317        // turn on default
318        tcm.setColumnVisible(tcm.getColumnByModelIndex(MOVES_COLUMN), true);
319    }
320
321    @Override
322    public int getRowCount() {
323        return engineList.size();
324    }
325
326    @Override
327    public int getColumnCount() {
328        return HIGHEST_COLUMN;
329    }
330
331    @Override
332    public String getColumnName(int col) {
333        switch (col) {
334            case SELECT_COLUMN:
335                return Bundle.getMessage("ButtonSelect");
336            case NUM_COLUMN:
337                return Bundle.getMessage("Number");
338            case ROAD_COLUMN:
339                return Bundle.getMessage("Road");
340            case MODEL_COLUMN:
341                return Bundle.getMessage("Model");
342            case HP_COLUMN:
343                return Bundle.getMessage("HP");
344            case TYPE_COLUMN:
345                return Bundle.getMessage("Type");
346            case COLOR_COLUMN:
347                return Bundle.getMessage("Color");
348            case LENGTH_COLUMN:
349                return Bundle.getMessage("Len");
350            case WEIGHT_COLUMN:
351                return Bundle.getMessage("Weight");
352            case CONSIST_COLUMN:
353                return Bundle.getMessage("Consist");
354            case LOCATION_COLUMN:
355                return Bundle.getMessage("Location");
356            case RFID_WHERE_LAST_SEEN_COLUMN:
357                return Bundle.getMessage("WhereLastSeen");
358            case RFID_WHEN_LAST_SEEN_COLUMN:
359                return Bundle.getMessage("WhenLastSeen");
360            case DESTINATION_COLUMN:
361                return Bundle.getMessage("Destination");
362            case PREVIOUS_LOCATION_COLUMN:
363                return Bundle.getMessage("LastLocation");
364            case TRAIN_COLUMN:
365                return Bundle.getMessage("Train");
366            case LAST_TRAIN_COLUMN:
367                return Bundle.getMessage("LastTrain");
368            case MOVES_COLUMN:
369                return Bundle.getMessage("Moves");
370            case BUILT_COLUMN:
371                return Bundle.getMessage("Built");
372            case OWNER_COLUMN:
373                return Bundle.getMessage("Owner");
374            case VALUE_COLUMN:
375                return Setup.getValueLabel();
376            case RFID_COLUMN:
377                return Setup.getRfidLabel();
378            case LAST_COLUMN:
379                return Bundle.getMessage("LastMoved");
380            case DCC_ADDRESS_COLUMN:
381                return Bundle.getMessage("DccAddress");
382            case PICKUP_COLUMN:
383                return Bundle.getMessage("Pickup");
384            case SETOUT_COLUMN:
385                return Bundle.getMessage("SetOut");
386            case COMMENT_COLUMN:
387                return Bundle.getMessage("Comment");
388            case SET_COLUMN:
389                return Bundle.getMessage("Set");
390            case EDIT_COLUMN:
391                return Bundle.getMessage("ButtonEdit"); // titles above all columns
392            default:
393                return "unknown"; // NOI18N
394        }
395    }
396
397    @Override
398    public Class<?> getColumnClass(int col) {
399        switch (col) {
400            case SELECT_COLUMN:
401                return Boolean.class;
402            case SET_COLUMN:
403            case EDIT_COLUMN:
404                return JButton.class;
405            case LENGTH_COLUMN:
406            case MOVES_COLUMN:
407                return Integer.class;
408            default:
409                return String.class;
410        }
411    }
412
413    @Override
414    public boolean isCellEditable(int row, int col) {
415        Engine engine = engineList.get(row);
416        if (engine.isClone()) {
417            return false;
418        }
419        switch (col) {
420            case SELECT_COLUMN:
421            case SET_COLUMN:
422            case EDIT_COLUMN:
423            case MOVES_COLUMN:
424            case VALUE_COLUMN:
425            case RFID_COLUMN:
426                return true;
427            default:
428                return false;
429        }
430    }
431
432    @Override
433    public Object getValueAt(int row, int col) {
434        if (row >= getRowCount()) {
435            return "ERROR row " + row; // NOI18N
436        }
437        Engine engine = engineList.get(row);
438        if (engine == null) {
439            return "ERROR engine unknown " + row; // NOI18N
440        }
441        if (engine.isClone()) {
442            setToolTip(Bundle.getMessage("DoNotModifyClone", engine.toString()), col);
443        } else {
444            setToolTip(null, col);
445        }
446        switch (col) {
447            case SELECT_COLUMN:
448                return engine.isSelected();
449            case NUM_COLUMN:
450                return engine.getNumber();
451            case ROAD_COLUMN:
452                return engine.getRoadName();
453            case COLOR_COLUMN:
454                return engine.getColorName();
455            case LENGTH_COLUMN:
456                return engine.getLengthInteger();
457            case MODEL_COLUMN:
458                return engine.getModel();
459            case HP_COLUMN:
460                return engine.getHp();
461            case TYPE_COLUMN: {
462                if (engine.isBunit()) {
463                    return engine.getTypeName() + " " + Bundle.getMessage("(B)");
464                }
465                return engine.getTypeName();
466            }
467            case WEIGHT_COLUMN:
468                return engine.getWeightTons();
469            case CONSIST_COLUMN: {
470                if (engine.isLead()) {
471                    return engine.getConsistName() + "*";
472                }
473                return engine.getConsistName();
474            }
475            case LOCATION_COLUMN: {
476                String s = engine.getStatus();
477                if (!engine.getLocationName().equals(Engine.NONE)) {
478                    s = engine.getStatus() + engine.getLocationName() + " (" + engine.getTrackName() + ")";
479                }
480                return s;
481            }
482            case RFID_WHERE_LAST_SEEN_COLUMN: {
483                return engine.getWhereLastSeenName() +
484                        (engine.getTrackLastSeenName().equals(Engine.NONE) ? ""
485                                : " (" + engine.getTrackLastSeenName() + ")");
486            }
487            case RFID_WHEN_LAST_SEEN_COLUMN: {
488                return engine.getWhenLastSeenDate();
489            }
490            case DESTINATION_COLUMN: {
491                String s = "";
492                if (!engine.getDestinationName().equals(Engine.NONE)) {
493                    s = engine.getDestinationName() + " (" + engine.getDestinationTrackName() + ")";
494                }
495                return s;
496            }
497            case PREVIOUS_LOCATION_COLUMN: {
498                String s = "";
499                if (!engine.getLastLocationName().equals(Engine.NONE)) {
500                    s = engine.getLastLocationName() + " (" + engine.getLastTrackName() + ")";
501                }
502                return s;
503            }
504            case TRAIN_COLUMN: {
505                // if train was manually set by user add an asterisk
506                if (engine.getTrain() != null && engine.getRouteLocation() == null) {
507                    return engine.getTrainName() + "*";
508                }
509                return engine.getTrainName();
510            }
511            case LAST_TRAIN_COLUMN:
512                return engine.getLastTrainName();
513            case MOVES_COLUMN:
514                return engine.getMoves();
515            case BUILT_COLUMN:
516                return engine.getBuilt();
517            case OWNER_COLUMN:
518                return engine.getOwnerName();
519            case VALUE_COLUMN:
520                return engine.getValue();
521            case RFID_COLUMN:
522                return engine.getRfid();
523            case LAST_COLUMN:
524                return engine.getSortDate();
525            case DCC_ADDRESS_COLUMN:
526                return engine.getDccAddress();
527            case PICKUP_COLUMN:
528                return engine.getPickupTime();
529            case SETOUT_COLUMN:
530                return engine.getSetoutTime();
531            case COMMENT_COLUMN:
532                return engine.getComment();
533            case SET_COLUMN:
534                return Bundle.getMessage("Set");
535            case EDIT_COLUMN:
536                return Bundle.getMessage("ButtonEdit");
537            default:
538                return "unknown " + col; // NOI18N
539        }
540    }
541
542    EngineEditFrame engineEditFrame = null;
543    EngineSetFrame engineSetFrame = null;
544
545    @Override
546    public void setValueAt(Object value, int row, int col) {
547        Engine engine = engineList.get(row);
548        switch (col) {
549            case SELECT_COLUMN:
550                engine.setSelected(((Boolean) value).booleanValue());
551                break;
552            case MOVES_COLUMN:
553                try {
554                    engine.setMoves(Integer.parseInt(value.toString()));
555                } catch (NumberFormatException e) {
556                    log.error("move count must be a number");
557                }
558                break;
559            case BUILT_COLUMN:
560                engine.setBuilt(value.toString());
561                break;
562            case OWNER_COLUMN:
563                engine.setOwnerName(value.toString());
564                break;
565            case VALUE_COLUMN:
566                engine.setValue(value.toString());
567                break;
568            case RFID_COLUMN:
569                engine.setRfid(value.toString());
570                break;
571            case SET_COLUMN:
572                log.debug("Set engine location");
573                if (engineSetFrame != null) {
574                    engineSetFrame.dispose();
575                }
576                // use invokeLater so new window appears on top
577                SwingUtilities.invokeLater(() -> {
578                    engineSetFrame = new EngineSetFrame();
579                    engineSetFrame.initComponents();
580                    engineSetFrame.load(engine);
581                });
582                break;
583            case EDIT_COLUMN:
584                log.debug("Edit engine");
585                if (engineEditFrame != null) {
586                    engineEditFrame.dispose();
587                }
588                // use invokeLater so new window appears on top
589                SwingUtilities.invokeLater(() -> {
590                    engineEditFrame = new EngineEditFrame();
591                    engineEditFrame.initComponents();
592                    engineEditFrame.load(engine);
593                });
594                break;
595            default:
596                break;
597        }
598    }
599
600    @Override
601    protected Font getFont(int row) {
602        Engine eng = engineList.get(row);
603        if (eng.isClone() || engineManager.getClone(eng) != null) {
604            Font font = super.getFont(row);
605            font = new Font(font.getFontName(), Font.ITALIC, font.getSize());
606            return font;
607        }
608        return super.getFont(row);
609    }
610
611    public void dispose() {
612        log.debug("dispose EngineTableModel");
613        engineManager.removePropertyChangeListener(this);
614        removePropertyChangeEngines();
615        if (engineSetFrame != null) {
616            engineSetFrame.dispose();
617        }
618        if (engineEditFrame != null) {
619            engineEditFrame.dispose();
620        }
621    }
622
623    private void addPropertyChangeEngines() {
624        for (RollingStock rs : engineManager.getList()) {
625            rs.addPropertyChangeListener(this);
626        }
627    }
628
629    private void removePropertyChangeEngines() {
630        for (RollingStock rs : engineManager.getList()) {
631            rs.removePropertyChangeListener(this);
632        }
633    }
634
635    @Override
636    public void propertyChange(PropertyChangeEvent e) {
637        if (Control.SHOW_PROPERTY) {
638            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
639                    .getNewValue());
640        }
641        if (e.getPropertyName().equals(EngineManager.LISTLENGTH_CHANGED_PROPERTY) ||
642                e.getPropertyName().equals(ConsistManager.LISTLENGTH_CHANGED_PROPERTY)) {
643            updateList();
644            fireTableDataChanged();
645        }
646        // Engine length, type, and HP are based on model, so multiple changes
647        else if (e.getPropertyName().equals(Engine.LENGTH_CHANGED_PROPERTY) ||
648                e.getPropertyName().equals(Engine.TYPE_CHANGED_PROPERTY) ||
649                e.getPropertyName().equals(Engine.HP_CHANGED_PROPERTY)) {
650            fireTableDataChanged();
651        }
652        // must be a engine change
653        else if (e.getSource().getClass().equals(Engine.class)) {
654            Engine engine = (Engine) e.getSource();
655            int row = engineList.indexOf(engine);
656            if (Control.SHOW_PROPERTY) {
657                log.debug("Update engine table row: {}", row);
658            }
659            if (row >= 0) {
660                fireTableRowsUpdated(row, row);
661                // next is needed when only showing engines at a location or track
662            } else if (e.getPropertyName().equals(Engine.TRACK_CHANGED_PROPERTY)) {
663                updateList();
664                fireTableDataChanged();
665            }
666        }
667    }
668
669    private static final Logger log = LoggerFactory.getLogger(EnginesTableModel.class);
670}