001package jmri.jmrix.can.cbus.node; 002 003import java.io.File; 004import java.util.ArrayList; 005 006import javax.annotation.Nonnull; 007import javax.swing.*; 008 009import jmri.GlobalProgrammerManager; 010import jmri.InstanceManager; 011import jmri.jmrit.decoderdefn.DecoderFile; 012import jmri.jmrit.decoderdefn.DecoderIndexFile; 013import jmri.jmrit.roster.RosterEntry; 014import jmri.jmrit.roster.Roster; 015import jmri.jmrit.symbolicprog.tabbedframe.PaneServiceProgFrame; 016import jmri.jmrix.can.CanSystemConnectionMemo; 017import jmri.jmrix.can.cbus.*; 018import jmri.util.ThreadingUtil; 019import jmri.util.swing.JmriJOptionPane; 020 021/** 022 * Table data model for display of CBUS Nodes 023 * 024 * @author Steve Young (c) 2019 025 * 026 */ 027public class CbusBasicNodeTable extends javax.swing.table.AbstractTableModel { 028 029 protected ArrayList<CbusNode> _mainArray; 030 protected final CanSystemConnectionMemo _memo; 031 protected CbusDccProgrammerManager progMan; 032 033 // column order needs to match list in column tooltips 034 public static final int NODE_NUMBER_COLUMN = 0; 035 public static final int NODE_TYPE_NAME_COLUMN = 1; 036 public static final int NODE_USER_NAME_COLUMN = 2; 037 public static final int NODE_RESYNC_BUTTON_COLUMN = 3; 038 public static final int NODE_EDIT_BUTTON_COLUMN = 4; 039 public static final int COMMAND_STAT_NUMBER_COLUMN = 5; 040 public static final int CANID_COLUMN = 6; 041 public static final int NODE_EVENTS_COLUMN = 7; 042 public static final int BYTES_REMAINING_COLUMN = 8; 043 public static final int NODE_TOTAL_BYTES_COLUMN = 9; 044 public static final int NODE_IN_LEARN_MODE_COLUMN = 10; 045 public static final int NODE_EVENT_INDEX_VALID_COLUMN = 11; 046 public static final int SESSION_BACKUP_STATUS_COLUMN = 12; 047 public static final int NUMBER_BACKUPS_COLUMN = 13; 048 public static final int LAST_BACKUP_COLUMN = 14; 049 public static final int MAX_COLUMN = 15; 050 051 public CbusBasicNodeTable(@Nonnull CanSystemConnectionMemo memo, int row, int column) { 052 _mainArray = new ArrayList<>(); 053 _memo = memo; 054 var cfgMan = memo.get(CbusConfigurationManager.class); 055 if ( cfgMan != null ) { 056 progMan = cfgMan.get(GlobalProgrammerManager.class); 057 if ( progMan == null ) { 058 log.info("No Global Programmer available for NV programming"); 059 } 060 } else { 061 log.info("No CbusConfigurationManager available for NV programming"); 062 } 063 } 064 065 /** 066 * {@inheritDoc} 067 */ 068 @Override 069 public int getRowCount() { 070 if ( _mainArray == null ) { 071 log.error("Node Table Array _mainArray not initialised"); 072 return 0; 073 } 074 else { 075 return _mainArray.size(); 076 } 077 } 078 079 /** 080 * {@inheritDoc} 081 */ 082 @Override 083 public int getColumnCount() { 084 return MAX_COLUMN; 085 } 086 087 /** 088 * {@inheritDoc} 089 */ 090 @Override 091 public String getColumnName(int col) { // not in any order 092 switch (col) { 093 case CANID_COLUMN: 094 return Bundle.getMessage("CanID"); 095 case NODE_NUMBER_COLUMN: 096 return Bundle.getMessage("NodeNumberCol"); 097 case NODE_USER_NAME_COLUMN: 098 return Bundle.getMessage("UserName"); 099 case NODE_RESYNC_BUTTON_COLUMN: 100 return Bundle.getMessage("ReSynchronizeButton"); 101 case NODE_EDIT_BUTTON_COLUMN: 102 return Bundle.getMessage("EditButton"); 103 case NODE_TYPE_NAME_COLUMN: 104 return Bundle.getMessage("ColumnType"); 105 case COMMAND_STAT_NUMBER_COLUMN: 106 return Bundle.getMessage("CommandStationNumber"); 107 case NODE_EVENTS_COLUMN: 108 return Bundle.getMessage("CbusEvents"); 109 case NODE_TOTAL_BYTES_COLUMN: 110 return Bundle.getMessage("TotalBytes"); 111 case BYTES_REMAINING_COLUMN: 112 return Bundle.getMessage("FetchProgress"); 113 case NODE_IN_LEARN_MODE_COLUMN: 114 return Bundle.getMessage("LearnMode"); 115 case NODE_EVENT_INDEX_VALID_COLUMN: 116 return Bundle.getMessage("EventIndexValid"); 117 case SESSION_BACKUP_STATUS_COLUMN: 118 return("Backup Status"); 119 case NUMBER_BACKUPS_COLUMN: 120 return("Num. Backups"); 121 case LAST_BACKUP_COLUMN: 122 return("Last Backup"); 123 default: 124 return "unknown " + col; // NOI18N 125 } 126 } 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override 132 public Class<?> getColumnClass(int col) { 133 if (_mainArray.isEmpty() || getValueAt(0, col)==null) { 134 return Object.class; 135 } 136 return getValueAt(0, col).getClass(); 137 } 138 139 /** 140 * {@inheritDoc} 141 * @return UserName and Resync Button columns true, else false 142 */ 143 @Override 144 public boolean isCellEditable(int row, int col) { 145 return (col == NODE_USER_NAME_COLUMN || col == NODE_RESYNC_BUTTON_COLUMN 146 || col == NODE_EDIT_BUTTON_COLUMN); 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override 153 public Object getValueAt(int row, int col) { 154 switch (col) { 155 case NODE_NUMBER_COLUMN: 156 return _mainArray.get(row).getNodeNumber(); 157 case NODE_USER_NAME_COLUMN: 158 return _mainArray.get(row).getUserName(); 159 case NODE_TYPE_NAME_COLUMN: 160 return _mainArray.get(row).getNodeStats().getNodeTypeName(); 161 case CANID_COLUMN: 162 return _mainArray.get(row).getNodeCanId(); 163 case COMMAND_STAT_NUMBER_COLUMN: 164 return _mainArray.get(row).getCsNum(); 165 case NODE_EVENTS_COLUMN: 166 return _mainArray.get(row).getNodeEventManager().getTotalNodeEvents(); 167 case NODE_TOTAL_BYTES_COLUMN: 168 return _mainArray.get(row).getNodeStats().totalNodeBytes(); 169 case BYTES_REMAINING_COLUMN: 170 return _mainArray.get(row).getNodeStats().floatPercentageRemaining(); 171 case NODE_IN_LEARN_MODE_COLUMN: 172 return _mainArray.get(row).getNodeInLearnMode(); 173 case NODE_RESYNC_BUTTON_COLUMN: 174 return ("Re-Sync"); 175 case NODE_EDIT_BUTTON_COLUMN: 176 return ("Edit"); 177 case NODE_EVENT_INDEX_VALID_COLUMN: 178 return _mainArray.get(row).getNodeEventManager().isEventIndexValid(); 179 case SESSION_BACKUP_STATUS_COLUMN: 180 return _mainArray.get(row).getNodeBackupManager().getSessionBackupStatus(); 181 case NUMBER_BACKUPS_COLUMN: 182 return _mainArray.get(row).getNodeBackupManager().getNumCompleteBackups(); 183 case LAST_BACKUP_COLUMN: 184 return _mainArray.get(row).getNodeBackupManager().getLastBackupTime(); 185 default: 186 return null; 187 } 188 } 189 190 /** 191 * {@inheritDoc} 192 */ 193 @Override 194 public void setValueAt(Object value, int row, int col) { 195 switch (col) { 196 case NODE_USER_NAME_COLUMN: 197 _mainArray.get(row).setUserName( (String) value ); 198 ThreadingUtil.runOnGUI( () -> fireTableCellUpdated(row, col) ); 199 break; 200 case NODE_RESYNC_BUTTON_COLUMN: 201 _mainArray.get(row).saveForResync(); 202 _mainArray.get(row).resetNodeAll(); 203 if (this instanceof CbusNodeTableDataModel) { 204 ((CbusNodeTableDataModel)this).setUrgentNode( _mainArray.get(row).getNodeNumber() ); 205 ((CbusNodeTableDataModel)this).startBackgroundFetch(); 206 } 207 break; 208 case NODE_EDIT_BUTTON_COLUMN: 209 // Try to load a local xml file 210 String title = _mainArray.get(row).getName() + " (CBUS)"; 211 DecoderFile decoderFile = InstanceManager.getDefault(DecoderIndexFile.class).fileFromTitle(title); 212 String userName = _mainArray.get(row).getUserName(); 213 String nodeNumber = "CBUS_Node_" + Integer.toString(_mainArray.get(row).getNodeNumber()); 214 if (!userName.equals("")) { 215 nodeNumber = nodeNumber.concat("_" + userName); 216 } 217 if ((decoderFile != null) && (progMan != null)) { 218 log.debug("decoder file: {}", decoderFile.getFileName()); // NOI18N 219 // Look for an existing roster entry 220 RosterEntry re = Roster.getDefault().getEntryForId(nodeNumber); 221 if (re == null) { 222 // Or create one 223 re = new RosterEntry(new RosterEntry(), nodeNumber); 224 re.setDecoderFamily("CBUS"); 225 re.setMfg(decoderFile.getMfg()); 226 re.setDecoderModel(decoderFile.getModel()); 227 re.setRoadNumber(Integer.toString(_mainArray.get(row).getNodeNumber())); 228 re.setRoadName(userName); 229 } 230 String progTitle = "CBUS NV Programmer"; 231 String progFile = "programmers" + File.separator + "Cbus" + ".xml"; 232 JFrame p = new PaneServiceProgFrame( 233 decoderFile, re, progTitle, progFile, progMan.getGlobalProgrammer()); 234 p.pack(); 235 p.setVisible(true); 236 } else { 237 log.info("No xml, or no programmer found for node {}", title); 238 JmriJOptionPane.showMessageDialog(null, 239 "<html><h3>No programmer or no decoder file</h3><p>Use Node Variables tab</p></html>", 240 "No xml, or no programmer for " + title, JmriJOptionPane.INFORMATION_MESSAGE); 241 } 242 break; 243 default: 244 log.debug("invalid column"); 245 break; 246 } 247 } 248 249 /** 250 * String array of Column Tool tips. 251 * Order needs to match column list. 252 */ 253 public static final String[] COLUMNTOOLTIPS = { 254 null, 255 null, 256 null, 257 null, 258 "Edit Node Variables", 259 null, 260 null, 261 null, 262 null, 263 null, 264 null, 265 "Index invalid when an event addition or deletion has taken place since last fetch.", 266 "Session Backup Status", 267 "Total backups in xml file", 268 null 269 270 }; // Length = number of items in array should (at least) match number of columns 271 272 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusBasicNodeTable.class); 273 274}