Add support for references in window inflater

This commit is contained in:
2021-03-16 20:11:09 +01:00
parent 397e9e1f9c
commit e5b97546f6
3 changed files with 59 additions and 6 deletions

View File

@@ -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<String, Component>();
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<String, Component> 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<String, Component> 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<String, Component> 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());