diff --git a/core/framework/src/main/java/org/phoebus/framework/preferences/PropertyPreferenceWriter.java b/core/framework/src/main/java/org/phoebus/framework/preferences/PropertyPreferenceWriter.java
index 0f39f4392e..310df03199 100644
--- a/core/framework/src/main/java/org/phoebus/framework/preferences/PropertyPreferenceWriter.java
+++ b/core/framework/src/main/java/org/phoebus/framework/preferences/PropertyPreferenceWriter.java
@@ -7,10 +7,27 @@
*******************************************************************************/
package org.phoebus.framework.preferences;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
import java.util.prefs.Preferences;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/** Write preferences in property file format
* @author Kay Kasemir
@@ -36,31 +53,149 @@ public static void save(final OutputStream stream) throws Exception
final OutputStreamWriter out = new OutputStreamWriter(stream);
)
{
- out.append("# Preference settings\n");
- out.append("# Format:\n");
- out.append("# the.package.name/key=value\n");
- listSettings(out, Preferences.userRoot());
- out.append("# End.\n");
+ out.append("# Preference settings
\n");
+ out.append("# Format:
\n");
+ out.append("# the.package.name/key=value
\n");
+ out.append("
# key=value in red are incorrect properties
\n");
+ listSettings(getAllPropertyKeys(), out, Preferences.userRoot());
+ out.append("# End.
\n");
out.flush();
}
}
- private static void listSettings(final Writer out, final Preferences node) throws Exception
+ private static void listSettings(Map allKeysWithPackages, final Writer out, final Preferences node) throws Exception
{
for (String key : node.keys())
- formatSetting(out, node, key);
+ formatSetting(allKeysWithPackages, out, node, key);
for (String child : node.childrenNames())
- listSettings(out, node.node(child));
+ listSettings(allKeysWithPackages, out, node.node(child));
}
- private static void formatSetting(final Writer out, final Preferences node, final String key) throws Exception
+ private static void formatSetting(Map allKeysWithPackages, final Writer out, final Preferences node, final String key) throws Exception
{
final String path = node.absolutePath();
- out.append(path.substring(1).replace('/', '.'))
- .append('/')
- .append(key)
+ String fullKey = path.substring(1).replace('/', '.') + '/' + key;
+ String keyFound = allKeysWithPackages.get(fullKey);
+ boolean bNotFound = keyFound == null ? true : false;
+ if (bNotFound) out.append("");
+ out.append(escapeHtml(fullKey))
.append('=')
- .append(node.get(key, ""))
- .append('\n');
+ .append(escapeHtml(node.get(key, "")))
+ .append("
\n");
+ if (bNotFound) out.append("
");
+ }
+
+ private static Map getAllPropertyKeys() throws Exception
+ {
+ Map allKeysWithPackages = new HashMap<>();
+
+ String classpath = System.getProperty("java.class.path");
+ String[] jars = classpath.split(System.getProperty("path.separator"));
+
+ if (jars.length == 1) jars = getAllJarFromManifest(jars[0]);
+
+ for (String jarEntry : jars) {
+ File file = new File(jarEntry);
+
+ if (jarEntry.endsWith(".jar")) {
+ try (JarFile jarFile = new JarFile(file)) {
+ Enumeration entries = jarFile.entries();
+
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String entryName = entry.getName();
+
+ if (entryName.endsWith("preferences.properties")) {
+ parsePropertiesWithPackage(
+ jarFile.getInputStream(entry),
+ entryName,
+ allKeysWithPackages
+ );
+ }
+ }
+ } catch (IOException e) {
+ System.err.println("Error opening JAR : " + jarEntry);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ return allKeysWithPackages;
+ }
+
+ private static String[] getAllJarFromManifest(String jarPath) {
+ String[] jars = new String[0];
+ File jarFile = new File(jarPath);
+
+ try (JarFile jar = new JarFile(jarFile)) {
+ Manifest manifest = jar.getManifest();
+
+ if (manifest != null) {
+ String classPath = manifest.getMainAttributes().getValue("Class-Path");
+
+ if (classPath != null && !classPath.isEmpty()) {
+ jars = classPath.split(" ");
+
+ for (int iJar = 0; iJar < jars.length; iJar++) {
+ Path fullPath = Paths.get(jarFile.getParent()).resolve(jars[iJar]);
+ jars[iJar] = fullPath.toString();
+ }
+ } else {
+ System.err.println("No Class-Path found in MANIFEST.MF.");
+ }
+ } else {
+ System.err.println("MANIFEST.MF not found in the JAR.");
+ }
+ } catch (IOException e) {
+ System.err.println("Error when reading the jar : " + jarPath);
+ e.printStackTrace();
+ }
+
+ return jars;
+ }
+
+ private static void parsePropertiesWithPackage(InputStream inputStream, String fileName, Map allKeysWithPackages) {
+ Properties props = new Properties();
+ String packageName = null;
+
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+ String line;
+ StringBuilder content = new StringBuilder();
+
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("#") && line.contains("Package")) {
+ // Find package name
+ Pattern pattern = Pattern.compile("#\\s*Package\\s+([^\\s]+)");
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.find()) {
+ packageName = matcher.group(1);
+ }
+ } else if (!line.startsWith("#")) {
+ content.append(line).append("\n");
+ }
+ }
+
+ if (content.length() > 0) {
+ props.load(new ByteArrayInputStream(content.toString().getBytes()));
+ }
+
+ // properties found
+ for (String key : props.stringPropertyNames()) {
+ String prefixedKey = (packageName != null) ? packageName + "/" + key : key;
+ allKeysWithPackages.put(prefixedKey, props.getProperty(key));
+ }
+ } catch (IOException e) {
+ System.err.println("Error when reading file " + fileName);
+ e.printStackTrace();
+ }
+ }
+
+ private static String escapeHtml(String input) {
+ return input.replace("&", "&")
+ .replace("<", "<")
+ .replace(">", ">")
+ .replace("\"", """)
+ .replace("'", "'");
}
}
diff --git a/core/ui/src/main/java/org/phoebus/ui/help/OpenAbout.java b/core/ui/src/main/java/org/phoebus/ui/help/OpenAbout.java
index 0add9484a5..254d9d48d5 100644
--- a/core/ui/src/main/java/org/phoebus/ui/help/OpenAbout.java
+++ b/core/ui/src/main/java/org/phoebus/ui/help/OpenAbout.java
@@ -42,6 +42,7 @@
import javafx.scene.image.Image;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
+import javafx.scene.web.WebView;
/** Menu entry to open 'about'
* @author Kay Kasemir
@@ -204,12 +205,17 @@ private Node createDetailSection()
logger.log(Level.WARNING, "Cannot list preferences", ex);
}
- area = new TextArea(prefs_buf.toString());
- area.setEditable(false);
+ WebView webView = new WebView();
+ String content = "";
+ content += prefs_buf.toString();
+ content += "";
+ webView.getEngine().loadContent(content);
- VBox.setVgrow(area, Priority.ALWAYS);
+ VBox.setVgrow(webView, Priority.ALWAYS);
- final Tab prefs = new Tab(Messages.HelpAboutPrefs, area);
+ final Tab prefs = new Tab(Messages.HelpAboutPrefs, webView);
final TabPane tabs = new TabPane(apps, envs, props, prefs);
return tabs;