001package jmri.jmrix.tams.swing.locodatabase; 002 003import java.util.ArrayList; 004 005import javax.swing.JButton; 006import javax.swing.JLabel; 007import javax.swing.JTable; 008import javax.swing.JTextField; 009import javax.swing.table.TableCellEditor; 010import javax.swing.table.TableColumnModel; 011 012import jmri.jmrix.tams.TamsListener; 013import jmri.jmrix.tams.TamsMessage; 014import jmri.jmrix.tams.TamsReply; 015import jmri.util.swing.JmriMouseEvent; 016import jmri.util.table.ButtonEditor; 017import jmri.util.table.ButtonRenderer; 018 019import org.slf4j.Logger; 020import org.slf4j.LoggerFactory; 021 022/** 023 * Table data model for display the loco database of the Tams MC. 024 * 025 * @author Kevin Dickerson Copyright (C) 2012 026 */ 027public class LocoDataModel extends javax.swing.table.AbstractTableModel implements TamsListener { 028 029 static public final int ADDRCOLUMN = 0; 030 static public final int SPDCOLUMN = 1; 031 static public final int FMTCOLUMN = 2; 032 static public final int NAMECOLUMN = 3; 033 static public final int DELCOLUMN = 4; 034 035 static public final int NUMCOLUMN = 5; 036 037 jmri.jmrix.tams.TamsSystemConnectionMemo memo; 038 039 ArrayList<String[]> locolist = new ArrayList<String[]>(); 040 041 LocoDataModel(int row, int column, jmri.jmrix.tams.TamsSystemConnectionMemo memo) { 042 this.memo = memo; 043 TamsMessage m = new TamsMessage("xLOCDUMP"); 044 memo.getTrafficController().sendTamsMessage(m, this); 045 } 046 047 /** 048 * Returns the number of rows to be displayed. This can vary depending on 049 * whether only active rows are displayed, and whether the system slots 050 * should be displayed. 051 * <p> 052 * This should probably use a local cache instead of counting/searching each 053 * time. 054 */ 055 @Override 056 public int getRowCount() { 057 return locolist.size(); 058 } 059 060 @Override 061 public int getColumnCount() { 062 return NUMCOLUMN; 063 } 064 065 @Override 066 public String getColumnName(int col) { 067 switch (col) { 068 case ADDRCOLUMN: 069 return Bundle.getMessage("ColAddress"); 070 case SPDCOLUMN: 071 return Bundle.getMessage("ColSteps"); 072 case FMTCOLUMN: 073 return Bundle.getMessage("ColFormat"); 074 case NAMECOLUMN: 075 return Bundle.getMessage("ColName"); 076 case DELCOLUMN: 077 return Bundle.getMessage("ColDelete"); // TODO reuse existing key in jmri.NBBundle 078 default: 079 return "unknown"; 080 } 081 } 082 083 @Override 084 public Class<?> getColumnClass(int col) { 085 086 switch (col) { 087 case DELCOLUMN: 088 return JButton.class; 089 default: 090 return String.class; 091 } 092 } 093 094 @Override 095 public boolean isCellEditable(int row, int col) { 096 switch (col) { 097 case DELCOLUMN: 098 return true; 099 default: 100 return false; 101 } 102 } 103 104 @Override 105 public Object getValueAt(int row, int col) { 106 if (locolist.size() == 0) { 107 return null; 108 } 109 String[] loco = locolist.get(row); 110 try { 111 switch (col) { 112 case ADDRCOLUMN: // 113 return loco[0];//Integer.valueOf(s.locoAddr()); 114 case SPDCOLUMN: // 115 return loco[1]; 116 case FMTCOLUMN: // 117 return loco[2]; 118 case NAMECOLUMN: // 119 return loco[3]; 120 case DELCOLUMN: 121 return "delete"; // NOI18N 122 default: 123 log.error("internal state inconsistent with table request for {} {}", row, col); 124 return null; 125 } 126 } catch (RuntimeException ex) { 127 128 } 129 return null; 130 } 131 132 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "DB_DUPLICATE_SWITCH_CLAUSES", 133 justification="better to keep cases in column order rather than to combine") 134 public int getPreferredWidth(int col) { 135 switch (col) { 136 case ADDRCOLUMN: 137 return new JTextField(5).getPreferredSize().width; 138 case SPDCOLUMN: 139 return new JTextField(6).getPreferredSize().width; 140 case FMTCOLUMN: 141 return new JTextField(6).getPreferredSize().width; 142 case NAMECOLUMN: 143 return new JTextField(12).getPreferredSize().width; 144 case DELCOLUMN: 145 return new JButton(Bundle.getMessage("DeleteLoco")).getPreferredSize().width; 146 default: 147 return new JLabel(" <unknown> ").getPreferredSize().width; // NOI18N 148 } 149 } 150 151 @Override 152 public void setValueAt(Object value, int row, int col) { 153 if (col == DELCOLUMN) { 154 deleteLoco(row); 155 } 156 } 157 158 //to delete a loco in the MC we have to clear all the locos in the list and add in the ones that we want to keep. 159 void deleteLoco(int row) { 160 locolist.remove(row); 161 TamsMessage m = new TamsMessage("xLOCCLEAR"); 162 memo.getTrafficController().sendTamsMessage(m, this); 163 for (String[] loco : locolist) { 164 m = new TamsMessage("xLOCADD " + loco[0] + ", " + loco[1] + ", " + loco[2] + ", '" + loco[3] + "'"); 165 memo.getTrafficController().sendTamsMessage(m, this); 166 } 167 m = new TamsMessage("xLOCDUMP"); 168 memo.getTrafficController().sendTamsMessage(m, this); 169 } 170 171 /** 172 * Configure a table to have our standard rows and columns. This is 173 * optional, in that other table formats can use this table model. But we 174 * put it here to help keep it consistent. 175 * 176 * @param slotTable the table to configure 177 */ 178 public void configureTable(JTable slotTable) { 179 // allow reordering of the columns 180 slotTable.getTableHeader().setReorderingAllowed(true); 181 182 // shut off autoResizeMode to get horizontal scroll to work (JavaSwing p 541) 183 slotTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 184 185 // resize columns as requested 186 for (int i = 0; i < slotTable.getColumnCount(); i++) { 187 int width = getPreferredWidth(i); 188 slotTable.getColumnModel().getColumn(i).setPreferredWidth(width); 189 } 190 slotTable.sizeColumnsToFit(-1); 191 192 // install a button renderer & editor in the "DISP" column for freeing a slot 193 setColumnToHoldButton(slotTable, LocoDataModel.DELCOLUMN); 194 195 // install a button renderer & editor in the "ESTOP" column for stopping a loco 196 //setColumnToHoldEStopButton(slotTable, LocoDataModel.ESTOPCOLUMN); 197 } 198 199 void setColumnToHoldButton(JTable slotTable, int column) { 200 TableColumnModel tcm = slotTable.getColumnModel(); 201 // install the button renderers & editors in this column 202 ButtonRenderer buttonRenderer = new ButtonRenderer(); 203 tcm.getColumn(column).setCellRenderer(buttonRenderer); 204 TableCellEditor buttonEditor = new ButtonEditor(new JButton()); 205 tcm.getColumn(column).setCellEditor(buttonEditor); 206 // ensure the table rows, columns have enough room for buttons 207 slotTable.setRowHeight(new JButton(" " + getValueAt(1, column)).getPreferredSize().height); 208 slotTable.getColumnModel().getColumn(column) 209 .setPreferredWidth(new JButton(" " + getValueAt(1, column)).getPreferredSize().width); 210 } 211 212 void setColumnToHoldEStopButton(JTable slotTable, int column) { 213 TableColumnModel tcm = slotTable.getColumnModel(); 214 // install the button renderers & editors in this column 215 ButtonRenderer buttonRenderer = new ButtonRenderer(); 216 tcm.getColumn(column).setCellRenderer(buttonRenderer); 217 TableCellEditor buttonEditor = new ButtonEditor(new JButton()) { 218 @Override 219 public void mousePressed(JmriMouseEvent e) { 220 stopCellEditing(); 221 } 222 }; 223 tcm.getColumn(column).setCellEditor(buttonEditor); 224 // ensure the table rows, columns have enough room for buttons 225 slotTable.setRowHeight(new JButton(" " + getValueAt(1, column)).getPreferredSize().height); 226 slotTable.getColumnModel().getColumn(column) 227 .setPreferredWidth(new JButton(" " + getValueAt(1, column)).getPreferredSize().width); 228 } 229 230 public void dispose() { 231 232 } 233 234 @Override 235 public void message(TamsMessage m) { 236 237 } 238 239 @Override 240 public void reply(TamsReply r) { 241 if (r != null) { 242 if (r.match("xLOCADD") >= 0) { 243 //loco added so will request a fresh update 244 TamsMessage m = new TamsMessage("xLOCDUMP"); 245 memo.getTrafficController().sendTamsMessage(m, this); 246 } else { 247 locolist = new ArrayList<>(); 248 String msg = r.toString(); 249 String[] rawlocolist = msg.split("\\r"); 250 log.info("Raw loco list length: {}", rawlocolist.length); 251 for (String loco : rawlocolist) { 252 log.info("Loco: {}", loco ); 253 if (!loco.equals("*END*")) { 254 String[] locodetails = loco.split(","); 255 locolist.add(locodetails); 256 } else { 257 break; 258 } 259 } 260 fireTableDataChanged(); 261 } 262 } 263 } 264 265 protected void addLoco(TamsMessage m) { 266 memo.getTrafficController().sendTamsMessage(m, this); 267 } 268 269 private final static Logger log = LoggerFactory.getLogger(LocoDataModel.class); 270 271}