001package apps.util.issuereporter; 002 003import java.awt.*; 004import java.io.File; 005import java.net.NetworkInterface; 006import java.net.SocketException; 007import java.util.*; 008import java.util.List; 009 010import javax.annotation.Nonnull; 011import javax.swing.filechooser.FileSystemView; 012 013import jmri.*; 014import jmri.configurexml.LoadXmlUserAction; 015import jmri.jmrit.audio.AudioFactory; 016import jmri.jmrit.operations.OperationsXml; 017import jmri.jmrit.roster.Roster; 018import jmri.util.gui.GuiLafPreferencesManager; 019import jmri.jmrix.ConnectionConfigManager; 020import jmri.profile.Profile; 021import jmri.profile.ProfileManager; 022import jmri.util.FileUtil; 023import jmri.util.PortNameMapper; 024import jmri.util.PortNameMapper.SerialPortFriendlyName; 025import jmri.util.node.NodeIdentity; 026import jmri.util.zeroconf.ZeroConfServiceManager; 027 028/** 029 * Provide the JMRI context info. 030 * 031 * @author Bob Jacobsen Copyright (C) 2007, 2009 032 * @author Matt Harris Copyright (C) 2008, 2009 033 */ 034public class SystemInfo { 035 036 private final boolean inBody; 037 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SystemInfo.class); 038 039 SystemInfo(boolean inBody) { 040 this.inBody = inBody; 041 } 042 043 @Override 044 @Nonnull 045 public String toString() { 046 StringBuilder builder = new StringBuilder(); 047 if (inBody) { 048 builder.append("<details>\n<summary>System Info</summary>\n\n"); 049 } 050 asList().forEach(l -> builder.append(l).append("\n")); 051 if (inBody) { 052 builder.append("</details>\n"); 053 } 054 return builder.toString(); 055 } 056 057 public List<String> asList() { 058 List<String> list = new ArrayList<>(); 059 list.add("|Item|Value|"); 060 list.add("|---|---|"); 061 062 addLine(list, "JMRI Version", Version.name()); 063 addLine(list, "Application", Application.getApplicationName()); 064 065 Profile profile = ProfileManager.getDefault().getActiveProfile(); 066 if (profile != null) { 067 addLine(list, "Active profile", profile.getName()); 068 addLine(list, "Profile location", profile.getPath().getPath()); 069 addLine(list, "Profile ID", profile.getId()); 070 } else { 071 addLine(list, "Active profile", ""); 072 } 073 074 addLine(list, "JMRI Network ID", NodeIdentity.networkIdentity()); 075 addLine(list, "JMRI Storage ID", NodeIdentity.storageIdentity(profile)); 076 077 addLine(list, "Preferences directory", FileUtil.getUserFilesPath()); 078 addLine(list, "Program directory", FileUtil.getProgramPath()); 079 addLine(list, "Roster index", Roster.getDefault().getRosterIndexPath()); 080 081 File panel = LoadXmlUserAction.getCurrentFile(); 082 addLine(list, "Panel file", panel != null ? panel.getPath() : ""); 083 084 addLine(list, "Locale", InstanceManager.getDefault(GuiLafPreferencesManager.class).getLocale().toString()); 085 086 addLine(list, "Operations location", OperationsXml.getFileLocation()); 087 088 InstanceManager.getOptionalDefault(AudioManager.class).ifPresent(am -> { 089 AudioFactory af = am.getActiveAudioFactory(); 090 addLine(list, "Audio factory", af != null ? af.toString() : ""); 091 }); 092 093 InstanceManager.getOptionalDefault(ConnectionConfigManager.class) 094 .ifPresent(ccm -> Arrays.stream(ccm.getConnections()) 095 .forEach(c -> addLine(list, 096 "Connection " + c.getConnectionName(), 097 c.getManufacturer() + " connected via " + c.name() + " on " + c.getInfo() + (c.getDisabled() ? " (disabled)" : " (enabled)")))); 098 099 addComPortInfo(list); 100 101 System.getProperties().stringPropertyNames().stream().sorted() 102 .filter(n -> !n.equals("line.separator")) 103 .forEach(n -> addLine(list, n, System.getProperty(n))); 104 105 if (!GraphicsEnvironment.isHeadless()) { 106 addLine(list, "FileSystemView#getDefaultDirectory()", FileSystemView.getFileSystemView().getDefaultDirectory().getPath()); 107 addLine(list, "FileSystemView#getHomeDirectory()", FileSystemView.getFileSystemView().getHomeDirectory().getPath()); 108 addLine(list, "Default JFileChooser()", new jmri.util.swing.JmriJFileChooser().getCurrentDirectory().getPath()); 109 } 110 addDisplayDimensions(list); 111 112 addNetworkInfo(list); 113 114 return list; 115 } 116 117 private void addDisplayDimensions(List<String> list) { 118 if (!GraphicsEnvironment.isHeadless()) { 119 Arrays.stream(GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) 120 .forEachOrdered(device -> { 121 Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(device.getDefaultConfiguration()); 122 addLine(list, 123 "Display " + device.getIDstring(), 124 " size: width " + device.getDisplayMode().getWidth() + " height " + device.getDisplayMode().getHeight() 125 + " insets: top " + insets.top + " right " + insets.right + " bottom " + insets.bottom + " left " + insets.left); 126 }); 127 } else { 128 addLine(list, "Display", "headless"); 129 } 130 } 131 132 private void addNetworkInfo(List<String> list) { 133 try { 134 Collections.list(NetworkInterface.getNetworkInterfaces()).stream().forEach(ni 135 -> ni.getInterfaceAddresses().forEach(ia 136 -> addLine(list, 137 "Network Interface " + ni.getDisplayName(), 138 ia.getAddress().getHostAddress()))); 139 } catch (SocketException ex) { 140 log.error("Unable to enumerate network interfaces", ex); 141 } 142 InstanceManager.getDefault(ZeroConfServiceManager.class).allServices().forEach(zcs 143 -> addLine(list, 144 "ZeroConf service " + zcs.getKey(), 145 zcs.getServiceInfo().getNiceTextString())); 146 } 147 148 private void addComPortInfo(List<String> list) { 149 var portNames = jmri.jmrix.AbstractSerialPortController.getActualPortNames(); 150 151 // now output the details 152 for (String name : portNames) { 153 // output details 154 SerialPortFriendlyName port = PortNameMapper.getPortNameMap().get(name); 155 if (port == null) { 156 port = new SerialPortFriendlyName(name, null); 157 PortNameMapper.getPortNameMap().put(name, port); 158 } 159 addLine(list, " Port: " + name, ""); 160 } 161 } 162 163 private void addLine(List<String> list, String item, String value) { 164 list.add(String.format("|%s|%s|", escapePipes(item), escapePipes(value))); 165 } 166 167 private String escapePipes(String input) { 168 return input.replace("|", "\\|"); 169 } 170}