diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml
index b8f690535..dd253fa57 100644
--- a/org.hl7.fhir.r5/pom.xml
+++ b/org.hl7.fhir.r5/pom.xml
@@ -166,7 +166,13 @@
4.12
test
-
+
+ net.sourceforge.plantuml
+ plantuml-mit
+ 1.2023.9
+ compile
+
+
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ExampleScenarioRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ExampleScenarioRenderer.java
new file mode 100644
index 000000000..493de71e2
--- /dev/null
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ExampleScenarioRenderer.java
@@ -0,0 +1,481 @@
+package org.hl7.fhir.r5.renderers;
+
+import net.sourceforge.plantuml.FileFormat;
+import net.sourceforge.plantuml.FileFormatOption;
+import org.hl7.fhir.exceptions.FHIRException;
+import org.hl7.fhir.r5.context.ContextUtilities;
+import org.hl7.fhir.r5.model.*;
+import org.hl7.fhir.r5.model.ExampleScenario.*;
+import org.hl7.fhir.r5.renderers.utils.RenderingContext;
+import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType;
+import org.hl7.fhir.utilities.xhtml.XhtmlDocument;
+import org.hl7.fhir.utilities.xhtml.XhtmlNode;
+import net.sourceforge.plantuml.SourceStringReader;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExampleScenarioRenderer extends TerminologyRenderer {
+
+ public ExampleScenarioRenderer(RenderingContext context) {
+ super(context);
+ }
+
+ public boolean render(XhtmlNode x, Resource scen) throws IOException {
+ return render(x, (ExampleScenario) scen);
+ }
+
+ public boolean render(XhtmlNode x, ExampleScenario scen) throws FHIRException {
+ try {
+ switch (context.getScenarioMode()) {
+ case ACTORS:
+ return renderActors(x, scen);
+ case INSTANCES:
+ return renderInstances(x, scen);
+ case PROCESSES:
+ return renderProcesses(x, scen);
+ default:
+ throw new FHIRException("Unknown ExampleScenario Renderer Mode " + context.getScenarioMode());
+ }
+ } catch (Exception e) {
+ throw new FHIRException("Error rendering ExampleScenario " + scen.getUrl(), e);
+ }
+ }
+
+ public String renderDiagram(ExampleScenario scen) throws IOException {
+ String plantUml = toPlantUml(scen);
+ SourceStringReader reader = new SourceStringReader(plantUml);
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ reader.outputImage(os, new FileFormatOption(FileFormat.SVG));
+ os.close();
+
+ final String svg = new String(os.toByteArray(), Charset.forName("UTF-8"));
+ return svg;
+ }
+
+ protected String toPlantUml(ExampleScenario scen) throws IOException {
+ String plantUml = "@startuml\r\n";
+ plantUml += "Title " + (scen.hasTitle() ? scen.getTitle() : scen.getName()) + "\r\n\r\n";
+ Map actorKeys = new HashMap();
+
+ for (ExampleScenarioActorComponent actor: scen.getActor()) {
+ String actorType = actor.getType().equals(Enumerations.ExampleScenarioActorType.PERSON) ? "actor" : "participant";
+ actorKeys.put(actor.getKey(), escapeKey(actor.getKey()));
+ plantUml += actorType + " \"" + creolLink(actor.getTitle(), "#a_" + actor.getKey(), actor.getDescription()) + "\" as " + actorKeys.get(actor.getKey()) + "\r\n";
+ }
+ plantUml += "\r\n";
+
+ int processNum = 1;
+ for (ExampleScenarioProcessComponent process: scen.getProcess()) {
+ plantUml += toPlantUml(process, Integer.toString(processNum), scen, actorKeys);
+ processNum++;
+ }
+ plantUml += "@enduml";
+
+ return plantUml;
+ }
+
+ private String escapeKey(String origKey) {
+ char[] chars = origKey.toCharArray();
+ for (int i=0; i='A' && c<='Z') || (c>='a' && c<='z') || (c>='0' && c<='9') || c=='@' || c=='.'))
+ chars[i] = '_';
+ }
+ return new String(chars);
+ }
+
+ protected String toPlantUml(ExampleScenarioProcessComponent process, String prefix, ExampleScenario scen, Map actorKeys) throws IOException {
+ String plantUml = "group " + process.getTitle() + " " + creolLink("details", "#p_" + prefix, process.getDescription()) + "\r\n";
+
+ Map actorsActive = new HashMap();
+ for (ExampleScenarioActorComponent actor : scen.getActor()) {
+ actorsActive.put(actor.getKey(), Boolean.FALSE);
+ }
+ int stepCount = 1;
+ for (ExampleScenarioProcessStepComponent step: process.getStep()) {
+ plantUml += toPlantUml(step, stepPrefix(prefix, step, stepCount), scen, actorsActive, actorKeys);
+ stepCount++;
+ }
+
+ plantUml += "end\r\n\r\n";
+ return plantUml;
+ }
+
+ protected String toPlantUml(ExampleScenarioProcessStepComponent step, String prefix, ExampleScenario scen, Map actorsActive, Map actorKeys) throws IOException {
+ String plantUml = "";
+ if (step.hasWorkflow()) {
+ XhtmlNode n = new XhtmlDocument();
+ renderCanonical(scen, n, step.getWorkflow());
+ XhtmlNode ref = n.getChildNodes().get(0);
+ plantUml += noteOver(scen.getActor(), "Step " + trimPrefix(prefix) + " - See scenario\n" + creolLink(ref.getContent(), ref.getAttribute("href")));
+ } else if (step.hasProcess())
+ plantUml += toPlantUml(step.getProcess(), prefix, scen, actorKeys);
+ else {
+ // Operation
+ plantUml += toPlantUml(step.getOperation(), prefix, scen, actorsActive, actorKeys);
+ }
+
+ return plantUml;
+ }
+
+ protected String toPlantUml(ExampleScenarioProcessStepOperationComponent op, String prefix, ExampleScenario scen, Map actorsActive, Map actorKeys) {
+ StringBuilder plantUml = new StringBuilder();
+ plantUml.append(handleActivation(op.getInitiator(), op.getInitiatorActive(), actorsActive, actorKeys));
+ plantUml.append(handleActivation(op.getReceiver(), op.getReceiverActive(), actorsActive, actorKeys));
+ plantUml.append(actorKeys.get(op.getInitiator()) + " -> " + actorKeys.get(op.getReceiver()) + ": ");
+ plantUml.append(creolLink(op.getTitle(), "#s_" + prefix, op.getDescription()));
+ if (op.hasRequest()) {
+ plantUml.append(" (" + creolLink("payload", linkForInstance(op.getRequest())) + ")\r\n");
+ }
+ if (op.hasResponse()) {
+ plantUml.append("activate " + actorKeys.get(op.getReceiver()) + "\r\n");
+ plantUml.append(actorKeys.get(op.getReceiver()) + " --> " + actorKeys.get(op.getInitiator()) + ": ");
+ plantUml.append(creolLink("response", "#s_" + prefix, op.getDescription()));
+ plantUml.append(" (" + creolLink("payload", linkForInstance(op.getRequest())) + ")\r\n");
+ plantUml.append("deactivate " + actorKeys.get(op.getReceiver()) + "\r\n");
+ }
+ plantUml.append(handleDeactivation(op.getInitiator(), op.getInitiatorActive(), actorsActive, actorKeys));
+ plantUml.append(handleDeactivation(op.getReceiver(), op.getReceiverActive(), actorsActive, actorKeys));
+
+ return plantUml.toString();
+ }
+
+ private String handleActivation(String actorId, boolean active, Map actorsActive, Map actorKeys) {
+ String plantUml = "";
+ Boolean actorWasActive = actorsActive.get(actorId);
+ if (active && !actorWasActive) {
+ plantUml += "activate " + actorKeys.get(actorId) + "\r\n";
+ }
+ return plantUml;
+ }
+
+ private String handleDeactivation(String actorId, boolean active, Map actorsActive, Map actorKeys) {
+ String plantUml = "";
+ Boolean actorWasActive = actorsActive.get(actorId);
+ if (!active && actorWasActive) {
+ plantUml += "deactivate " + actorKeys.get(actorId) + "\r\n";
+ }
+ if (active != actorWasActive) {
+ actorsActive.remove(actorId);
+ actorsActive.put(actorId, Boolean.valueOf(active));
+ }
+ return plantUml;
+ }
+
+ private String linkForInstance(ExampleScenarioInstanceContainedInstanceComponent ref) {
+ String plantUml = "#i_" + ref.getInstanceReference();
+ if (ref.hasVersionReference())
+ plantUml += "v_" + ref.getVersionReference();
+ return plantUml;
+ }
+
+ private String trimPrefix(String prefix){
+ return prefix.substring(prefix.lastIndexOf(".") + 1);
+ }
+
+ private String noteOver(List actors, String text) {
+ String plantUml = "Note over ";
+ List actorKeys = new ArrayList();
+ for (ExampleScenarioActorComponent actor: actors) {
+ actorKeys.add(actor.getKey());
+ }
+ plantUml += String.join(", ", actorKeys);
+ plantUml += " " + text;
+ return plantUml;
+ }
+
+ private String creolLink(String text, String url) {
+ return creolLink(text, url, null);
+ }
+
+ private String creolLink(String text, String url, String flyover) {
+ String s = "[[" + url;
+ if (flyover!=null)
+ s += "{" + flyover + "}";
+ s += " " + text + "]]";
+ return s;
+ }
+
+ public boolean renderActors(XhtmlNode x, ExampleScenario scen) throws IOException {
+ XhtmlNode tbl = x.table("table-striped table-bordered");
+ XhtmlNode thead = tbl.tr();
+ thead.th().addText("Name");
+ thead.th().addText("Type");
+ thead.th().addText("Description");
+ for (ExampleScenarioActorComponent actor : scen.getActor()) {
+ XhtmlNode tr = tbl.tr();
+ XhtmlNode nameCell = tr.td();
+ nameCell.an("a_" + actor.getKey());
+ nameCell.tx(actor.getTitle());
+ tr.td().tx(actor.getType().getDisplay());
+ addMarkdown(tr.td().style("overflow-wrap:break-word"), actor.getDescription());
+ }
+ return true;
+ }
+
+ public boolean renderInstances(XhtmlNode x, ExampleScenario scen) throws IOException {
+ XhtmlNode tbl = x.table("table-striped table-bordered");
+ XhtmlNode thead = tbl.tr();
+ thead.th().addText("Name");
+ thead.th().addText("Type");
+ thead.th().addText("Content");
+ thead.th().addText("Description");
+
+ Map instanceNames = new HashMap();
+ for (ExampleScenarioInstanceComponent instance : scen.getInstance()) {
+ instanceNames.put("i_" + instance.getKey(), instance.getTitle());
+ if (instance.hasVersion()) {
+ for (ExampleScenarioInstanceVersionComponent version: instance.getVersion()) {
+ instanceNames.put("i_" + instance.getKey() + "v_" + version.getKey(), version.getTitle());
+ }
+ }
+ }
+
+ for (ExampleScenarioInstanceComponent instance : scen.getInstance()) {
+ XhtmlNode row = tbl.tr();
+ XhtmlNode nameCell = row.td();
+ nameCell.an("i_" + instance.getKey());
+ nameCell.tx(instance.getTitle());
+ XhtmlNode typeCell = row.td();
+ if (instance.hasVersion())
+ typeCell.attribute("rowSpan", Integer.toString(instance.getVersion().size()+1));
+
+ if (!instance.hasStructureVersion() || instance.getStructureType().getSystem().equals("")) {
+ if (instance.hasStructureVersion())
+ typeCell.tx("FHIR version " + instance.getStructureVersion() + " ");
+ if (instance.hasStructureProfile()) {
+ renderCanonical(scen, typeCell, instance.getStructureProfile().toString());
+ } else {
+ renderCanonical(scen, typeCell, "http://hl7.org/fhir/StructureDefinition/" + instance.getStructureType().getCode());
+ }
+ } else {
+ render(typeCell, instance.getStructureVersionElement());
+ typeCell.tx(" version " + instance.getStructureVersion());
+ if (instance.hasStructureProfile()) {
+ typeCell.tx(" ");
+ renderCanonical(scen, typeCell, instance.getStructureProfile().toString());
+ }
+ }
+ if (instance.hasContent() && instance.getContent().hasReference()) {
+ // Force end-user mode to avoid ugly references
+ RenderingContext.ResourceRendererMode mode = context.getMode();
+ context.setMode(RenderingContext.ResourceRendererMode.END_USER);
+ renderReference(scen, row.td(), instance.getContent().copy().setDisplay("here"));
+ context.setMode(mode);
+ } else
+ row.td();
+
+ XhtmlNode descCell = row.td();
+ addMarkdown(descCell, instance.getDescription());
+ if (instance.hasContainedInstance()) {
+ descCell.b().tx("Contains: ");
+ int containedCount = 1;
+ for (ExampleScenarioInstanceContainedInstanceComponent contained: instance.getContainedInstance()) {
+ String key = "i_" + contained.getInstanceReference();
+ if (contained.hasVersionReference())
+ key += "v_" + contained.getVersionReference();
+ String description = instanceNames.get(key);
+ if (description==null)
+ throw new FHIRException("Unable to find contained instance " + key + " under " + instance.getKey());
+ descCell.ah("#" + key).tx(description);
+ containedCount++;
+ if (instance.getContainedInstance().size() > containedCount)
+ descCell.tx(", ");
+ }
+ }
+
+ for (ExampleScenarioInstanceVersionComponent version: instance.getVersion()) {
+ row = tbl.tr();
+ nameCell = row.td().style("padding-left: 10px;");
+ nameCell.an("i_" + instance.getKey() + "v_" + version.getKey());
+ XhtmlNode nameItem = nameCell.ul().li();
+ nameItem.tx(version.getTitle());
+
+ if (version.hasContent() && version.getContent().hasReference()) {
+ // Force end-user mode to avoid ugly references
+ RenderingContext.ResourceRendererMode mode = context.getMode();
+ context.setMode(RenderingContext.ResourceRendererMode.END_USER);
+ renderReference(scen, row.td(), version.getContent().copy().setDisplay("here"));
+ context.setMode(mode);
+ } else
+ row.td();
+
+ descCell = row.td();
+ addMarkdown(descCell, instance.getDescription());
+ }
+ }
+ return true;
+ }
+
+ public boolean renderProcesses(XhtmlNode x, ExampleScenario scen) throws IOException {
+ Map actors = new HashMap<>();
+ for (ExampleScenarioActorComponent actor: scen.getActor()) {
+ actors.put(actor.getKey(), actor);
+ }
+
+ Map instances = new HashMap<>();
+ for (ExampleScenarioInstanceComponent instance: scen.getInstance()) {
+ instances.put(instance.getKey(), instance);
+ }
+
+ int num = 1;
+ for (ExampleScenarioProcessComponent process : scen.getProcess()) {
+ renderProcess(x, process, Integer.toString(num), actors, instances);
+ num++;
+ }
+ return true;
+ }
+
+ public void renderProcess(XhtmlNode x, ExampleScenarioProcessComponent process, String prefix, Map actors, Map instances) throws IOException {
+ XhtmlNode div = x.div();
+ div.an("p_" + prefix);
+ div.b().tx("Process: " + process.getTitle());
+ if (process.hasDescription())
+ addMarkdown(div, process.getDescription());
+ if (process.hasPreConditions()) {
+ div.para().b().i().tx("Pre-conditions:");
+ addMarkdown(div, process.getPreConditions());
+ }
+ if (process.hasPostConditions()) {
+ div.para().b().i().tx("Post-conditions:");
+ addMarkdown(div, process.getPostConditions());
+ }
+ XhtmlNode tbl = div.table("table-striped table-bordered").style("width:100%");
+ XhtmlNode thead = tbl.tr();
+ thead.th().addText("Step");
+ thead.th().addText("Name");
+ thead.th().addText("Description");
+ thead.th().addText("Initator");
+ thead.th().addText("Receiver");
+ thead.th().addText("Request");
+ thead.th().addText("Response");
+ int stepCount = 1;
+ for (ExampleScenarioProcessStepComponent step: process.getStep()) {
+ renderStep(tbl, step, stepPrefix(prefix, step, stepCount), actors, instances);
+ stepCount++;
+ }
+
+ // Now go through the steps again and spit out any child processes
+ stepCount = 1;
+ for (ExampleScenarioProcessStepComponent step: process.getStep()) {
+ stepSubProcesses(tbl, step, stepPrefix(prefix, step, stepCount), actors, instances);
+ stepCount++;
+ }
+ }
+
+ private String stepPrefix(String prefix, ExampleScenarioProcessStepComponent step, int stepCount) {
+ String num = step.hasNumber() ? step.getNumber() : Integer.toString(stepCount);
+ return (!prefix.isEmpty() ? prefix + "." : "") + num;
+ }
+
+ private String altStepPrefix(String prefix, ExampleScenarioProcessStepComponent step, int altNum, int stepCount) {
+ return stepPrefix(prefix + "-Alt" + Integer.toString(altNum) + ".", step, stepCount);
+ }
+
+ private void stepSubProcesses(XhtmlNode x, ExampleScenarioProcessStepComponent step, String prefix, Map actors, Map instances) throws IOException {
+ if (step.hasProcess())
+ renderProcess(x, step.getProcess(), prefix, actors, instances);
+ if (step.hasAlternative()) {
+ int altNum = 1;
+ for (ExampleScenarioProcessStepAlternativeComponent alt: step.getAlternative()) {
+ int stepCount = 1;
+ for (ExampleScenarioProcessStepComponent altStep: alt.getStep()) {
+ stepSubProcesses(x, altStep, altStepPrefix(prefix, altStep, altNum, stepCount), actors, instances);
+ stepCount++;
+ }
+ altNum++;
+ }
+ }
+ }
+
+ private boolean renderStep(XhtmlNode tbl, ExampleScenarioProcessStepComponent step, String stepLabel, Map actors, Map instances) throws IOException {
+ XhtmlNode row = tbl.tr();
+ XhtmlNode prefixCell = row.td();
+ prefixCell.an("s_" + stepLabel);
+ prefixCell.tx(stepLabel.substring(stepLabel.indexOf(".") + 1));
+ if (step.hasProcess()) {
+ XhtmlNode n = row.td().colspan(6);
+ n.tx("See subprocess" );
+ n.ah("#p_" + stepLabel, step.getProcess().getTitle());
+ n.tx(" below");
+
+ } else if (step.hasWorkflow()) {
+ XhtmlNode n = row.td().colspan(6);
+ n.tx("See other scenario ");
+ String link = new ContextUtilities(context.getWorker()).getLinkForUrl(context.getLink(KnownLinkType.SPEC), step.getWorkflow());
+ n.ah(link, step.getProcess().getTitle());
+
+ } else {
+ // Must be an operation
+ ExampleScenarioProcessStepOperationComponent op = step.getOperation();
+ XhtmlNode name = row.td();
+ name.tx(op.getTitle());
+ if (op.hasType()) {
+ name.tx(" - ");
+ renderCoding(name, op.getType());
+ }
+ XhtmlNode descCell = row.td();
+ addMarkdown(descCell, op.getDescription());
+
+ addActor(row, op.getInitiator(), actors);
+ addActor(row, op.getReceiver(), actors);
+ addInstance(row, op.getRequest(), instances);
+ addInstance(row, op.getResponse(), instances);
+ }
+
+ int altNum = 1;
+ for (ExampleScenarioProcessStepAlternativeComponent alt : step.getAlternative()) {
+ XhtmlNode altHeading = tbl.tr().colspan(7).td();
+ altHeading.para().i().tx("Alternative " + alt.getTitle());
+ if (alt.hasDescription())
+ addMarkdown(altHeading, alt.getDescription());
+ int stepCount = 1;
+ for (ExampleScenarioProcessStepComponent subStep : alt.getStep()) {
+ renderStep(tbl, subStep, altStepPrefix(stepLabel, step, altNum, stepCount), actors, instances);
+ stepCount++;
+ }
+ altNum++;
+ }
+
+ return true;
+ }
+
+ private void addActor(XhtmlNode row, String actorId, Map actors) throws FHIRException {
+ XhtmlNode actorCell = row.td();
+ if (actorId==null)
+ return;
+ ExampleScenarioActorComponent actor = actors.get(actorId);
+ if (actor==null)
+ throw new FHIRException("Unable to find referenced actor " + actorId);
+ actorCell.ah("#a_" + actor.getKey(), actor.getDescription()).tx(actor.getTitle());
+ }
+
+ private void addInstance(XhtmlNode row, ExampleScenarioInstanceContainedInstanceComponent instanceRef, Map instances) {
+ XhtmlNode instanceCell = row.td();
+ if (instanceRef==null || instanceRef.getInstanceReference()==null)
+ return;
+ ExampleScenarioInstanceComponent instance = instances.get(instanceRef.getInstanceReference());
+ if (instance==null)
+ throw new FHIRException("Unable to find referenced instance " + instanceRef.getInstanceReference());
+ if (instanceRef.hasVersionReference()) {
+ ExampleScenarioInstanceVersionComponent theVersion = null;
+ for (ExampleScenarioInstanceVersionComponent version: instance.getVersion()) {
+ if (version.getKey().equals(instanceRef.getVersionReference())) {
+ theVersion = version;
+ break;
+ }
+ }
+ if (theVersion==null)
+ throw new FHIRException("Unable to find referenced version " + instanceRef.getVersionReference() + " within instance " + instanceRef.getInstanceReference());
+ instanceCell.ah("#i_" + instance.getKey() + "v_"+ theVersion.getKey() , theVersion.getDescription()).tx(theVersion.getTitle());
+
+ } else
+ instanceCell.ah("#i_" + instance.getKey(), instance.getDescription()).tx(instance.getTitle());
+ }
+}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java
index 63c076cbf..37cc20ff0 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java
@@ -80,7 +80,30 @@ public class RenderingContext {
BINDINGS, // tree/name + column for each kind of binding found, cells are lists of bindings
OBLIGATIONS, // tree/name + column for each actor that has obligations
}
-
+
+ public enum ExampleScenarioRendererMode {
+ /**
+ * A visual presentation of the questionnaire, with a set of property panes that can be toggled on and off.
+ * Note that this is not the same as how the questionnaire would like on a form filler, since all dynamic behavior is ignored
+ */
+ ACTORS,
+
+ /**
+ * A table listing all the instances (and versions there-of) used in a scenario
+ */
+ INSTANCES,
+
+ /**
+ * Information about the processes (and sub-processes) defined in a scenario
+ */
+ PROCESSES,
+
+ /**
+ * A diagram showing interactions between the actors as part of the process steps
+ */
+ DIAGRAM
+ }
+
public enum QuestionnaireRendererMode {
/**
* A visual presentation of the questionnaire, with a set of property panes that can be toggled on and off.
@@ -146,6 +169,7 @@ public class RenderingContext {
private boolean inlineGraphics;
private StandardsStatus defaultStandardsStatus;
+ private ExampleScenarioRendererMode scenarioMode = null;
private QuestionnaireRendererMode questionnaireMode = QuestionnaireRendererMode.FORM;
private StructureDefinitionRendererMode structureMode = StructureDefinitionRendererMode.SUMMARY;
@@ -211,6 +235,7 @@ public class RenderingContext {
res.definitionsTarget = definitionsTarget;
res.destDir = destDir;
res.addGeneratedNarrativeHeader = addGeneratedNarrativeHeader;
+ res.scenarioMode = scenarioMode;
res.questionnaireMode = questionnaireMode;
res.structureMode = structureMode;
res.header = header;
@@ -440,6 +465,15 @@ public class RenderingContext {
return this;
}
+ public ExampleScenarioRendererMode getScenarioMode() {
+ return scenarioMode;
+ }
+
+ public RenderingContext setScenarioMode(ExampleScenarioRendererMode scenarioMode) {
+ this.scenarioMode = scenarioMode;
+ return this;
+ }
+
public QuestionnaireRendererMode getQuestionnaireMode() {
return questionnaireMode;
}