001package jmri.jmrit.operations.routes.tools; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.util.ArrayList; 006import java.util.List; 007 008import javax.swing.JButton; 009import javax.swing.JComboBox; 010import javax.swing.JTable; 011import javax.swing.table.TableCellEditor; 012 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016import jmri.jmrit.operations.routes.Route; 017import jmri.jmrit.operations.routes.RouteLocation; 018import jmri.jmrit.operations.setup.Control; 019import jmri.util.swing.XTableColumnModel; 020import jmri.util.table.ButtonEditor; 021import jmri.util.table.ButtonRenderer; 022 023/** 024 * Table Model for edit of route blocking used by operations 025 * 026 * @author Daniel Boudreau Copyright (C) 2021 027 */ 028public class RouteBlockingOrderEditTableModel extends javax.swing.table.AbstractTableModel implements PropertyChangeListener { 029 030 // Defines the columns 031 private static final int ID_COLUMN = 0; 032 private static final int NAME_COLUMN = ID_COLUMN + 1; 033 private static final int TRAIN_DIRECTION_COLUMN = NAME_COLUMN + 1; 034 private static final int UP_COLUMN = TRAIN_DIRECTION_COLUMN + 1; 035 private static final int DOWN_COLUMN = UP_COLUMN + 1; 036 037 private static final int HIGHEST_COLUMN = DOWN_COLUMN + 1; 038 039 private JTable _table; 040 private Route _route; 041 private RouteBlockingOrderEditFrame _frame; 042 List<RouteLocation> _blockingOrderList = new ArrayList<>(); 043 044 public RouteBlockingOrderEditTableModel() { 045 super(); 046 } 047 048 private void updateList() { 049 if (_route == null) { 050 return; 051 } 052 // first, remove listeners from the individual objects 053 removePropertyChangeRouteLocations(); 054 _blockingOrderList = _route.getBlockingOrder(); 055 // and add them back in 056 for (RouteLocation rl : _blockingOrderList) { 057 rl.addPropertyChangeListener(this); 058 } 059 } 060 061 protected void initTable(RouteBlockingOrderEditFrame frame, JTable table, Route route) { 062 _frame = frame; 063 _table = table; 064 _route = route; 065 if (_route != null) { 066 _route.addPropertyChangeListener(this); 067 } 068 initTable(table); 069 } 070 071 private void initTable(JTable table) { 072 // Use XTableColumnModel so we can control which columns are visible 073 XTableColumnModel tcm = new XTableColumnModel(); 074 _table.setColumnModel(tcm); 075 _table.createDefaultColumnsFromModel(); 076 // Install the button handlers 077 ButtonRenderer buttonRenderer = new ButtonRenderer(); 078 TableCellEditor buttonEditor = new ButtonEditor(new javax.swing.JButton()); 079 tcm.getColumn(UP_COLUMN).setCellRenderer(buttonRenderer); 080 tcm.getColumn(UP_COLUMN).setCellEditor(buttonEditor); 081 tcm.getColumn(DOWN_COLUMN).setCellRenderer(buttonRenderer); 082 tcm.getColumn(DOWN_COLUMN).setCellEditor(buttonEditor); 083 table.setDefaultRenderer(JComboBox.class, new jmri.jmrit.symbolicprog.ValueRenderer()); 084 table.setDefaultEditor(JComboBox.class, new jmri.jmrit.symbolicprog.ValueEditor()); 085 086 // set column preferred widths 087 table.getColumnModel().getColumn(ID_COLUMN).setPreferredWidth(40); 088 table.getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(150); 089 table.getColumnModel().getColumn(TRAIN_DIRECTION_COLUMN).setPreferredWidth(95); 090 table.getColumnModel().getColumn(UP_COLUMN).setPreferredWidth(60); 091 table.getColumnModel().getColumn(DOWN_COLUMN).setPreferredWidth(70); 092 093 _frame.loadTableDetails(table); 094 // does not use a table sorter 095 table.setRowSorter(null); 096 097 updateList(); 098 } 099 100 @Override 101 public int getRowCount() { 102 return _blockingOrderList.size(); 103 } 104 105 @Override 106 public int getColumnCount() { 107 return HIGHEST_COLUMN; 108 } 109 110 @Override 111 public String getColumnName(int col) { 112 switch (col) { 113 case ID_COLUMN: 114 return Bundle.getMessage("Id"); 115 case NAME_COLUMN: 116 return Bundle.getMessage("Location"); 117 case TRAIN_DIRECTION_COLUMN: 118 return Bundle.getMessage("TrainDirection"); 119 case UP_COLUMN: 120 return Bundle.getMessage("Up"); 121 case DOWN_COLUMN: 122 return Bundle.getMessage("Down"); 123 default: 124 return "unknown"; // NOI18N 125 } 126 } 127 128 @Override 129 public Class<?> getColumnClass(int col) { 130 switch (col) { 131 case ID_COLUMN: 132 case NAME_COLUMN: 133 case TRAIN_DIRECTION_COLUMN: 134 return String.class; 135 case UP_COLUMN: 136 case DOWN_COLUMN: 137 return JButton.class; 138 default: 139 return null; 140 } 141 } 142 143 @Override 144 public boolean isCellEditable(int row, int col) { 145 switch (col) { 146 case UP_COLUMN: 147 case DOWN_COLUMN: 148 return true; 149 default: 150 return false; 151 } 152 } 153 154 @Override 155 public Object getValueAt(int row, int col) { 156 if (row >= getRowCount()) { 157 return "ERROR unknown " + row; // NOI18N 158 } 159 RouteLocation rl = _blockingOrderList.get(row); 160 if (rl == null) { 161 return "ERROR unknown route location " + row; // NOI18N 162 } 163 switch (col) { 164 case ID_COLUMN: 165 return rl.getId(); 166 case NAME_COLUMN: 167 return rl.getName(); 168 case TRAIN_DIRECTION_COLUMN: { 169 return rl.getTrainDirectionString(); 170 } 171 case UP_COLUMN: 172 return Bundle.getMessage("Up"); 173 case DOWN_COLUMN: 174 return Bundle.getMessage("Down"); 175 default: 176 return "unknown " + col; // NOI18N 177 } 178 } 179 180 @Override 181 public void setValueAt(Object value, int row, int col) { 182 if (value == null) { 183 log.debug("Warning route table row {} still in edit", row); 184 return; 185 } 186 RouteLocation rl = _blockingOrderList.get(row); 187 if (rl == null) { 188 log.error("ERROR unknown route location for row: {}", row); // NOI18N 189 } 190 switch (col) { 191 case UP_COLUMN: 192 moveUpRouteLocation(rl); 193 break; 194 case DOWN_COLUMN: 195 moveDownRouteLocation(rl); 196 break; 197 default: 198 break; 199 } 200 } 201 202 private void moveUpRouteLocation(RouteLocation rl) { 203 log.debug("move location up"); 204 _route.setBlockingOrderUp(rl); 205 } 206 207 private void moveDownRouteLocation(RouteLocation rl) { 208 log.debug("move location down"); 209 _route.setBlockingOrderDown(rl); 210 } 211 212 // this table listens for changes to a route and it's locations 213 @Override 214 public void propertyChange(PropertyChangeEvent e) { 215 if (Control.SHOW_PROPERTY) { 216 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e 217 .getNewValue()); 218 } 219 if (e.getPropertyName().equals(Route.ROUTE_BLOCKING_CHANGED_PROPERTY)) { 220 updateList(); 221 fireTableDataChanged(); 222 } 223 224 if (e.getSource().getClass().equals(RouteLocation.class)) { 225 RouteLocation rl = (RouteLocation) e.getSource(); 226 int row = _blockingOrderList.indexOf(rl); 227 if (Control.SHOW_PROPERTY) { 228 log.debug("Update route table row: {} id: {}", row, rl.getId()); 229 } 230 if (row >= 0) { 231 fireTableRowsUpdated(row, row); 232 } 233 } 234 } 235 236 private void removePropertyChangeRouteLocations() { 237 for (RouteLocation rl : _blockingOrderList) { 238 rl.removePropertyChangeListener(this); 239 } 240 } 241 242 public void dispose() { 243 removePropertyChangeRouteLocations(); 244 if (_route != null) { 245 _route.removePropertyChangeListener(this); 246 } 247 _blockingOrderList.clear(); 248 fireTableDataChanged(); 249 } 250 251 private final static Logger log = LoggerFactory.getLogger(RouteBlockingOrderEditTableModel.class); 252}