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