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