package nl.uva.softwcons.ql.ui; import static java.util.stream.Collectors.toList; import java.util.Arrays; import java.util.List; import nl.uva.softwcons.ql.ast.form.Form; import nl.uva.softwcons.ql.ast.form.FormVisitor; import nl.uva.softwcons.ql.ast.statement.ComputedQuestion; import nl.uva.softwcons.ql.ast.statement.Conditional; import nl.uva.softwcons.ql.ast.statement.Question; import nl.uva.softwcons.ql.ast.statement.Statement; import nl.uva.softwcons.ql.ast.statement.StatementVisitor; import nl.uva.softwcons.ql.eval.Evaluator; import nl.uva.softwcons.ql.ui.layout.Layout; import nl.uva.softwcons.ql.ui.layout.QuestionLayout; import nl.uva.softwcons.ql.ui.renderer.Renderer; import nl.uva.softwcons.ql.ui.widget.Widget; import nl.uva.softwcons.ql.ui.widget.factory.WidgetFactory; public class UiBuilder implements FormVisitor<Void>, StatementVisitor<List<QuestionLayout>> { private final Evaluator evaluator; private final WidgetFactory widgetFactory; private final Renderer renderer; public UiBuilder(final Form form, final Renderer renderer, final WidgetFactory widgetFactory) { this.evaluator = new Evaluator(form); this.widgetFactory = widgetFactory; this.renderer = renderer; } public static Layout buildFrom(final Form form, final Renderer renderer, final WidgetFactory widgetFactory) { final UiBuilder u = new UiBuilder(form, renderer, widgetFactory); form.accept(u); return renderer.getLayout(); } @Override public Void visit(final Form form) { form.getStatements().forEach(s -> s.accept(this)); visitAndFlatten(form.getStatements()).forEach(l -> { renderer.add(l); }); return null; } @Override public List<QuestionLayout> visit(final ComputedQuestion question) { final Widget questionWidget = this.widgetFactory.getWidget(question); final QuestionLayout layout = new QuestionLayout(question.getId(), question.getLabel(), questionWidget); questionWidget.setEditable(false); questionWidget.setValue(evaluator.getValue(question.getId())); evaluator.addListener(question, (newValue) -> { questionWidget.setValue(newValue); }); return Arrays.asList(layout); } @Override public List<QuestionLayout> visit(final Question question) { final Widget questionWidget = this.widgetFactory.getWidget(question); final QuestionLayout layout = new QuestionLayout(question.getId(), question.getLabel(), questionWidget); questionWidget.addListener((newValue) -> { evaluator.updateValue(question.getId(), newValue); }); return Arrays.asList(layout); } @Override public List<QuestionLayout> visit(final Conditional conditional) { final List<QuestionLayout> layouts = visitAndFlatten(conditional.getQuestions()); layouts.forEach(layout -> { layout.setVisible(evaluator.getValue(conditional).inConditionalContext()); evaluator.addListener(conditional, (value) -> { layout.setVisible(value.inConditionalContext()); }); }); return layouts; } /** * Visits the given statements, collects found question layouts and merges * them into a flat resulting list. */ private List<QuestionLayout> visitAndFlatten(final List<? extends Statement> statements) { return statements.stream().flatMap(s -> s.accept(this).stream()).collect(toList()); } }