package xapi.jre.ui.impl.feature; import com.github.javaparser.ASTHelper; import com.github.javaparser.ast.expr.*; import com.github.javaparser.ast.expr.BinaryExpr.Operator; import com.github.javaparser.ast.plugin.NodeTransformer; import com.github.javaparser.ast.plugin.Transformer; import xapi.dev.source.MethodBuffer; import xapi.dev.ui.ContainerMetadata; import xapi.dev.ui.UiComponentGenerator; import xapi.dev.ui.UiFeatureGenerator; import xapi.dev.ui.UiGeneratorTools; import xapi.dev.ui.UiVisitScope; import xapi.jre.ui.runtime.DoubleSupplierBinding; import java.util.List; import java.util.Optional; /** * Created by James X. Nelson (james @wetheinter.net) on 7/1/16. */ public class JavaFxSizeFeatureGenerator extends UiFeatureGenerator { @Override public UiVisitScope startVisit( UiGeneratorTools service, UiComponentGenerator generator, ContainerMetadata container, UiAttrExpr attr ) { String panel = container.peekPanelName(); final UiContainerExpr parent = container.getUi(); final MethodBuffer mb = container.getMethod(panel); final UiAttrExpr size = parent.getAttributeNotNull("size"); Expression expr = size.getExpression(); while (expr instanceof EnclosedExpr) { expr = ((EnclosedExpr)expr).getInner(); } final Expression width, height; if (ASTHelper.isNumericLiteral(expr)) { // a single numeric literal means "use this number for both width and height". width = expr; height = expr; } else if (expr instanceof BinaryExpr) { BinaryExpr binary = (BinaryExpr) expr; if (binary.getOperator() == Operator.times) { width = binary.getLeft(); height = binary.getRight(); } else { width = binary; height = binary; } } else { width = expr; height = expr; } final Transformer transformer = generator.getTransformer(); String widthStr = toLambdaOrLiteral(width, transformer); String heightStr = toLambdaOrLiteral(height, transformer); if (width != null) { if (ASTHelper.isNumericLiteral(width)) { mb.println(panel+".setPrefWidth(" + widthStr + ");"); } else { final Optional<UiAttrExpr> fill = parent.getAttribute("fill"); if (fill.isPresent()) { if (!"height".equals(ASTHelper.extractAttrValue(fill.get()))) { throw new IllegalArgumentException( "Cannot use a width size expression in a container which uses a fill that modifies width. " + "Bad container: " + parent); } } final String binder = mb.addImport(DoubleSupplierBinding.class); mb.println(panel + ".prefWidthProperty().bind(" + binder + ".valueOf("); mb.indentln(widthStr); mb.print(")"); final List<String> notifiers = NodeTransformer.findTransformers(width); if (!notifiers.isEmpty()) { mb.println(); notifiers.forEach(n-> mb.indentln(".bindNotifier(" + n + ".out1())") ); } mb.println(");"); } } if (height != null) { if (ASTHelper.isNumericLiteral(height)) { mb.println(panel+".setPrefHeight(" + heightStr + ");"); } else { final Optional<UiAttrExpr> fill = parent.getAttribute("fill"); if (fill.isPresent()) { if (!"width".equals(ASTHelper.extractAttrValue(fill.get()))) { throw new IllegalArgumentException( "Cannot use a height size expression in a container which uses a fill that modifies height. " + "Bad container: " + parent); } } final String binder = mb.addImport(DoubleSupplierBinding.class); mb.println(panel + ".prefHeightProperty().bind(" + binder + ".valueOf("); mb.indentln(heightStr); mb.print(")"); final List<String> notifiers = NodeTransformer.findTransformers(width); if (!notifiers.isEmpty()) { mb.println(); notifiers.forEach(n-> mb.indentln(".bindNotifier(" + n + ".out1())") ); } mb.println(");"); } } return super.startVisit(service, generator, container, attr); } protected String toLambdaOrLiteral(Expression expr, Transformer transformer) { while (expr instanceof EnclosedExpr) { expr = ((EnclosedExpr)expr).getInner(); } if ( expr instanceof LambdaExpr || expr instanceof MethodReferenceExpr || expr instanceof DoubleLiteralExpr) { return expr.toSource(transformer); } if (expr instanceof IntegerLiteralExpr) { return expr.toSource(transformer) + "."; // declare as double } if (expr instanceof LongLiteralExpr) { return expr.toSource(transformer).replace("L", "."); // declare as double } return "()->" + expr.toSource(transformer); } }