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