001package jmri.jmrit.operations.routes.gui;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005import java.util.List;
006
007import javax.swing.*;
008import javax.swing.table.TableCellEditor;
009import javax.swing.table.TableColumnModel;
010
011import jmri.InstanceManager;
012import jmri.jmrit.operations.locations.LocationManager;
013import jmri.jmrit.operations.routes.*;
014import jmri.jmrit.operations.setup.Control;
015import jmri.jmrit.operations.setup.Setup;
016import jmri.jmrit.operations.trains.Train;
017import jmri.jmrit.operations.trains.TrainManager;
018import jmri.util.swing.JmriJOptionPane;
019import jmri.util.table.ButtonEditor;
020import jmri.util.table.ButtonRenderer;
021
022/**
023 * Table Model for edit of routes used by operations
024 *
025 * @author Daniel Boudreau Copyright (C) 2008, 2015
026 */
027public class RoutesTableModel extends javax.swing.table.AbstractTableModel implements PropertyChangeListener {
028
029    RouteManager routemanager; // There is only one manager
030
031    // Defines the columns
032    public static final int ID_COLUMN = 0;
033    public static final int NAME_COLUMN = ID_COLUMN + 1;
034    public static final int COMMENT_COLUMN = NAME_COLUMN + 1;
035    public static final int DEPARTS_COLUMN = COMMENT_COLUMN + 1;
036    public static final int TIME_COLUMN = DEPARTS_COLUMN + 1;
037    public static final int MIN_LENGTH_COLUMN = TIME_COLUMN + 1;
038    public static final int MAX_LENGTH_COLUMN = MIN_LENGTH_COLUMN + 1;
039    public static final int STATUS_COLUMN = MAX_LENGTH_COLUMN + 1;
040    public static final int EDIT_COLUMN = STATUS_COLUMN + 1;
041
042    private static final int HIGHESTCOLUMN = EDIT_COLUMN + 1;
043
044    public RoutesTableModel() {
045        super();
046        Setup.getDefault().addPropertyChangeListener(this);
047        routemanager = InstanceManager.getDefault(RouteManager.class);
048        routemanager.addPropertyChangeListener(this);
049        InstanceManager.getDefault(LocationManager.class).addPropertyChangeListener(this);
050        updateList();
051    }
052
053    public final int SORTBYNAME = 1;
054    public final int SORTBYID = 2;
055
056    private int _sort = SORTBYNAME;
057
058    public void setSort(int sort) {
059        _sort = sort;
060        updateList();
061        fireTableDataChanged();
062    }
063
064    private void updateList() {
065        // first, remove listeners from the individual objects
066        removePropertyChangeRoutes();
067
068        if (_sort == SORTBYID) {
069            sysList = routemanager.getRoutesByIdList();
070        } else {
071            sysList = routemanager.getRoutesByNameList();
072        }
073        // and add them back in
074        for (Route route : sysList) {
075            route.addPropertyChangeListener(this);
076        }
077    }
078
079    List<Route> sysList = null;
080
081    void initTable(RoutesTableFrame frame, JTable table) {
082        // Install the button handlers
083        TableColumnModel tcm = table.getColumnModel();
084        ButtonRenderer buttonRenderer = new ButtonRenderer();
085        TableCellEditor buttonEditor = new ButtonEditor(new javax.swing.JButton());
086        tcm.getColumn(EDIT_COLUMN).setCellRenderer(buttonRenderer);
087        tcm.getColumn(EDIT_COLUMN).setCellEditor(buttonEditor);
088
089        // set column preferred widths
090        table.getColumnModel().getColumn(ID_COLUMN).setPreferredWidth(30);
091        table.getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(220);
092        table.getColumnModel().getColumn(COMMENT_COLUMN).setPreferredWidth(380);
093        table.getColumnModel().getColumn(STATUS_COLUMN).setPreferredWidth(70);
094        table.getColumnModel().getColumn(DEPARTS_COLUMN).setPreferredWidth(75);
095        table.getColumnModel().getColumn(TIME_COLUMN).setPreferredWidth(60);
096        table.getColumnModel().getColumn(MIN_LENGTH_COLUMN).setPreferredWidth(75);
097        table.getColumnModel().getColumn(MAX_LENGTH_COLUMN).setPreferredWidth(75);
098        table.getColumnModel().getColumn(EDIT_COLUMN).setPreferredWidth(80);
099
100        frame.loadTableDetails(table);
101    }
102
103    @Override
104    public int getRowCount() {
105        return sysList.size();
106    }
107
108    @Override
109    public int getColumnCount() {
110        return HIGHESTCOLUMN;
111    }
112
113    @Override
114    public String getColumnName(int col) {
115        switch (col) {
116            case ID_COLUMN:
117                return Bundle.getMessage("Id");
118            case NAME_COLUMN:
119                return Bundle.getMessage("Name");
120            case COMMENT_COLUMN:
121                return Bundle.getMessage("Comment");
122            case DEPARTS_COLUMN:
123                return Bundle.getMessage("DepartsDirection");
124            case TIME_COLUMN:
125                return Bundle.getMessage("Time");
126            case MIN_LENGTH_COLUMN:
127                return Bundle.getMessage("MinLength");
128            case MAX_LENGTH_COLUMN:
129                return Bundle.getMessage("MaxLength");
130            case STATUS_COLUMN:
131                return Bundle.getMessage("Status");
132            case EDIT_COLUMN:
133                return Bundle.getMessage("ButtonEdit"); // titles above all columns
134            default:
135                return "unknown"; // NOI18N
136        }
137    }
138
139    @Override
140    public Class<?> getColumnClass(int col) {
141        switch (col) {
142            case NAME_COLUMN:
143            case COMMENT_COLUMN:
144            case DEPARTS_COLUMN:
145            case TIME_COLUMN:
146            case STATUS_COLUMN:
147                return String.class;
148            case ID_COLUMN:
149            case MIN_LENGTH_COLUMN:
150            case MAX_LENGTH_COLUMN:
151                return Integer.class;
152            case EDIT_COLUMN:
153                return JButton.class;
154            default:
155                return null;
156        }
157    }
158
159    @Override
160    public boolean isCellEditable(int row, int col) {
161        switch (col) {
162            case EDIT_COLUMN:
163                return true;
164            default:
165                return false;
166        }
167    }
168
169    @Override
170    public Object getValueAt(int row, int col) {
171        if (row >= getRowCount()) {
172            return "ERROR unknown " + row; // NOI18N
173        }
174        Route route = sysList.get(row);
175        if (route == null) {
176            return "ERROR route unknown " + row; // NOI18N
177        }
178        switch (col) {
179            case ID_COLUMN:
180                return Integer.parseInt(route.getId());
181            case NAME_COLUMN:
182                return route.getName();
183            case COMMENT_COLUMN:
184                return route.getComment();
185            case DEPARTS_COLUMN:
186                return route.getDepartureDirection();
187            case TIME_COLUMN:
188                return getTime(route);
189            case MIN_LENGTH_COLUMN:
190                return route.getRouteMinimumTrainLength();
191            case MAX_LENGTH_COLUMN:
192                return route.getRouteMaximumTrainLength();
193            case STATUS_COLUMN:
194                return route.getStatus();
195            case EDIT_COLUMN:
196                return Bundle.getMessage("ButtonEdit");
197            default:
198                return "unknown " + col; // NOI18N
199        }
200    }
201
202    @Override
203    public void setValueAt(Object value, int row, int col) {
204        switch (col) {
205            case EDIT_COLUMN:
206                editRoute(row);
207                break;
208            default:
209                break;
210        }
211    }
212    
213    private String getTime(Route route) {
214        if (!route.getDepartsRouteLocation().getDepartureTimeHourMinutes().equals(RouteLocation.NONE)) {
215            return route.getDepartsRouteLocation().getFormatedDepartureTime(); 
216        }
217        // check to see if there's a departure time anywhere in the route
218        for (RouteLocation rl : route.getLocationsBySequenceList()) {
219            if (!rl.getDepartureTimeHourMinutes().equals(RouteLocation.NONE)) {
220                return Bundle.getMessage("ButtonYes");
221            }
222        }
223        return "";
224    }
225
226    RouteEditFrame ref = null;
227    protected static final String NEW_LINE = "\n"; // NOI18N
228
229    private void editRoute(int row) {
230        log.debug("Edit route");
231        if (ref != null) {
232            ref.dispose();
233        }
234        Route route = sysList.get(row);
235        if (route != null && route.getStatus().equals(Route.TRAIN_BUILT)) {
236            // list the built trains for this route
237            StringBuffer buf = new StringBuffer(Bundle.getMessage("DoNotModifyRoute"));
238            for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByIdList()) {
239                if (train.getRoute() == route && train.isBuilt()) {
240                    buf.append(NEW_LINE +
241                            Bundle.getMessage("TrainIsBuilt",
242                                    train.getName(), route.getName()));
243                }
244            }
245            JmriJOptionPane.showMessageDialog(null, buf.toString(), Bundle.getMessage("TrainBuilt"),
246                    JmriJOptionPane.WARNING_MESSAGE);
247        }
248        // use invokeLater so new window appears on top
249        SwingUtilities.invokeLater(() -> {
250                ref = new RouteEditFrame();
251                ref.initComponents(sysList.get(row));
252        });
253    }
254
255    @Override
256    public void propertyChange(PropertyChangeEvent e) {
257        if (Control.SHOW_PROPERTY) {
258            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
259                    .getNewValue());
260        }
261        if (e.getPropertyName().equals(LocationManager.LISTLENGTH_CHANGED_PROPERTY) ||
262                e.getPropertyName().equals(Setup.TRAIN_DIRECTION_PROPERTY_CHANGE)) {
263            fireTableDataChanged();
264        } else if (e.getPropertyName().equals(RouteManager.LISTLENGTH_CHANGED_PROPERTY)) {
265            updateList();
266            fireTableDataChanged();
267        } else if (e.getSource().getClass().equals(Route.class)) {
268            Route route = (Route) e.getSource();
269            int row = sysList.indexOf(route);
270            if (Control.SHOW_PROPERTY) {
271                log.debug("Update route table row: {} id: {}", row, route.getId());
272            }
273            if (row >= 0) {
274                fireTableRowsUpdated(row, row);
275            }
276        }
277    }
278
279    private void removePropertyChangeRoutes() {
280        if (sysList != null) {
281            for (Route route : sysList) {
282                route.removePropertyChangeListener(this);
283            }
284        }
285    }
286
287    public void dispose() {
288        if (ref != null) {
289            ref.dispose();
290        }
291        Setup.getDefault().removePropertyChangeListener(this);
292        routemanager.removePropertyChangeListener(this);
293        InstanceManager.getDefault(LocationManager.class).removePropertyChangeListener(this);
294        removePropertyChangeRoutes();
295    }
296
297    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RoutesTableModel.class);
298}