001package jmri.jmrix.can.cbus.swing.nodeconfig; 002 003import java.awt.BorderLayout; 004import java.awt.Desktop; 005import java.awt.event.ActionEvent; 006import java.beans.PropertyChangeEvent; 007import java.io.IOException; 008import java.net.URI; 009import java.net.URISyntaxException; 010import javax.swing.JButton; 011import javax.swing.JLabel; 012import javax.swing.JPanel; 013import javax.swing.JScrollPane; 014import javax.swing.JTextArea; 015import jmri.jmrix.can.cbus.node.CbusNode; 016import jmri.jmrix.can.cbus.node.CbusNodeConstants; 017import jmri.jmrix.can.cbus.node.CbusNodeParameterManager; 018 019import org.slf4j.Logger; 020import org.slf4j.LoggerFactory; 021 022/** 023 * 024 * @author Steve Young Copyright (C) 2018 025 */ 026public class CbusNodeInfoPane extends CbusNodeConfigTab { 027 028 private JButton nodesupportlinkbutton; 029 private URI supportlink; 030 private JLabel header; 031 private JPanel menuPane; 032 protected JTextArea textArea; 033 private CbusNodeParameterManager paramMgr; 034 private JScrollPane textAreaPanel; 035 036 private JPanel paneToDisplay; 037 038 /** 039 * Create a new instance of CbusNodeInfoPane. 040 * @param main the NodeConfigToolPane this is a component of 041 */ 042 public CbusNodeInfoPane(NodeConfigToolPane main) { 043 super(main); 044 } 045 046 /** 047 * {@inheritDoc} 048 */ 049 @Override 050 public void propertyChange(PropertyChangeEvent ev){ 051 jmri.util.ThreadingUtil.runOnGUIEventually( ()->{ 052 paramsHaveUpdated(); 053 }); 054 } 055 056 /** 057 * {@inheritDoc} 058 */ 059 @Override 060 public String getTitle(){ 061 return Bundle.getMessage("NodeInfo"); 062 } 063 064 /** 065 * Initialise the pane for a particular CbusNode ( or CbusBackupNode ) 066 * @param node the node to display info for 067 */ 068 @Override 069 public void changedNode(CbusNode node) { 070 if (paneToDisplay==null) { 071 paneToDisplay = newInfoPane(); 072 add(paneToDisplay); 073 } 074 paramMgr = node.getNodeParamManager(); 075 paramsHaveUpdated(); 076 validate(); 077 repaint(); 078 079 } 080 081 private JPanel newInfoPane(){ 082 083 JPanel newPane = new JPanel(); 084 newPane.setLayout(new BorderLayout() ); 085 086 nodesupportlinkbutton = new JButton(""); 087 nodesupportlinkbutton.addActionListener((ActionEvent e) -> { 088 openUri(supportlink); 089 }); 090 091 textArea = new JTextArea(); 092 textArea.setEditable(false); 093 textArea.setMargin( new java.awt.Insets(10,10,10,10) ); 094 textAreaPanel = new JScrollPane(textArea); 095 096 header = new JLabel(""); 097 menuPane = new JPanel(); 098 menuPane.add(header); 099 menuPane.add(nodesupportlinkbutton); 100 101 newPane.add(menuPane, BorderLayout.PAGE_START); 102 newPane.add(textAreaPanel, BorderLayout.CENTER); 103 newPane.validate(); 104 newPane.repaint(); 105 106 return newPane; 107 } 108 109 private void appendIfKnown( StringBuilder sb, int paramToCheck, String label ){ 110 111 // log.info("returning param index {} val {}",paramToCheck,paramMgr.getParameter(paramToCheck)); 112 113 if (paramMgr.getParameter(paramToCheck) > -1) { 114 appendRaw(sb,String.valueOf(paramMgr.getParameter(paramToCheck)),label); 115 } 116 } 117 118 private void appendRaw( StringBuilder sb, Object value, String label ){ 119 sb.append (label).append (" : ").append (value).append(System.getProperty("line.separator")); 120 } 121 122 private void setHeaderText() { 123 StringBuilder buildheader = new StringBuilder(); 124 buildheader.append("<html><h3>"); 125 buildheader.append(CbusNodeConstants.getManu(paramMgr.getParameter(1))); 126 buildheader.append(" "); 127 buildheader.append(nodeOfInterest.getNodeStats().getNodeTypeName()); 128 buildheader.append("</h3></html>"); 129 header.setText(buildheader.toString()); 130 } 131 132 /** 133 * Recalculates pane following notification from CbusNode that parameters have changed 134 */ 135 private void paramsHaveUpdated() { 136 137 updateSupportButton(); 138 139 setHeaderText(); 140 141 StringBuilder textAreaString = new StringBuilder(); 142 143 appendRaw(textAreaString,nodeOfInterest.getNodeNumber(),Bundle.getMessage("NodeNumberTitle")); 144 145 appendNodeTypeInfo(textAreaString); 146 147 appendIfKnown(textAreaString, 6, Bundle.getMessage("NodeVariables")); 148 149 appendIfKnown(textAreaString, 0, "Parameters"); 150 151 if ( nodeOfInterest.getNodeEventManager().getTotalNodeEvents()> -1 ) { 152 appendRaw(textAreaString,nodeOfInterest.getNodeEventManager() 153 .getTotalNodeEvents(), "Current Events"); 154 } 155 156 appendIfKnown(textAreaString, 4, "Max Events"); 157 appendIfKnown(textAreaString, 5, "Max Event Variables per Event"); 158 159 if ((paramMgr.getParameter(0)>9) && (paramMgr.getParameter(10)>0)) { 160 textAreaString.append (CbusNodeConstants.getBusType(paramMgr.getParameter(10))); 161 textAreaString.append (" "); 162 textAreaString.append (Bundle.getMessage("BusType")); 163 textAreaString.append(System.getProperty("line.separator")); 164 } 165 166 appendRaw(textAreaString, Math.max(0,nodeOfInterest.getNodeStats() 167 .totalNodeBytes()), "Current Node Data Bytes"); 168 169 addBackupInfo(textAreaString); 170 171 appendRaw(textAreaString, nodeOfInterest.getsendsWRACKonNVSET(), "Sends WRACK Following NV Set"); 172 173 appendAllParams(textAreaString); 174 175 // nodePartTwobuilder.append ("<p> Is Bootable Y / N</p>"); 176 // nodePartTwobuilder.append ("<p> Processor : </p>"); 177 // nodePartTwobuilder.append ("<p> Flags </p>"); 178 179 if ( !(textArea.getText().equals(textAreaString.toString()) )) { 180 textArea.setText(textAreaString.toString()); 181 textArea.setCaretPosition(0); 182 } 183 } 184 185 private void appendNodeTypeInfo(StringBuilder sb) { 186 187 if (paramMgr.getParameter(1) > -1 && 188 paramMgr.getParameter(3) > -1 ) { 189 190 sb.append(Bundle.getMessage("ManufacturerType", 191 paramMgr.getParameter(1), 192 CbusNodeConstants.getManu(paramMgr.getParameter(1)), 193 paramMgr.getParameter(3))); 194 195 sb.append(System.getProperty("line.separator")); 196 197 } 198 199 if (!nodeOfInterest.getNodeStats().getNodeTypeName().isEmpty()){ 200 sb.append(Bundle.getMessage("IdentifiesAs", 201 nodeOfInterest.getNodeStats().getNodeTypeName(), 202 CbusNodeConstants.getModuleTypeExtra( 203 paramMgr.getParameter(1), 204 paramMgr.getParameter(3))) 205 ); 206 sb.append(System.getProperty("line.separator")); 207 } 208 209 appendFirmware(sb); 210 211 } 212 213 private void appendFirmware(StringBuilder sb) { 214 215 if ((paramMgr.getParameter(2)>0) && 216 (paramMgr.getParameter(7)>0)) { 217 sb.append (Bundle.getMessage("FirmwareVer", 218 paramMgr.getParameter(7), 219 Character.toString((char) paramMgr.getParameter(2)))); 220 221 if ((paramMgr.getParameter(0)>19) && (paramMgr.getParameter(20)>0) ){ 222 sb.append (Bundle.getMessage("FWBeta")); 223 sb.append (paramMgr.getParameter(20)); 224 } 225 sb.append(System.getProperty("line.separator")); 226 } 227 } 228 229 230 private void addBackupInfo(StringBuilder sb) { 231 232 sb.append(System.getProperty("line.separator")); 233 234 appendRaw(sb, nodeOfInterest.getNodeBackupManager() 235 .getBackups().size(), "Entries in Node xml file"); 236 237 appendRaw(sb, nodeOfInterest.getNodeBackupManager() 238 .getNumCompleteBackups(), "Num Backups in Node xml file"); 239 240 if( nodeOfInterest.getNodeBackupManager().getNumCompleteBackups()>0 ) { 241 appendRaw(sb, nodeOfInterest.getNodeBackupManager().getFirstBackupTime(), "First entry"); 242 appendRaw(sb, nodeOfInterest.getNodeBackupManager().getLastBackupTime(), "Last entry"); 243 } 244 } 245 246 private void appendAllParams(StringBuilder sb) { 247 248 if (!paramMgr.getParameterHexString().isEmpty()) { 249 sb.append(System.getProperty("line.separator")); 250 sb.append ("Parameter Hex String : "); 251 sb.append (paramMgr.getParameterHexString()); 252 sb.append(System.getProperty("line.separator")); 253 } 254 255 256 sb.append(System.getProperty("line.separator")); 257 for (int i = 1; i <= paramMgr.getParameter(0); i++) { 258 if ( paramMgr.getParameter(i) > -1 ) { 259 sb.append ("Parameter "); 260 sb.append (i); 261 sb.append (" : "); 262 sb.append ( paramMgr.getParameter(i) ); 263 sb.append (" (dec)"); 264 sb.append(System.getProperty("line.separator")); 265 } 266 } 267 } 268 269 private void updateSupportButton() { 270 271 String supportLinkStr = CbusNodeConstants.getModuleSupportLink(paramMgr.getParameter(1),paramMgr.getParameter(3)); 272 273 if ( !supportLinkStr.isEmpty() ) { 274 nodesupportlinkbutton.setText(supportLinkStr); 275 276 nodesupportlinkbutton.setToolTipText("<html>" + CbusNodeConstants.getManu(paramMgr.getParameter(1)) + 277 " " + CbusNodeConstants.getModuleType(paramMgr.getParameter(1),paramMgr.getParameter(3)) + 278 " " + Bundle.getMessage("Support") + "</html>"); 279 280 try { 281 supportlink=new URI(supportLinkStr); 282 nodesupportlinkbutton.setVisible(true); 283 return; 284 } 285 catch (URISyntaxException ex) { 286 log.warn("Unable to create support link URI for module type {}", paramMgr.getParameter(3), ex); 287 } 288 289 } 290 nodesupportlinkbutton.setVisible(false); 291 292 } 293 294 private static void openUri(URI uri) { 295 if (Desktop.isDesktopSupported()) { 296 try { 297 Desktop.getDesktop().browse(uri); 298 } catch (IOException e) { 299 log.warn("Unable to get URI for {}", uri, e); 300 } 301 } 302 } 303 304 private final static Logger log = LoggerFactory.getLogger(CbusNodeInfoPane.class); 305 306}