001package jmri.jmrix.pricom.pockettester; 002 003import java.util.Vector; 004import javax.swing.JButton; 005import javax.swing.JLabel; 006import javax.swing.JTable; 007import javax.swing.JTextField; 008import javax.swing.table.TableCellEditor; 009import javax.swing.table.TableColumnModel; 010import jmri.util.table.ButtonEditor; 011import jmri.util.table.ButtonRenderer; 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015/** 016 * Table data model for display of DCC packet contents 017 * 018 * @author Bob Jacobsen Copyright (C) 2005 019 */ 020public class PacketDataModel extends javax.swing.table.AbstractTableModel { 021 022 static public final int ADDRESSCOLUMN = 0; 023 static public final int TYPECOLUMN = 1; 024 static public final int DETAILCOLUMN = 2; 025 static public final int MONITORBUTTONCOLUMN = 3; 026 027 static public final int NUMCOLUMN = 4; 028 029 /** 030 * Returns the number of rows to be displayed. This can vary depending on 031 * what has been seen 032 * @return number of rows 033 */ 034 @Override 035 public int getRowCount() { 036 return keys.size(); 037 } 038 039 @Override 040 public int getColumnCount() { 041 return NUMCOLUMN; 042 } 043 044 @Override 045 public String getColumnName(int col) { 046 switch (col) { 047 case ADDRESSCOLUMN: 048 return Bundle.getMessage("ColumnAddress"); 049 case TYPECOLUMN: 050 return Bundle.getMessage("ColumnType"); 051 case DETAILCOLUMN: 052 return Bundle.getMessage("ColumnDetails"); 053 case MONITORBUTTONCOLUMN: 054 return ""; // no heading, as button is clear 055 default: 056 return "unknown"; 057 } 058 } 059 060 @Override 061 public Class<?> getColumnClass(int col) { 062 switch (col) { 063 case ADDRESSCOLUMN: 064 case TYPECOLUMN: 065 case DETAILCOLUMN: 066 return String.class; 067 case MONITORBUTTONCOLUMN: 068 return JButton.class; 069 default: 070 return null; 071 } 072 } 073 074 @Override 075 public boolean isCellEditable(int row, int col) { 076 switch (col) { 077 case MONITORBUTTONCOLUMN: 078 return true; 079 default: 080 return false; 081 } 082 } 083 084 static final Boolean True = Boolean.valueOf(true); 085 static final Boolean False = Boolean.valueOf(false); 086 087 @Override 088 public Object getValueAt(int row, int col) { 089 090 switch (col) { 091 case ADDRESSCOLUMN: // slot number 092 return addresses.elementAt(row); 093 case TYPECOLUMN: // 094 return types.elementAt(row); 095 case DETAILCOLUMN: // 096 return details.elementAt(row); 097 case MONITORBUTTONCOLUMN: // 098 return Bundle.getMessage("ButtonTrace"); 099 default: 100 log.error("internal state inconsistent with table request for {} {}", row, col); 101 return null; 102 } 103 } 104 105 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "DB_DUPLICATE_SWITCH_CLAUSES", 106 justification="better to keep cases in column order rather than to combine") 107 public int getPreferredWidth(int col) { 108 switch (col) { 109 case ADDRESSCOLUMN: 110 return new JTextField(8).getPreferredSize().width; 111 case TYPECOLUMN: 112 return new JTextField(12).getPreferredSize().width; 113 case DETAILCOLUMN: 114 return new JTextField(12).getPreferredSize().width; 115 case MONITORBUTTONCOLUMN: 116 return new JButton("Details").getPreferredSize().width; 117 default: 118 return new JLabel(" <unknown> ").getPreferredSize().width; 119 } 120 } 121 122 @Override 123 public void setValueAt(Object value, int row, int col) { 124 switch (col) { 125 case MONITORBUTTONCOLUMN: 126 MonitorFrame f = new MonitorFrame(); 127 try { 128 f.initComponents(); 129 f.setFilter((String) getValueAt(row, ADDRESSCOLUMN)); 130 source.addListener(f); 131 } catch (Exception ex) { 132 log.error("starting MonitorFrame caught exception: {}", ex.toString()); 133 } 134 f.setVisible(true); 135 136 return; 137 default: 138 return; 139 } 140 } 141 142 /** 143 * Configure a table to have our standard rows and columns. 144 * This is optional, in that other table formats can use this table model. 145 * But we put it here to help keep it consistent. 146 * 147 * @param slotTable the table to configure. 148 */ 149 public void configureTable(JTable slotTable) { 150 // allow reordering of the columns 151 slotTable.getTableHeader().setReorderingAllowed(true); 152 153 // shut off autoResizeMode to get horizontal scroll to work (JavaSwing p 541) 154 slotTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 155 156 // resize columns as requested 157 for (int i = 0; i < slotTable.getColumnCount(); i++) { 158 int width = getPreferredWidth(i); 159 slotTable.getColumnModel().getColumn(i).setPreferredWidth(width); 160 } 161 slotTable.sizeColumnsToFit(-1); 162 163 // install a button renderer & editor in the "DISP" column for freeing a slot 164 setColumnToHoldButton(slotTable, PacketDataModel.MONITORBUTTONCOLUMN); 165 166 } 167 168 void setColumnToHoldButton(JTable slotTable, int column) { 169 TableColumnModel tcm = slotTable.getColumnModel(); 170 // install the button renderers & editors in this column 171 ButtonRenderer buttonRenderer = new ButtonRenderer(); 172 tcm.getColumn(column).setCellRenderer(buttonRenderer); 173 TableCellEditor buttonEditor = new ButtonEditor(new JButton()); 174 tcm.getColumn(column).setCellEditor(buttonEditor); 175 // ensure the table rows, columns have enough room for buttons 176 slotTable.setRowHeight(new JButton(" " + getValueAt(1, column)).getPreferredSize().height); 177 slotTable.getColumnModel().getColumn(column) 178 .setPreferredWidth(new JButton(" " + getValueAt(1, column)).getPreferredSize().width); 179 } 180 181 public void dispose() { 182 } 183 184 public void asciiFormattedMessage(String m) { 185 String key = getKey(m); 186 if (key == null) { 187 return; // ignore this input 188 } 189 String address = getPrefix(m); 190 String type = getType(m); 191 String detail = getDetails(m); 192 193 // see if exists 194 int index = keys.indexOf(key); 195 196 if (index == -1) { 197 // not present, add 198 keys.addElement(key); 199 addresses.addElement(address); 200 types.addElement(type); 201 details.addElement(detail); 202 203 index = keys.indexOf(key); 204 fireTableRowsInserted(index, index); 205 } else { 206 // index has been set, update 207 keys.setElementAt(key, index); 208 addresses.setElementAt(address, index); 209 types.setElementAt(type, index); 210 details.setElementAt(detail, index); 211 fireTableRowsUpdated(index, index); 212 } 213 } 214 215 DataSource source; 216 217 public void setSource(DataSource d) { 218 source = d; 219 } 220 221 public void reset() { 222 int count = keys.size(); 223 keys = new Vector<String>(); 224 addresses = new Vector<String>(); 225 types = new Vector<String>(); 226 details = new Vector<String>(); 227 fireTableRowsDeleted(0, count - 1); 228 } 229 230 Vector<String> keys = new Vector<String>(); 231 Vector<String> addresses = new Vector<String>(); 232 Vector<String> types = new Vector<String>(); 233 Vector<String> details = new Vector<String>(); 234 235 /** 236 * Find the display key from the current input line. A later input line that 237 * maps to the same key will overwrite the earlier line. 238 * <p> 239 * The current implementation is address+type, so that separate lines will 240 * be used for each type sent to the same address. 241 * 242 * @param s Current line of input 243 * @return null if not to be displayed, e.g. no address 244 */ 245 String getKey(String s) { 246 if (!s.startsWith("ADR=")) { 247 return null; 248 } else { 249 return s.substring(0, 22); 250 } 251 } 252 253 /** 254 * Find the address (1st column) from the current input line 255 * @param s Current line of input 256 * @return address 257 */ 258 String getPrefix(String s) { 259 return s.substring(0, 8); 260 } 261 262 /** 263 * Find the message type (2nd column) from the current input line. Should 264 * not be called if getPrefix has returned null. 265 * 266 * @param s Current line of input 267 * @return null if not to be displayed, e.g. too short 268 */ 269 String getType(String s) { 270 return s.substring(9, 22); 271 } 272 273 /** 274 * Find the message arguments (3rd column) from the current input line. 275 * Should not be called if getPrefix has returned null. 276 * 277 * @param s Current line of input 278 * @return null if not to be displayed, e.g. too short 279 */ 280 String getDetails(String s) { 281 return s.substring(23, s.length() - 1); 282 } 283 284 private final static Logger log = LoggerFactory.getLogger(PacketDataModel.class); 285 286}