From e5b97546f670df15215362e34a84b24b9676ae12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Tue, 16 Mar 2021 20:11:09 +0100 Subject: [PATCH] Add support for references in window inflater --- .../base/api/game/gui/window/Inflatable.java | 7 +++ .../base/api/game/gui/window/Ref.java | 12 +++++ .../engine/gui/xml/inflater/Inflater.java | 46 ++++++++++++++++--- 3 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 api/src/main/java/com/bartlomiejpluta/base/api/game/gui/window/Inflatable.java create mode 100644 api/src/main/java/com/bartlomiejpluta/base/api/game/gui/window/Ref.java diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/window/Inflatable.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/window/Inflatable.java new file mode 100644 index 00000000..4e2e04dd --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/window/Inflatable.java @@ -0,0 +1,7 @@ +package com.bartlomiejpluta.base.api.game.gui.window; + +public interface Inflatable { + default void onInflate() { + // do nothing + } +} diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/window/Ref.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/window/Ref.java new file mode 100644 index 00000000..7d826c96 --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/gui/window/Ref.java @@ -0,0 +1,12 @@ +package com.bartlomiejpluta.base.api.game.gui.window; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Ref { + String value(); +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/xml/inflater/Inflater.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/xml/inflater/Inflater.java index 6c403ddd..e1125797 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/xml/inflater/Inflater.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/gui/xml/inflater/Inflater.java @@ -4,6 +4,8 @@ import com.bartlomiejpluta.base.api.game.context.Context; import com.bartlomiejpluta.base.api.game.gui.base.GUI; import com.bartlomiejpluta.base.api.game.gui.base.SizeMode; import com.bartlomiejpluta.base.api.game.gui.component.Component; +import com.bartlomiejpluta.base.api.game.gui.window.Inflatable; +import com.bartlomiejpluta.base.api.game.gui.window.Ref; import com.bartlomiejpluta.base.api.game.gui.window.Window; import com.bartlomiejpluta.base.api.game.gui.window.WindowPosition; import com.bartlomiejpluta.base.engine.error.AppException; @@ -18,6 +20,8 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.File; import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; import java.util.stream.Stream; @org.springframework.stereotype.Component @@ -77,6 +81,8 @@ public class Inflater { @SneakyThrows private Window inflateWindow(Node root, Context context, GUI gui) { + var refs = new HashMap(); + var uri = root.getNamespaceURI(); var name = root.getLocalName(); @@ -122,20 +128,42 @@ public class Inflater { throw new AppException("Window can have at most 1 child"); } - var content = parseNode(child, context, gui); + var content = parseNode(child, refs, context, gui); window.setContent(content); hasContent = true; } + updateWindowRefs(window, refs); + + if (window instanceof Inflatable) { + ((Inflatable) window).onInflate(); + } + return window; } + @SneakyThrows + private void updateWindowRefs(Window window, Map refs) { + var windowClass = window.getClass(); + for (var field : windowClass.getDeclaredFields()) { + if (field.isAnnotationPresent(Ref.class)) { + var ref = field.getAnnotation(Ref.class).value(); + var referencedComponent = refs.get(ref); + if (referencedComponent == null) { + throw new AppException("The [%s] window is trying to reference component [%s] which does not exist", windowClass.getSimpleName(), ref); + } + field.setAccessible(true); + field.set(window, referencedComponent); + } + } + } + private Component inflateComponent(Node root, Context context, GUI gui) { - return parseNode(root, context, gui); + return parseNode(root, new HashMap<>(), context, gui); } @SneakyThrows - private Component parseNode(Node node, Context context, GUI gui) { + private Component parseNode(Node node, Map refs, Context context, GUI gui) { var uri = node.getNamespaceURI(); var name = node.getLocalName(); @@ -146,7 +174,7 @@ public class Inflater { var canonicalName = name.replaceAll("\\*", "").replaceAll("\\.+", "."); var componentClass = loader.loadClass(canonicalName); - var component = createComponent(componentClass, node.getAttributes(), context, gui); + var component = createComponent(componentClass, node.getAttributes(), refs, context, gui); var children = node.getChildNodes(); @@ -168,14 +196,14 @@ public class Inflater { continue; } - component.add(parseNode(childNode, context, gui)); + component.add(parseNode(childNode, refs, context, gui)); } return component; } @SneakyThrows - private Component createComponent(Class componentClass, NamedNodeMap attributes, Context context, GUI gui) { + private Component createComponent(Class componentClass, NamedNodeMap attributes, Map refs, Context context, GUI gui) { var component = (Component) componentClass.getConstructor(Context.class, GUI.class).newInstance(context, gui); // Set attributes via setter methods @@ -187,6 +215,12 @@ public class Inflater { continue; } + // Collect referencable components + if ("ref".equals(attribute.getLocalName())) { + refs.put(attribute.getNodeValue(), component); + continue; + } + var setterName = createSetterMethodName(attribute.getLocalName()); var value = parseValue(attribute.getNodeValue()); var setter = componentClass.getMethod(setterName, value.getClass());