001package jmri.jmrix.can.cbus.eventtable; 002 003import java.util.ArrayList; 004import javax.annotation.Nonnull; 005import jmri.jmrix.can.CanSystemConnectionMemo; 006import jmri.jmrix.can.cbus.CbusNameService; 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010/** 011 * Class to provide access to the EventTableData.xml file. 012 * @author Steve Young Copyright (C) 2019 013 */ 014public class CbusBasicEventTableModel extends javax.swing.table.AbstractTableModel { 015 016 public static final int NODE_COLUMN = 0; 017 public static final int EVENT_COLUMN = 1; 018 public static final int NAME_COLUMN = 2; 019 public static final int NODENAME_COLUMN = 3; 020 public static final int COMMENT_COLUMN = 4; 021 public static final int STATE_COLUMN = 5; 022 023 public static final int TOGGLE_BUTTON_COLUMN = 6; 024 public static final int ON_BUTTON_COLUMN = 7; 025 public static final int OFF_BUTTON_COLUMN = 8; 026 public static final int CANID_COLUMN = 9; 027 public static final int LATEST_TIMESTAMP_COLUMN = 10; 028 public static final int STATUS_REQUEST_BUTTON_COLUMN = 11; 029 030 public static final int SESSION_TOTAL_COLUMN = 12; 031 public static final int SESSION_ON_COLUMN = 13; 032 public static final int SESSION_OFF_COLUMN = 14; 033 public static final int SESSION_IN_COLUMN = 15; 034 public static final int SESSION_OUT_COLUMN = 16; 035 036 public static final int ALL_TOTAL_COLUMN = 17; 037 public static final int ALL_ON_COLUMN = 18; 038 public static final int ALL_OFF_COLUMN = 19; 039 public static final int ALL_IN_COLUMN = 20; 040 public static final int ALL_OUT_COLUMN = 21; 041 042 public static final int DELETE_BUTTON_COLUMN = 22; 043 public static final int STLR_ON_COLUMN = 23; 044 public static final int STLR_OFF_COLUMN = 24; 045 046 public static final int EVENT_DAT_1 = 25; 047 public static final int EVENT_DAT_2 = 26; 048 public static final int EVENT_DAT_3 = 27; 049 050 public static final int MAX_COLUMN = 28; 051 052 protected final CanSystemConnectionMemo _memo; 053 protected ArrayList<CbusTableEvent> _mainArray; 054 public final CbusEventTableAction ta; 055 public static final int[] INITIAL_COLS = new int[]{ 0,1,2,4,5,6,23,24 }; 056 057 // list of Columns which may update on receipt of CanFrame. 058 static final int[] canFrameCols = new int[]{ 059 CANID_COLUMN, LATEST_TIMESTAMP_COLUMN, STATE_COLUMN, TOGGLE_BUTTON_COLUMN, 060 SESSION_TOTAL_COLUMN, SESSION_IN_COLUMN, SESSION_OUT_COLUMN, SESSION_OFF_COLUMN, SESSION_ON_COLUMN, 061 ALL_TOTAL_COLUMN, ALL_ON_COLUMN, ALL_OFF_COLUMN, ALL_IN_COLUMN, ALL_OUT_COLUMN, 062 EVENT_DAT_1, EVENT_DAT_2, EVENT_DAT_3 }; 063 064 public CbusBasicEventTableModel(CanSystemConnectionMemo memo) { 065 this(memo, 1); 066 } 067 068 public CbusBasicEventTableModel(CanSystemConnectionMemo memo, int initialRowSize) { 069 super(); 070 _memo = memo; 071 _mainArray = new ArrayList<>(initialRowSize); 072 ta = new CbusEventTableAction( this); 073 } 074 075 /** 076 * {@inheritDoc} 077 */ 078 @Override 079 public int getColumnCount() { 080 return MAX_COLUMN; 081 } 082 083 /** 084 * {@inheritDoc} 085 */ 086 @Override 087 public int getRowCount() { 088 return _mainArray.size(); 089 } 090 091 /** 092 * {@inheritDoc} 093 */ 094 @Override 095 public Object getValueAt(int row, int col) { 096 switch (col) { 097 case NODE_COLUMN: 098 return _mainArray.get(row).getNn(); 099 case EVENT_COLUMN: 100 return _mainArray.get(row).getEn(); 101 case NAME_COLUMN: 102 return _mainArray.get(row).getName(); 103 case NODENAME_COLUMN: 104 return new CbusNameService(_memo).getNodeName( _mainArray.get(row).getNn() ); 105 case COMMENT_COLUMN: 106 return _mainArray.get(row).getComment(); 107 case STATE_COLUMN: 108 return _mainArray.get(row).getState(); 109 default: 110 return getValueAtPt2(row,col); 111 } 112 } 113 114 private Object getValueAtPt2(int row, int col) { 115 switch (col) { 116 case TOGGLE_BUTTON_COLUMN: // on or off event 1 is on, 0 is off, null unknown 117 if ( _mainArray.get(row).getState()==CbusTableEvent.EvState.OFF ) { 118 return Bundle.getMessage("CbusSendOn"); // NOI18N 119 } else { 120 return Bundle.getMessage("CbusSendOff"); // NOI18N 121 } 122 case ON_BUTTON_COLUMN: 123 return Bundle.getMessage("CbusSendOn"); // NOI18N 124 case OFF_BUTTON_COLUMN: 125 return Bundle.getMessage("CbusSendOff"); 126 case CANID_COLUMN: 127 return _mainArray.get(row).getEventCanId(); 128 case LATEST_TIMESTAMP_COLUMN: 129 return _mainArray.get(row).getDate(); 130 default: 131 return getValueAtPt3(row,col); 132 } 133 } 134 135 private Object getValueAtPt3(int row, int col) { 136 switch (col) { 137 case SESSION_TOTAL_COLUMN: 138 return (_mainArray.get(row).getSessionOnOff(true) + _mainArray.get(row).getSessionOnOff(false) ); 139 case SESSION_ON_COLUMN: 140 return _mainArray.get(row).getSessionOnOff(true); 141 case SESSION_OFF_COLUMN: 142 return _mainArray.get(row).getSessionOnOff(false); 143 case SESSION_IN_COLUMN: 144 return _mainArray.get(row).getSessionInOut(true); 145 case SESSION_OUT_COLUMN: 146 return _mainArray.get(row).getSessionInOut(false); 147 default: 148 return getValueAtPt4(row,col); 149 } 150 } 151 152 private Object getValueAtPt4(int row, int col) { 153 switch (col) { 154 case ALL_TOTAL_COLUMN: 155 return (_mainArray.get(row).getTotalInOut(true) + _mainArray.get(row).getTotalInOut(false) ); 156 case ALL_ON_COLUMN: 157 return _mainArray.get(row).getTotalOnOff(true); 158 case ALL_OFF_COLUMN: 159 return _mainArray.get(row).getTotalOnOff(false); 160 case ALL_IN_COLUMN: 161 return _mainArray.get(row).getTotalInOut(true); 162 case ALL_OUT_COLUMN: 163 return _mainArray.get(row).getTotalInOut(false); 164 default: 165 return getValueAtPt5(row,col); 166 } 167 } 168 169 private Object getValueAtPt5(int row, int col) { 170 switch (col) { 171 case STATE_COLUMN: 172 return _mainArray.get(row).getState(); 173 case STATUS_REQUEST_BUTTON_COLUMN: 174 return Bundle.getMessage("StatusButton"); // NOI18N 175 case DELETE_BUTTON_COLUMN: 176 return Bundle.getMessage("ButtonDelete"); // NOI18N 177 case STLR_ON_COLUMN: 178 return _mainArray.get(row).getBeans(CbusTableEvent.EvState.ON); 179 case STLR_OFF_COLUMN: 180 return _mainArray.get(row).getBeans(CbusTableEvent.EvState.OFF); 181 default: 182 return getValueAtPt6(row,col); 183 } 184 } 185 186 private Object getValueAtPt6(int row, int col) { 187 switch (col) { 188 case EVENT_DAT_1: 189 return _mainArray.get(row).getData(1); 190 case EVENT_DAT_2: 191 return _mainArray.get(row).getData(2); 192 case EVENT_DAT_3: 193 return _mainArray.get(row).getData(3); 194 default: 195 return null; 196 } 197 } 198 199 /** 200 * {@inheritDoc} 201 */ 202 @Override 203 public void setValueAt(Object value, int row, int col) { 204 switch (col) { 205 case NAME_COLUMN: 206 _mainArray.get(row).setName( (String) value ); 207 break; 208 case COMMENT_COLUMN: 209 _mainArray.get(row).setComment( (String) value ); 210 break; 211 case ON_BUTTON_COLUMN: 212 _mainArray.get(row).sendEvent(CbusTableEvent.EvState.ON); 213 break; 214 case OFF_BUTTON_COLUMN: 215 _mainArray.get(row).sendEvent(CbusTableEvent.EvState.OFF); 216 break; 217 default: 218 setValueAt2( value, row, col); 219 } 220 } 221 222 public void setValueAt2(Object value, int row, int col) { 223 switch (col) { 224 case TOGGLE_BUTTON_COLUMN: 225 _mainArray.get(row).sendEvent(CbusTableEvent.EvState.TOGGLE); 226 ta.updateGuiCell(row,col); 227 break; 228 case STATUS_REQUEST_BUTTON_COLUMN: 229 _mainArray.get(row).sendEvent(CbusTableEvent.EvState.REQUEST); 230 break; 231 default: 232 log.error("Invalid Column {}",col); 233 break; 234 } 235 } 236 237 238 239 /** 240 * Provide a new Event and add to Table. 241 * @param nn Node Number 242 * @param en Event Number 243 * @return New or existing table event. 244 */ 245 @Nonnull 246 public CbusTableEvent provideEvent(int nn, int en){ 247 int row = getEventTableRow(nn,en); 248 if (row>-1){ 249 return _mainArray.get(row); 250 } 251 // not existing so creating new 252 CbusTableEvent newtabev = new CbusTableEvent(_memo,nn,en ); 253 _mainArray.add(newtabev); 254 int newRow = _mainArray.size() - 1; 255 _rowIndex.put(eventKey(nn, en), newRow); 256 fireTableRowsInserted(newRow, newRow); 257 return newtabev; 258 } 259 260 /** 261 * Cache of Node + Event to table row, so that every incoming event frame 262 * does not need a linear search of the table. 263 * <p> 264 * An entry is only used after checking that the row still holds that event, 265 * so the cache self-corrects after rows are removed or the table cleared. 266 */ 267 private final java.util.Map<Integer, Integer> _rowIndex = new java.util.concurrent.ConcurrentHashMap<>(); 268 269 private static int eventKey(int node, int event) { 270 return (node << 16) | (event & 0xFFFF); 271 } 272 273 /** 274 * Do Node + Event check, returns -1 if not on table, otherwise the row id 275 * @since 4.13.3 276 * @param event int 277 * @param node int 278 * @return int of row, otherwise -1 279 */ 280 public int getEventTableRow( int node, int event) { 281 int key = eventKey(node, event); 282 Integer cached = _rowIndex.get(key); 283 if (cached != null) { 284 int row = cached; 285 if (row < _mainArray.size() && _mainArray.get(row).matches(node, event)) { 286 return row; 287 } 288 _rowIndex.remove(key); // stale, eg. after a row removal 289 } 290 for (int row = 0; row < _mainArray.size(); row++) { 291 if (_mainArray.get(row).matches(node, event)) { 292 _rowIndex.put(key, row); 293 return row; 294 } 295 } 296 return -1; 297 } 298 299 /** 300 * Get event name for an event in the table 301 * @param event int 302 * @param node int 303 * @return String of event name, empty string if not present. 304 */ 305 @Nonnull 306 public String getEventName( int node, int event ) { 307 int row = getEventTableRow(node,event); 308 if (row > -1 ) { 309 return _mainArray.get(row).getName(); 310 } 311 return ""; 312 } 313 314 /** 315 * Get event String for an event in the table 316 * @param event int 317 * @param node int 318 * @return String of event name, empty string if not present. 319 */ 320 @Nonnull 321 public String getEventString( int node, int event ) { 322 int row = getEventTableRow(node,event); 323 if (row > -1 ) { 324 return _mainArray.get(row).toString(); 325 } 326 return(""); 327 } 328 329 /** 330 * Get the core list containing all table events 331 * @return actual array of events 332 */ 333 @Nonnull 334 public ArrayList<CbusTableEvent> getEvents() { 335 return new ArrayList<>(_mainArray); 336 } 337 338 private static final Logger log = LoggerFactory.getLogger(CbusBasicEventTableModel.class); 339 340}