001package jmri.jmrit.operations.locations.tools;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005import java.util.ArrayList;
006import java.util.List;
007import javax.swing.JButton;
008import javax.swing.JComboBox;
009import javax.swing.JTable;
010import javax.swing.table.AbstractTableModel;
011import javax.swing.table.TableCellEditor;
012import jmri.jmrit.operations.locations.Location;
013import jmri.jmrit.operations.locations.Track;
014import jmri.jmrit.operations.setup.Control;
015import jmri.util.swing.XTableColumnModel;
016import jmri.util.table.ButtonEditor;
017import jmri.util.table.ButtonRenderer;
018import org.slf4j.Logger;
019import org.slf4j.LoggerFactory;
020
021/**
022 * Table Model for edit of tracks used by operations
023 *
024 * @author Daniel Boudreau Copyright (C) 2015
025 */
026public class LocationTrackBlockingOrderTableModel extends AbstractTableModel implements PropertyChangeListener {
027
028    protected Location _location;
029    protected List<Track> _tracksList = new ArrayList<Track>();
030    protected JTable _table;
031
032    // Defines the columns
033    protected static final int ID_COLUMN = 0;
034    protected static final int NAME_COLUMN = 1;
035    protected static final int TYPE_COLUMN = 2;
036    protected static final int ORDER_COLUMN = 3;
037    protected static final int UP_COLUMN = 4;
038    protected static final int DOWN_COLUMN = 5;
039
040    protected static final int HIGHESTCOLUMN = DOWN_COLUMN + 1;
041
042    public LocationTrackBlockingOrderTableModel() {
043        super();
044    }
045
046    private void updateList() {
047        if (_location == null) {
048            return;
049        }
050        // first, remove listeners from the individual objects
051        removePropertyChangeTracks();
052
053        _tracksList = _location.getTracksByBlockingOrderList(null);
054        // and add them back in
055        for (Track track : _tracksList) {
056            track.addPropertyChangeListener(this);
057        }
058        fireTableDataChanged();
059    }
060
061    protected void initTable(JTable table, Location location) {
062        _table = table;
063        _location = location;
064        if (_location != null) {
065            _location.addPropertyChangeListener(this);
066        }
067        initTable();
068        table.setRowHeight(new JComboBox<>().getPreferredSize().height);
069        // have to shut off autoResizeMode to get horizontal scroll to work (JavaSwing p 541)
070        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
071        updateList();
072    }
073
074    private void initTable() {
075        // Use XTableColumnModel so we can control which columns are visible
076        XTableColumnModel tcm = new XTableColumnModel();
077        _table.setColumnModel(tcm);
078        _table.createDefaultColumnsFromModel();
079
080        ButtonRenderer buttonRenderer = new ButtonRenderer();
081        TableCellEditor buttonEditor = new ButtonEditor(new javax.swing.JButton());
082        tcm.getColumn(UP_COLUMN).setCellRenderer(buttonRenderer);
083        tcm.getColumn(UP_COLUMN).setCellEditor(buttonEditor);
084        tcm.getColumn(DOWN_COLUMN).setCellRenderer(buttonRenderer);
085        tcm.getColumn(DOWN_COLUMN).setCellEditor(buttonEditor);
086
087        // set column preferred widths
088        tcm.getColumn(ID_COLUMN).setPreferredWidth(40);
089        tcm.getColumn(NAME_COLUMN).setPreferredWidth(200);
090        tcm.getColumn(TYPE_COLUMN).setPreferredWidth(80);
091        tcm.getColumn(ORDER_COLUMN).setPreferredWidth(60);
092        tcm.getColumn(UP_COLUMN).setPreferredWidth(60);
093        tcm.getColumn(DOWN_COLUMN).setPreferredWidth(70);
094    }
095
096    @Override
097    public int getRowCount() {
098        return _tracksList.size();
099    }
100
101    @Override
102    public int getColumnCount() {
103        return HIGHESTCOLUMN;
104    }
105
106    @Override
107    public String getColumnName(int col) {
108        switch (col) {
109            case ID_COLUMN:
110                return Bundle.getMessage("Id");
111            case NAME_COLUMN:
112                return Bundle.getMessage("TrackName");
113            case TYPE_COLUMN:
114                return Bundle.getMessage("Type");
115            case ORDER_COLUMN:
116                return Bundle.getMessage("ServiceOrder");
117            case UP_COLUMN:
118                return Bundle.getMessage("Up");
119            case DOWN_COLUMN:
120                return Bundle.getMessage("Down");
121            default:
122                return "unknown"; // NOI18N
123        }
124    }
125
126    @Override
127    public Class<?> getColumnClass(int col) {
128        switch (col) {
129            case ID_COLUMN:
130                return String.class;
131            case NAME_COLUMN:
132                return String.class;
133            case TYPE_COLUMN:
134                return String.class;
135            case ORDER_COLUMN:
136                return Integer.class;
137            case UP_COLUMN:
138                return JButton.class;
139            case DOWN_COLUMN:
140                return JButton.class;
141            default:
142                return null;
143        }
144    }
145
146    @Override
147    public boolean isCellEditable(int row, int col) {
148        switch (col) {
149            case ORDER_COLUMN:
150            case UP_COLUMN:
151            case DOWN_COLUMN:
152                return true;
153            default:
154                return false;
155        }
156    }
157
158    @Override
159    public Object getValueAt(int row, int col) {
160        if (row >= getRowCount()) {
161            return "ERROR row " + row; // NOI18N
162        }
163        Track track = _tracksList.get(row);
164        if (track == null) {
165            return "ERROR track unknown " + row; // NOI18N
166        }
167        switch (col) {
168            case ID_COLUMN:
169                return track.getId();
170            case NAME_COLUMN:
171                return track.getName();
172            case TYPE_COLUMN:
173                return track.getTrackTypeName();
174            case ORDER_COLUMN:
175                return track.getBlockingOrder();
176            case UP_COLUMN:
177                return Bundle.getMessage("Up");
178            case DOWN_COLUMN:
179                return Bundle.getMessage("Down");
180            default:
181                return "unknown " + col; // NOI18N
182        }
183    }
184
185    @Override
186    public void setValueAt(Object value, int row, int col) {
187        if (row >= getRowCount()) {
188            return;
189        }
190        Track track = _tracksList.get(row);
191        if (track == null) {
192            return; // NOI18N
193        }
194        switch (col) {
195            case ORDER_COLUMN:
196                if ((int) value >= 0)
197                    track.setBlockingOrder((int) value);
198                break;
199            case UP_COLUMN:
200                _location.changeTrackBlockingOrderEarlier(track);
201                break;
202            case DOWN_COLUMN:
203                _location.changeTrackBlockingOrderLater(track);
204                break;
205            default:
206                break;
207        }
208    }
209
210    // this table listens for changes to a location and its tracks
211    @Override
212    public void propertyChange(PropertyChangeEvent e) {
213        if (Control.SHOW_PROPERTY)
214            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
215                    .getNewValue());
216        if (e.getPropertyName().equals(Location.TRACK_LISTLENGTH_CHANGED_PROPERTY) ||
217                e.getPropertyName().equals(Location.TRACK_BLOCKING_ORDER_CHANGED_PROPERTY)) {
218            updateList();
219        }
220        if (e.getPropertyName().equals(Track.TRACK_BLOCKING_ORDER_CHANGED_PROPERTY) ||
221                e.getPropertyName().equals(Track.NAME_CHANGED_PROPERTY) ||
222                e.getPropertyName().equals(Track.TRACK_TYPE_CHANGED_PROPERTY)) {
223            fireTableDataChanged();
224        }
225    }
226
227    protected void removePropertyChangeTracks() {
228        for (Track track : _tracksList) {
229            track.removePropertyChangeListener(this);
230        }
231    }
232
233    public void dispose() {
234        removePropertyChangeTracks();
235        if (_location != null) {
236            _location.removePropertyChangeListener(this);
237        }
238        _tracksList.clear();
239        fireTableDataChanged();
240    }
241
242    private final static Logger log = LoggerFactory.getLogger(LocationTrackBlockingOrderTableModel.class);
243}