From 824ee701621f6d13a5d1bdd7b12845f3c13d9c9b Mon Sep 17 00:00:00 2001 From: kasemir Date: Thu, 20 Jul 2023 11:09:31 -0400 Subject: [PATCH] Handle macros w/ default values --- src/main/java/dbwr/macros/MacroUtil.java | 39 ++++++++++++++++++- src/main/java/dbwr/parser/XMLUtil.java | 24 +++++++++++- src/main/java/dbwr/widgets/NavTabsWidget.java | 2 +- src/main/webapp/index.jsp | 1 + 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/main/java/dbwr/macros/MacroUtil.java b/src/main/java/dbwr/macros/MacroUtil.java index 57306d4..32ea9f0 100644 --- a/src/main/java/dbwr/macros/MacroUtil.java +++ b/src/main/java/dbwr/macros/MacroUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Oak Ridge National Laboratory. + * Copyright (c) 2019-2023 Oak Ridge National Laboratory. * All rights reserved. This program and the accompanying materials * are made available under the terms of the LICENSE * which accompanies this distribution @@ -10,9 +10,12 @@ import static dbwr.WebDisplayRepresentation.logger; import java.io.ByteArrayOutputStream; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.w3c.dom.Element; @@ -22,8 +25,12 @@ import dbwr.parser.XMLUtil; +/* Macro support */ public class MacroUtil { + // This is simplified from the macro support in the desktop version + // TODO Update to use desktop version of macro support? + /** @param xml XML that contains '<macros>' * @return Name, value map of macros. May be empty. */ @@ -91,6 +98,10 @@ public static String toJSON(final Map macros) throws Exception return buf.toString(); } + // From Desktop 'Macros.MACRO_NAME_PATTERN' + private static String MACRO_NAME_PATTERN = "[A-Za-z][A-Za-z0-9_.\\-\\[\\]]*"; + // Find NAME and DEFAULT in "$(NAME=DEFAULT)" + private static Pattern MACRO_WITH_DEFAULT = Pattern.compile("\\$\\((" + MACRO_NAME_PATTERN + ")=([^)]+)\\)"); /** @param macros Macros * @param text Text that might contain macro references @@ -109,6 +120,18 @@ public static String expand(final MacroProvider macros, final String text) while (result.contains("${") && --recursions > 0) for (final String name : macros.getMacroNames()) result = result.replace("${" + name + "}", macros.getMacroValue(name)); + + // Expand unresolved macros that have default values + Matcher mac_w_def = MACRO_WITH_DEFAULT.matcher(result); + while (mac_w_def.find()) + { + final String expression = mac_w_def.group(0); + final String name = mac_w_def.group(1); + final String def_val = mac_w_def.group(2); + final String value = macros.getMacroValue(name); + result =result.replace(expression, value != null ? value : def_val); + mac_w_def = MACRO_WITH_DEFAULT.matcher(result); + } return result; } @@ -121,4 +144,18 @@ public static void expand(MacroProvider parent, Map macros) { macros.replaceAll((name, value) -> expand(parent, value)); } + + // Demo + public static void main(String[] args) + { + final Map values = new HashMap<>(); + values.put("S", "System"); + values.put("N", "2"); + final MacroProvider macros = MacroProvider.forMap(values); + + System.out.println(expand(macros, "$(S):Motor$(N)")); + System.out.println(expand(macros, "$(TAB=7)")); + System.out.println(expand(macros, "$(S):Motor$(N=99)")); + System.out.println(expand(macros, "$(S):Motor$(N=99) on tab $(TAB=7)")); + } } diff --git a/src/main/java/dbwr/parser/XMLUtil.java b/src/main/java/dbwr/parser/XMLUtil.java index 04de318..353bc1f 100644 --- a/src/main/java/dbwr/parser/XMLUtil.java +++ b/src/main/java/dbwr/parser/XMLUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019-2020 Oak Ridge National Laboratory. + * Copyright (c) 2019-2023 Oak Ridge National Laboratory. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -258,6 +258,28 @@ public static Optional getChildInteger(final Element parent, final Stri } } + /** Given a parent element, locate integer value of a child node. + * @param macros Macros + * @param parent Parent element + * @param name Name of child element + * @return Value of child element, or empty result + * @throws Exception on error parsing the number + */ + public static Optional getChildInteger(final MacroProvider macros, final Element parent, final String name) throws Exception + { + final Element child = getChildElement(parent, name); + if (child == null) + return Optional.empty(); + try + { + return Optional.of(Integer.valueOf(MacroUtil.expand(macros, getString(child)))); + } + catch (final NumberFormatException ex) + { + throw new Exception("Expected integer for <" + name +">", ex); + } + } + /** Given a parent element, locate long value of a child node. * @param parent Parent element * @param name Name of child element diff --git a/src/main/java/dbwr/widgets/NavTabsWidget.java b/src/main/java/dbwr/widgets/NavTabsWidget.java index 28c36c8..637d47d 100644 --- a/src/main/java/dbwr/widgets/NavTabsWidget.java +++ b/src/main/java/dbwr/widgets/NavTabsWidget.java @@ -73,7 +73,7 @@ public NavTabsWidget(final ParentWidget parent, final Element xml) throws Except tab_width = XMLUtil.getChildInteger(xml, "tab_width").orElse(100); tab_height = XMLUtil.getChildInteger(xml, "tab_height").orElse(30); tab_spacing = XMLUtil.getChildInteger(xml, "tab_spacing").orElse(2); - active_tab = XMLUtil.getChildInteger(xml, "active_tab").orElse(0); + active_tab = XMLUtil.getChildInteger(parent, xml, "active_tab").orElse(0); } @Override diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp index 2d1f3f5..0e1b59c 100644 --- a/src/main/webapp/index.jsp +++ b/src/main/webapp/index.jsp @@ -120,6 +120,7 @@ view.jsp?cache=false&display=file:/Path/to/Display+Builder/01_main.bob
+ 2023-07-20 Handle macros with default value
2023-05-11 Navigation Tabs: Use parent macros even if no instance macros
2023-04-28 Action Button: replace vs. new tab, also using ctrl key
2023-04-26 Navigation Tabs: Use both instance and parent macros