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