001package jmri.jmrit.operations.trains.schedules;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005import java.util.List;
006import javax.swing.JTable;
007import jmri.InstanceManager;
008import jmri.jmrit.beantable.EnablingCheckboxRenderer;
009import jmri.jmrit.operations.setup.Control;
010import jmri.jmrit.operations.trains.Train;
011import jmri.jmrit.operations.trains.TrainManager;
012import jmri.util.swing.XTableColumnModel;
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016/**
017 * Table Model for edit of train schedules used by operations
018 *
019 * @author Daniel Boudreau Copyright (C) 2010, 2012
020 */
021public class TrainsScheduleTableModel extends javax.swing.table.AbstractTableModel implements PropertyChangeListener {
022
023    TrainManager trainManager = InstanceManager.getDefault(TrainManager.class);
024    TrainScheduleManager scheduleManager = InstanceManager.getDefault(TrainScheduleManager.class);
025
026    // Defines the columns
027    private static final int IDCOLUMN = 0;
028    private static final int NAMECOLUMN = IDCOLUMN + 1;
029    private static final int DESCRIPTIONCOLUMN = NAMECOLUMN + 1;
030
031    private static final int FIXEDCOLUMN = DESCRIPTIONCOLUMN + 1;
032
033    public TrainsScheduleTableModel() {
034        super();
035        trainManager.addPropertyChangeListener(this);
036        scheduleManager.addPropertyChangeListener(this);
037        updateList();
038        addPropertyChangeTrainSchedules();
039    }
040
041    public final int SORTBYNAME = 1;
042    public final int SORTBYTIME = 2;
043    public final int SORTBYDEPARTS = 3;
044    public final int SORTBYTERMINATES = 4;
045    public final int SORTBYROUTE = 5;
046    public final int SORTBYID = 6;
047
048    private int _sort = SORTBYTIME;
049
050    public void setSort(int sort) {
051        _sort = sort;
052        updateList();
053        //fireTableStructureChanged();
054        initTable();
055        if (_table.getRowSorter() != null) {
056            _table.getRowSorter().setSortKeys(null);
057        }
058    }
059
060    private void updateList() {
061        // first, remove listeners from the individual objects
062        removePropertyChangeTrains();
063
064        if (_sort == SORTBYID) {
065            sysList = trainManager.getTrainsByIdList();
066        } else if (_sort == SORTBYNAME) {
067            sysList = trainManager.getTrainsByNameList();
068        } else if (_sort == SORTBYTIME) {
069            sysList = trainManager.getTrainsByTimeList();
070        } else if (_sort == SORTBYDEPARTS) {
071            sysList = trainManager.getTrainsByDepartureList();
072        } else if (_sort == SORTBYTERMINATES) {
073            sysList = trainManager.getTrainsByTerminatesList();
074        } else if (_sort == SORTBYROUTE) {
075            sysList = trainManager.getTrainsByRouteList();
076        }
077
078        // and add listeners back in
079        addPropertyChangeTrains();
080    }
081
082    public List<Train> getSelectedTrainList() {
083        return sysList;
084    }
085
086    List<Train> sysList = null;
087    JTable _table = null;
088    TrainsScheduleTableFrame _frame = null;
089
090    void initTable(JTable table, TrainsScheduleTableFrame frame) {
091        _table = table;
092        _frame = frame;
093        initTable();
094    }
095
096    // only the first three columns of the table have defaults
097    private final int[] tableScheduleColumnWidths = {50, 70, 120};
098
099    void initTable() {
100        if (_table == null) {
101            return;
102        }
103        
104        // Save table column order
105        XTableColumnModel tcm = new XTableColumnModel();
106        _table.setColumnModel(tcm);
107        _table.createDefaultColumnsFromModel();
108        
109        // Install the button handlers
110        _table.setDefaultRenderer(Boolean.class, new EnablingCheckboxRenderer());
111
112        // set column preferred widths
113        for (int i = 0; i < tableScheduleColumnWidths.length; i++) {
114            tcm.getColumn(i).setPreferredWidth(tableScheduleColumnWidths[i]);
115        }
116        _frame.loadTableDetails(_table);
117    }
118
119    @Override
120    public int getRowCount() {
121        return sysList.size();
122    }
123
124    public int getFixedColumn() {
125        return FIXEDCOLUMN;
126    }
127
128    @Override
129    public int getColumnCount() {
130        return getFixedColumn() + scheduleManager.numEntries();
131    }
132
133    @Override
134    public String getColumnName(int col) {
135        switch (col) {
136            case IDCOLUMN:
137                if (_sort == SORTBYID) {
138                    return Bundle.getMessage("Id");
139                }
140                return Bundle.getMessage("Time");
141            case NAMECOLUMN:
142                return Bundle.getMessage("Name");
143            case DESCRIPTIONCOLUMN:
144                return Bundle.getMessage("Description");
145            default:
146                // fall out
147                break;
148        }
149        TrainSchedule ts = getSchedule(col);
150        if (ts != null) {
151            return ts.getName();
152        }
153        return "unknown"; // NOI18N
154    }
155
156    @Override
157    public Class<?> getColumnClass(int col) {
158        switch (col) {
159            case IDCOLUMN:
160                return String.class;
161            case NAMECOLUMN:
162                return String.class;
163            case DESCRIPTIONCOLUMN:
164                return String.class;
165            default:
166                // fall out
167                break;
168        }
169        if (col >= getFixedColumn() && col < getColumnCount()) {
170            return Boolean.class;
171        }
172        return null;
173    }
174
175    @Override
176    public boolean isCellEditable(int row, int col) {
177        switch (col) {
178            case IDCOLUMN:
179            case NAMECOLUMN:
180            case DESCRIPTIONCOLUMN:
181                return false;
182            default:
183                return true;
184        }
185    }
186
187    @Override
188    public Object getValueAt(int row, int col) {
189        if (row >= getRowCount()) {
190            return "ERROR row " + row; // NOI18N
191        }
192        Train train = sysList.get(row);
193        if (train == null) {
194            return "ERROR train unknown " + row; // NOI18N
195        }
196        switch (col) {
197            case IDCOLUMN: {
198                if (_sort == SORTBYID) {
199                    return train.getId();
200                }
201                return train.getDepartureTime();
202            }
203            case NAMECOLUMN:
204                return train.getIconName();
205            case DESCRIPTIONCOLUMN:
206                return train.getDescription();
207            default:
208                // fall out
209                break;
210        }
211        TrainSchedule ts = getSchedule(col);
212        if (ts != null) {
213            return ts.containsTrainId(train.getId());
214        }
215        return "unknown " + col; // NOI18N
216    }
217
218    @Override
219    public void setValueAt(Object value, int row, int col) {
220        TrainSchedule ts = getSchedule(col);
221        if (ts != null) {
222            Train train = sysList.get(row);
223            if (train == null) {
224                log.error("train not found");
225                return;
226            }
227            if (((Boolean) value).booleanValue()) {
228                ts.addTrainId(train.getId());
229            } else {
230                ts.removeTrainId(train.getId());
231            }
232        }
233    }
234
235    @Override
236    public void propertyChange(PropertyChangeEvent e) {
237        if (Control.SHOW_PROPERTY) {
238            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
239                    .getNewValue());
240        }
241        if (e.getPropertyName().equals(TrainManager.LISTLENGTH_CHANGED_PROPERTY) ||
242                e.getPropertyName().equals(TrainManager.TRAIN_ACTION_CHANGED_PROPERTY)) {
243            updateList();
244            fireTableDataChanged();
245        } else if (e.getPropertyName().equals(TrainScheduleManager.LISTLENGTH_CHANGED_PROPERTY) ||
246                e.getPropertyName().equals(TrainSchedule.NAME_CHANGED_PROPERTY)) {
247            // update property change
248            removePropertyChangeTrainSchedules();
249            addPropertyChangeTrainSchedules();
250            //fireTableStructureChanged();
251            initTable();
252        } else if (e.getPropertyName().equals(TrainSchedule.SCHEDULE_CHANGED_PROPERTY)) {
253            fireTableDataChanged();
254        } else if (e.getSource().getClass().equals(Train.class)) {
255            Train train = (Train) e.getSource();
256            int row = sysList.indexOf(train);
257            if (Control.SHOW_PROPERTY) {
258                log.debug("Update train table row: {} name: {}", row, train.getName());
259            }
260            if (row >= 0) {
261                fireTableRowsUpdated(row, row);
262            }
263        }
264    }
265
266    public TrainSchedule getSchedule(int col) {
267        if (col >= getFixedColumn() && col < getColumnCount()) {
268            List<TrainSchedule> trainSchedules = scheduleManager.getSchedulesByIdList();
269            TrainSchedule ts = trainSchedules.get(col - getFixedColumn());
270            return ts;
271        }
272        return null;
273    }
274
275    private void removePropertyChangeTrainSchedules() {
276        List<TrainSchedule> trainSchedules = scheduleManager.getSchedulesByIdList();
277        for (TrainSchedule ts : trainSchedules) {
278            ts.removePropertyChangeListener(this);
279        }
280    }
281
282    private void addPropertyChangeTrainSchedules() {
283        List<TrainSchedule> trainSchedules = scheduleManager.getSchedulesByIdList();
284        for (TrainSchedule ts : trainSchedules) {
285            ts.addPropertyChangeListener(this);
286        }
287    }
288
289    private void removePropertyChangeTrains() {
290        if (sysList != null) {
291            for (Train train : sysList) {
292                train.removePropertyChangeListener(this);
293            }
294        }
295    }
296
297    private void addPropertyChangeTrains() {
298        if (sysList != null) {
299            for (Train train : sysList) {
300                train.addPropertyChangeListener(this);
301            }
302        }
303    }
304
305    public void dispose() {
306        trainManager.removePropertyChangeListener(this);
307        scheduleManager.removePropertyChangeListener(this);
308        removePropertyChangeTrains();
309        removePropertyChangeTrainSchedules();
310    }
311
312    private final static Logger log = LoggerFactory.getLogger(TrainsScheduleTableModel.class);
313}