001package jmri.jmrix.can.cbus.node; 002 003import java.util.ArrayList; 004import javax.annotation.CheckForNull; 005import javax.annotation.Nonnull; 006import jmri.jmrix.can.CanSystemConnectionMemo; 007import jmri.util.ThreadingUtil; 008 009/** 010 * Table data model for display of CBUS Nodes 011 * 012 * @author Steve Young (c) 2019 013 * 014 */ 015public class CbusBasicNodeTableOperations extends CbusBasicNodeTable { 016 017 public CbusBasicNodeTableOperations(@Nonnull CanSystemConnectionMemo memo, int row, int column) { 018 super(memo,row,column); 019 } 020 021 /** 022 * Register new node to table 023 * @param node The CbusNode to add to the table 024 */ 025 public void addNode(CbusNode node) { 026 _mainArray.add(node); 027 028 if (this instanceof CbusNodeTableDataModel) { 029 node.setTableModel( (CbusNodeTableDataModel)this); 030 node.addPropertyChangeListener((CbusNodeTableDataModel)this); 031 ((CbusNodeTableDataModel) this).startBackgroundFetch(); 032 } 033 if (_mainArray.size()==1){ 034 setRequestNodeDisplay(node.getNodeNumber()); 035 } 036 // notify the JTable object that a row has changed; do that in the Swing thread! 037 fireTableDataChanged(); 038 } 039 040 /** 041 * Returns an existing command station by cs number, NOT node number 042 * @param csnum The Command Station Number ( the default in CBUS is 0 ) 043 * @return the Node which has the command station number, else null 044 */ 045 @CheckForNull 046 public CbusNode getCsByNum(int csnum) { 047 for (int i = 0; i < getRowCount(); i++) { 048 if ( _mainArray.get(i).getCsNum() == csnum ) { 049 return _mainArray.get(i); 050 } 051 } 052 return null; 053 } 054 055 /** 056 * Returns a new or existing command station by cs number, NOT node number 057 * 058 * @param csnum The Command Station Number to provide by 059 * @param nodenum if existing CS sets node num to this, else node with this number and starts param lookup 060 * 061 * @return the Node which has the command station number 062 */ 063 @Nonnull 064 protected CbusNode provideCsByNum(int csnum, int nodenum) { 065 for (int i = 0; i < getRowCount(); i++) { 066 if ( _mainArray.get(i).getCsNum() == csnum ) { 067 _mainArray.get(i).setNodeNumber(nodenum); 068 return _mainArray.get(i); 069 } 070 } 071 CbusNode cs = provideNodeByNodeNum( nodenum); 072 cs.setCsNum(csnum); 073 return cs; 074 } 075 076 /** 077 * Returns a new or existing node by node number 078 * 079 * @param nodenum number to search nodes by, else creates node with this number and starts param lookup 080 * 081 * @return the Node which has the node number 082 */ 083 @Nonnull 084 public CbusNode provideNodeByNodeNum(int nodenum ) { 085 if ( nodenum < 1 || nodenum > 65535 ) { 086 throw new IllegalArgumentException("Node number should be between 1 and 65535"); 087 } 088 for (int i = 0; i < getRowCount(); i++) { 089 if ( _mainArray.get(i).getNodeNumber() == nodenum ) { 090 return _mainArray.get(i); 091 } 092 } 093 CbusNode cs = new CbusNode(_memo, nodenum); 094 addNode(cs); 095 return cs; 096 } 097 098 /** 099 * Returns an existing node by table row number 100 * @param rowNum The Row Number 101 * @return the Node 102 */ 103 public CbusNode getNodeByRowNum(int rowNum) { 104 return _mainArray.get(rowNum); 105 } 106 107 /** 108 * Returns the table row number by node number 109 * @param nodenum The Node Number ( min 1, max 65535 ) 110 * @return the Model Row which has the node number, else -1 111 */ 112 public int getNodeRowFromNodeNum(int nodenum) { 113 for (int i = 0; i < getRowCount(); i++) { 114 if ( _mainArray.get(i).getNodeNumber() == nodenum ) { 115 return i; 116 } 117 } 118 return -1; 119 } 120 121 /** 122 * For a given CAN ID, if in use, return formatted Node Name and number 123 * else returns zero length string 124 * @param canId the CAN ID to search the table for 125 * @return Node Number and name 126 */ 127 public String getNodeNameFromCanId (int canId) { 128 for (int i = 0; i < getRowCount(); i++) { 129 if ( _mainArray.get(i).getNodeCanId() == canId ) { 130 return _mainArray.get(i).getNodeStats().getNodeNumberName(); 131 } 132 } 133 return (""); 134 } 135 136 /** 137 * For a given CAN ID, return the number of nodes with the ID. 138 * The JMRI connection instance CAN ID is also checked. 139 * @param canId the CAN ID to search for. 140 * @return the number of nodes using the CAN ID. 141 */ 142 public int getNumberNodesWithCanId(int canId){ 143 int count = ( canId == _memo.getTrafficController().getCanid() ? 1 : 0); 144 final var list = _mainArray; 145 for (CbusNode node : list) { 146 if ( node.getNodeCanId() == canId ) { 147 count++; 148 } 149 } 150 return count; 151 } 152 153 /** 154 * Returns Node number of any node currently in Learn Mode 155 * @return Node Num, else -1 if no nodes known to be in learn mode 156 */ 157 public int getAnyNodeInLearnMode(){ 158 for (int i = 0; i < getRowCount(); i++) { 159 if ( _mainArray.get(i).getNodeInLearnMode() ) { 160 return _mainArray.get(i).getNodeNumber(); 161 } 162 } 163 return -1; 164 } 165 166 /** 167 * Returns an existing node by node number 168 * @param nodenum The Node Number ( min 1, max 65535 ) 169 * @return the Node which has the node number, else null 170 */ 171 @CheckForNull 172 public CbusNode getNodeByNodeNum( int nodenum ) { 173 for (int i = 0; i < getRowCount(); i++) { 174 if ( _mainArray.get(i).getNodeNumber() == nodenum ) { 175 return _mainArray.get(i); 176 } 177 } 178 return null; 179 } 180 181 /** 182 * Remove Row from table and dispose of it 183 * @param row int row number 184 * @param removeXml true to also remove the Node xml file 185 */ 186 public void removeRow(int row, boolean removeXml) { 187 CbusNode toRemove = getNodeByNodeNum( _mainArray.get(row).getNodeNumber() ); 188 _mainArray.remove(row); 189 if (toRemove != null) { 190 if (this instanceof CbusNodeTableDataModel) { 191 toRemove.removePropertyChangeListener((CbusNodeTableDataModel)this ); 192 } 193 if (removeXml) { 194 // delete xml file 195 if (!(toRemove.getNodeBackupManager().removeNode(true))){ 196 log.error("Unable to delete node xml file"); 197 } 198 } 199 ThreadingUtil.runOnGUI( ()->{ fireTableRowsDeleted(row,row); }); 200 toRemove.dispose(); 201 } 202 } 203 204 /** 205 * Returns the next available Node Number 206 * @param higherthan Node Number 207 * @return calculated next available number, else original value 208 */ 209 public int getNextAvailableNodeNumber( int higherthan ) { 210 if ( getRowCount() > 0 ) { 211 for (int i = 0; i < getRowCount(); i++) { 212 // log.debug("get next available i {} rowcount {}",i,getRowCount() ); 213 if ( _mainArray.get(i).getNodeNumber() < 65534 ) { 214 if ( _mainArray.get(i).getNodeNumber() >= higherthan ) { 215 higherthan = _mainArray.get(i).getNodeNumber() + 1; 216 } 217 } 218 } 219 } 220 return higherthan; 221 } 222 223 /** 224 * Returns a string ArrayList of all Node Number and User Names on the table 225 * @return Node Number + either node model or Username. 226 */ 227 @Nonnull 228 public ArrayList<String> getListOfNodeNumberNames(){ 229 ArrayList<String> list = new ArrayList<>(); 230 for (int i = 0; i < getRowCount(); i++) { 231 list.add( _mainArray.get(i).getNodeStats().getNodeNumberName() ); 232 } 233 return list; 234 } 235 236 /** 237 * Returns formatted Node Number and User Name by node number 238 * @param nodenum The Node Number ( min 1, max 65535 ) 239 * @return Node Number + either node model or Username. 240 */ 241 public String getNodeNumberName( int nodenum ) { 242 for (int i = 0; i < getRowCount(); i++) { 243 if ( _mainArray.get(i).getNodeNumber() == nodenum ) { 244 return _mainArray.get(i).getNodeStats().getNodeNumberName(); 245 } 246 } 247 return (""); 248 } 249 250 /** 251 * Single Node User Name 252 * @param nn Node Number, NOT row number 253 * @return Node Username, if unset returns node type name, else empty String 254 */ 255 @Nonnull 256 public String getNodeName( int nn ) { 257 int rownum = getNodeRowFromNodeNum(nn); 258 if ( rownum < 0 ) { 259 return ""; 260 } 261 if ( !_mainArray.get(rownum).getUserName().isEmpty() ) { 262 return _mainArray.get(rownum).getUserName(); 263 } 264 if ( !_mainArray.get(rownum).getNodeStats().getNodeTypeName().isEmpty() ) { 265 return _mainArray.get(rownum).getNodeStats().getNodeTypeName(); 266 } 267 return ""; 268 } 269 270 private int requestNodeToDisplay = 0; 271 272 public int getRequestNodeRowToDisplay(){ 273 return getNodeRowFromNodeNum(requestNodeToDisplay); 274 } 275 276 public void setRequestNodeDisplay(int nodeNumber){ 277 requestNodeToDisplay = nodeNumber; 278 } 279 280 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusBasicNodeTableOperations.class); 281 282}