001package org.hl7.fhir.r5.renderers; 002 003import java.io.IOException; 004import java.io.UnsupportedEncodingException; 005import java.util.List; 006 007import org.hl7.fhir.exceptions.DefinitionException; 008import org.hl7.fhir.exceptions.FHIRException; 009import org.hl7.fhir.exceptions.FHIRFormatError; 010import org.hl7.fhir.r5.model.Expression; 011import org.hl7.fhir.r5.model.Questionnaire; 012import org.hl7.fhir.r5.model.QuestionnaireResponse; 013import org.hl7.fhir.r5.model.QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent; 014import org.hl7.fhir.r5.model.QuestionnaireResponse.QuestionnaireResponseItemComponent; 015import org.hl7.fhir.r5.model.Resource; 016import org.hl7.fhir.r5.model.StructureDefinition; 017import org.hl7.fhir.r5.renderers.utils.RenderingContext; 018import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; 019import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; 020import org.hl7.fhir.r5.renderers.utils.ResourceWrapper; 021import org.hl7.fhir.r5.utils.EOperationOutcome; 022import org.hl7.fhir.utilities.Utilities; 023import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; 024import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; 025import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece; 026import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row; 027import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel; 028import org.hl7.fhir.utilities.xhtml.NodeType; 029import org.hl7.fhir.utilities.xhtml.XhtmlNode; 030 031public class QuestionnaireResponseRenderer extends ResourceRenderer { 032 033 public QuestionnaireResponseRenderer(RenderingContext context) { 034 super(context); 035 } 036 037 @Override 038 public String buildSummary(ResourceWrapper r) throws UnsupportedEncodingException, IOException { 039 ResourceWrapper q = r.child("questionnaire"); 040 String qd = q == null ? context.formatPhrase(RenderingContext.QUEST_UNSPECIFIED_QUESTIONNAIRE) : displayCanonical(q); 041 ResourceWrapper s = r.child("subject"); 042 String sd = s == null ? context.formatPhrase(RenderingContext.QUEST_UNSPECIFIED_SUBJECT) : displayReference(s); 043 return context.formatPhrase(RenderingContext.QUEST_SUMMARY, qd, sd); 044 } 045 046 @Override 047 public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper qr) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome { 048 renderResourceTechDetails(qr, x); 049 050 switch (context.getQuestionnaireMode()) { 051 case FORM: 052 renderTree(status, x, qr); 053 break; 054 case LINKS: 055 renderLinks(status, x, qr); 056 break; 057// case LOGIC: return renderLogic(x, q); 058// case DEFNS: return renderDefns(x, q); 059 case TREE: 060 renderTree(status, x, qr); 061 break; 062 default: 063 throw new Error(context.formatPhrase(RenderingContext.QUEST_UNKNOWN_MODE)); 064 } 065 } 066 067 public void renderTree(RenderingStatus status, XhtmlNode x, ResourceWrapper qr) throws UnsupportedEncodingException, IOException { 068 HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true, ""); 069 TableModel model = gen.new TableModel("qtree="+qr.getId(), false); 070 model.setAlternating(true); 071 if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { 072 model.setDocoImg(HierarchicalTableGenerator.help16AsData()); 073 } else { 074 model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); 075 } 076 model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table"); 077 model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.QUEST_LINKID), context.formatPhrase(RenderingContext.QUEST_LINK), null, 0)); 078 model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.QUEST_TEXT), context.formatPhrase(RenderingContext.QUEST_TEXTFOR), null, 0)); 079 model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.GENERAL_DEFINITION), context.formatPhrase(RenderingContext.QUEST_TIMES), null, 0)); 080 model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.QUEST_ANSWER), context.formatPhrase(RenderingContext.QUEST_TYPE_ITEM), null, 0)); 081 082 // first we add a root for the questionaire itself 083 Row row = addTreeRoot(gen, model.getRows(), qr); 084 List<ResourceWrapper> items = qr.children("item"); 085 for (ResourceWrapper i : items) { 086 renderTreeItem(status, gen, row.getSubRows(), qr, i); 087 } 088 XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); 089 x.addChildNode(xn); 090 } 091 092 private Row addTreeRoot(HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper qr) throws IOException { 093 Row r = gen.new Row(); 094 rows.add(r); 095 096 ResourceWrapper b = qr.child("questionnaire"); 097 String ref = b == null ? null : b.primitiveValue(); 098 Questionnaire q = context.getContext().fetchResource(Questionnaire.class, ref); 099 100 r.setIcon("icon_q_root.gif", context.formatPhrase(RenderingContext.QUEST_RESP_ROOT)); 101 r.getCells().add(gen.new Cell(null, null, qr.getId(), null, null)); 102 r.getCells().add(gen.new Cell(null, null, "", null, null)); 103 if (ref == null ) { 104 r.getCells().add(gen.new Cell(null, null, "", null, null)); 105 r.getCells().add(gen.new Cell(context.formatPhrase(RenderingContext.QUEST_QUESTION), null, context.formatPhrase(RenderingContext.QUEST_NONE_SPEC), null, null)); 106 } else if (q == null || !q.hasWebPath()) { 107 r.getCells().add(gen.new Cell(null, null, "", null, null)); 108 r.getCells().add(gen.new Cell(context.formatPhrase(RenderingContext.QUEST_QUESTION), null, ref, null, null)); 109 } else{ 110 r.getCells().add(gen.new Cell(null, null, "", null, null)); 111 r.getCells().add(gen.new Cell(context.formatPhrase(RenderingContext.QUEST_QUESTION), q.getWebPath(), q.present(), null, null)); 112 } 113 return r; 114 } 115 116 private boolean renderTreeItem(RenderingStatus status, HierarchicalTableGenerator gen, List<Row> rows, ResourceWrapper qr, ResourceWrapper i) throws IOException { 117 Row r = gen.new Row(); 118 rows.add(r); 119 boolean hasExt = false; 120 121 List<ResourceWrapper> items = i.children("item"); 122 List<ResourceWrapper> answers = i.children("answer"); 123 boolean hasItem = items != null && !items.isEmpty(); 124 if (answers != null) { 125 for (ResourceWrapper a : answers) { 126 hasItem = a.has("item"); 127 } 128 } 129 if (hasItem) { 130 r.setIcon("icon-q-group.png", context.formatPhrase(RenderingContext.QUEST_GROUP)); 131 } else { 132 r.setIcon("icon-q-string.png", context.formatPhrase(RenderingContext.QUEST_ITEM)); 133 } 134 String linkId = i.has("linkId") ? i.primitiveValue("linkId") : "??"; 135 String text = i.has("text") ? i.primitiveValue("text") : ""; 136 r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+linkId, linkId, null, null)); 137 r.getCells().add(gen.new Cell(null, null, text, null, null)); 138 r.getCells().add(gen.new Cell(null, null, null, null, null)); 139 if (answers == null || answers.size() == 0) { 140 r.getCells().add(gen.new Cell(null, null, null, null, null)); 141 if (items != null) { 142 for (ResourceWrapper si : items) { 143 renderTreeItem(status, gen, r.getSubRows(), qr, si); 144 } 145 } 146 } else if (answers.size() == 1) { 147 ResourceWrapper ans = answers.get(0); 148 renderAnswer(status, gen, qr, r, ans); 149 } else { 150 r.getCells().add(gen.new Cell(null, null, null, null, null)); 151 for (ResourceWrapper ans : answers) { 152 Row ar = gen.new Row(); 153 ar.setIcon("icon-q-string.png", "Item"); 154 ar.getSubRows().add(ar); 155 ar.getCells().add(gen.new Cell(null, null, null, null, null)); 156 ar.getCells().add(gen.new Cell(null, null, text, null, null)); 157 ar.getCells().add(gen.new Cell(null, null, null, null, null)); 158 renderAnswer(status, gen, qr, ar, ans); 159 } 160 } 161 162 return hasExt; 163 } 164 165 public void renderAnswer(RenderingStatus status, HierarchicalTableGenerator gen, ResourceWrapper qr, Row r, ResourceWrapper ans) throws UnsupportedEncodingException, IOException { 166 ResourceWrapper b = ans.child("value[x]"); 167 if (b == null) { 168 r.getCells().add(gen.new Cell(null, null, "null!", null, null)); 169 } else if (b.isPrimitive()) { 170 r.getCells().add(gen.new Cell(null, null, b.primitiveValue(), null, null)); 171 } else { 172 XhtmlNode x = new XhtmlNode(NodeType.Element, "span"); 173 Cell cell = gen.new Cell(null, null, null, null, null); 174 Piece p = gen.new Piece("span"); 175 p.getChildren().add(x); 176 cell.addPiece(p); 177 renderDataType(status, x, b); 178 r.getCells().add(cell); 179 } 180 for (ResourceWrapper si : ans.children("item")) { 181 renderTreeItem(status, gen, r.getSubRows(), qr, si); 182 } 183 } 184 185 private boolean renderTreeItem(HierarchicalTableGenerator gen, List<Row> rows, QuestionnaireResponse q, QuestionnaireResponseItemComponent i) throws IOException { 186 Row r = gen.new Row(); 187 rows.add(r); 188 boolean hasExt = false; 189 190 boolean hasItem = i.hasItem(); 191 for (QuestionnaireResponseItemAnswerComponent a : i.getAnswer()) { 192 hasItem = a.hasItem(); 193 } 194 if (hasItem) { 195 r.setIcon("icon-q-group.png", context.formatPhrase(RenderingContext.QUEST_GROUP)); 196 } else { 197 r.setIcon("icon-q-string.png", context.formatPhrase(RenderingContext.QUEST_ITEM)); 198 } 199 r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); 200 r.getCells().add(gen.new Cell(null, null, i.getText(), null, null)); 201 r.getCells().add(gen.new Cell(null, null, null, null, null)); 202 r.getCells().add(gen.new Cell(null, null, null, null, null)); 203 204 return hasExt; 205 } 206 207 public void genDefinitionLink(HierarchicalTableGenerator gen, QuestionnaireResponseItemComponent i, Cell defn, Resource src) { 208 // can we resolve the definition? 209 String path = null; 210 String d = i.getDefinition(); 211 if (d.contains("#")) { 212 path = d.substring(d.indexOf("#")+1); 213 d = d.substring(0, d.indexOf("#")); 214 } 215 StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, src); 216 if (sd != null) { 217 String url = sd.getWebPath(); 218 if (url != null) { 219 defn.getPieces().add(gen.new Piece(url+"#"+path, path, null)); 220 } else { 221 defn.getPieces().add(gen.new Piece(null, i.getDefinition(), null)); 222 } 223 } else { 224 defn.getPieces().add(gen.new Piece(null, i.getDefinition(), null)); 225 } 226 } 227 228 public void genDefinitionLink(XhtmlNode x, QuestionnaireResponseItemComponent i, Resource src) { 229 // can we resolve the definition? 230 String path = null; 231 String d = i.getDefinition(); 232 if (d.contains("#")) { 233 path = d.substring(d.indexOf("#")+1); 234 d = d.substring(0, d.indexOf("#")); 235 } 236 StructureDefinition sd = context.getWorker().fetchResource(StructureDefinition.class, d, src); 237 if (sd != null) { 238 String url = sd.getWebPath(); 239 if (url != null) { 240 x.ah(context.prefixLocalHref(url+"#"+path)).tx(path); 241 } else { 242 x.tx(i.getDefinition()); 243 } 244 } else { 245 x.tx(i.getDefinition()); 246 } 247 } 248 249 private void addExpression(Piece p, Expression exp, String label, String url) { 250 XhtmlNode x = new XhtmlNode(NodeType.Element, "li").style("font-size: 11px"); 251 p.addHtml(x); 252 x.ah(context.prefixLocalHref(url)).tx(label); 253 x.tx(": "); 254 x.code(exp.getExpression()); 255 } 256 257 public boolean renderForm(XhtmlNode x, QuestionnaireResponse q) throws UnsupportedEncodingException, IOException { 258 boolean hasExt = false; 259// XhtmlNode d = x.div(); 260// boolean hasPrefix = false; 261// for (QuestionnaireItemComponent c : q.getItem()) { 262// hasPrefix = hasPrefix || doesItemHavePrefix(c); 263// } 264// int i = 1; 265// for (QuestionnaireItemComponent c : q.getItem()) { 266// hasExt = renderFormItem(d, q, c, hasPrefix ? null : Integer.toString(i), 0) || hasExt; 267// i++; 268// } 269// return hasExt; 270// } 271// 272// private boolean doesItemHavePrefix(QuestionnaireItemComponent i) { 273// if (i.hasPrefix()) { 274// return true; 275// } 276// for (QuestionnaireItemComponent c : i.getItem()) { 277// if (doesItemHavePrefix(c)) { 278// return true; 279// } 280// } 281 return false; 282 } 283 284 public boolean renderForm(XhtmlNode x, ResourceWrapper q) throws UnsupportedEncodingException, IOException { 285 boolean hasExt = false; 286 XhtmlNode d = x.div(); 287 d.tx(context.formatPhrase(RenderingContext.GENERAL_TODO)); 288// boolean hasPrefix = false; 289// for (QuestionnaireItemComponent c : q.getItem()) { 290// hasPrefix = hasPrefix || doesItemHavePrefix(c); 291// } 292// int i = 1; 293// for (QuestionnaireItemComponent c : q.getItem()) { 294// hasExt = renderFormItem(d, q, c, hasPrefix ? null : Integer.toString(i), 0) || hasExt; 295// i++; 296// } 297// return hasExt; 298// } 299// 300// private boolean doesItemHavePrefix(QuestionnaireItemComponent i) { 301// if (i.hasPrefix()) { 302// return true; 303// } 304// for (QuestionnaireItemComponent c : i.getItem()) { 305// if (doesItemHavePrefix(c)) { 306// return true; 307// } 308// } 309 return hasExt; 310 } 311 312// private boolean renderFormItem(XhtmlNode x, QuestionnaireResponse q, QuestionnaireItemComponent i, String pfx, int indent) throws IOException { 313// boolean hasExt = false; 314// XhtmlNode d = x.div().style("width: "+Integer.toString(900-indent*10)+"px; border-top: 1px #eeeeee solid"); 315// if (indent > 0) { 316// d.style("margin-left: "+Integer.toString(10*indent)+"px"); 317// } 318// XhtmlNode display = d.div().style("display: inline-block; width: "+Integer.toString(500-indent*10)+"px"); 319// XhtmlNode details = d.div().style("border: 1px #ccccff solid; padding: 2px; display: inline-block; background-color: #fefce7; width: 380px"); 320// XhtmlNode p = display.para(); 321// if (i.getType() == QuestionnaireItemType.GROUP) { 322// p = p.b(); 323// } 324// if (i.hasPrefix()) { 325// p.tx(i.getPrefix()); 326// p.tx(": "); 327// } 328// p.span(null, "linkId: "+i.getLinkId()).tx(i.getText()); 329// if (i.getRequired()) { 330// p.span("color: red", context.formatPhrase(RenderingContext.QUEST_MAND)).tx("*"); 331// } 332// 333// XhtmlNode input = null; 334// switch (i.getType()) { 335// case STRING: 336// p.tx(" "); 337// input = p.input(i.getLinkId(), "text", i.getType().getDisplay(), 60); 338// break; 339// case ATTACHMENT: 340// break; 341// case BOOLEAN: 342// p.tx(" "); 343// input = p.input(i.getLinkId(), "checkbox", i.getType().getDisplay(), 1); 344// break; 345// case CHOICE: 346// input = p.select(i.getLinkId()); 347// listOptions(q, i, input); 348// break; 349// case DATE: 350// p.tx(" "); 351// input = p.input(i.getLinkId(), "date", i.getType().getDisplay(), 10); 352// break; 353// case DATETIME: 354// p.tx(" "); 355// input = p.input(i.getLinkId(), "datetime-local", i.getType().getDisplay(), 25); 356// break; 357// case DECIMAL: 358// p.tx(" "); 359// input = p.input(i.getLinkId(), "number", i.getType().getDisplay(), 15); 360// break; 361// case DISPLAY: 362// break; 363// case GROUP: 364// 365// break; 366// case INTEGER: 367// p.tx(" "); 368// input = p.input(i.getLinkId(), "number", i.getType().getDisplay(), 10); 369// break; 370// case OPENCHOICE: 371// break; 372// case QUANTITY: 373// p.tx(" "); 374// input = p.input(i.getLinkId(), "number", "value", 15); 375// p.tx(" "); 376// input = p.input(i.getLinkId(), "unit", "unit", 10); 377// break; 378// case QUESTION: 379// break; 380// case REFERENCE: 381// break; 382// case TEXT: 383// break; 384// case TIME: 385// break; 386// case URL: 387// break; 388// default: 389// break; 390// } 391// if (input != null) { 392// if (i.getReadOnly()) { 393// input.attribute("readonly", "1"); 394// input.style("background-color: #eeeeee"); 395// } 396// } 397// 398//// if (i.hasExtension(" http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-choiceOrientation")) { 399//// String code = ToolingExtensions.readStringExtension(i, "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-choiceOrientation"); 400//// flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("alt", "icon").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png")))); 401////} 402// 403// 404// XhtmlNode ul = details.ul(); 405// boolean hasFlag = false; 406// XhtmlNode flags = item(ul, "Flags"); 407// item(ul, "linkId", i.getLinkId()); 408// 409// if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-isSubject")) { 410// hasFlag = true; 411// flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-isSubject", "Can change the subject of the QuestionnaireResponse").img(Utilities.path(context.getLocalPrefix(), "icon-qi-subject.png")); 412// } 413// if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-hidden")) { 414// hasFlag = true; 415// flags.ah(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "extension-QuestionnaireResponse-hidden.html"), "Is a hidden item").img(Utilities.path(context.getLocalPrefix(), "icon-qi-hidden.png")); 416// d.style("background-color: #eeeeee"); 417// } 418// if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-optionalDisplay")) { 419// hasFlag = true; 420// flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-optionalDisplay", "Is optional to display").img(Utilities.path(context.getLocalPrefix(), "icon-qi-optional.png")); 421// } 422// if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod")) { 423// hasFlag = true; 424// flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod", "Is linked to an observation").img(Utilities.path(context.getLocalPrefix(), "icon-qi-observation.png")); 425// } 426// if (i.hasExtension(" http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory")) { 427// CodeableConcept cc = i.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory").getValueCodeableConcept(); 428// String code = cc.getCode("http://hl7.org/fhir/QuestionnaireResponse-display-category"); 429// hasFlag = true; 430// flags.ah("https://hl7.org/fhir/R4/extension-questionnaire-displayCategory.html", "Category: "+code).img(Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png")); 431// } 432// 433// if (i.hasMaxLength()) { 434// item(ul, "Max Length", Integer.toString(i.getMaxLength())); 435// } 436// if (i.hasDefinition()) { 437// genDefinitionLink(item(ul, "Definition"), i); 438// } 439// if (i.hasEnableWhen()) { 440// item(ul, "Enable When", "todo"); 441// } 442// if (i.hasAnswerValueSet()) { 443// XhtmlNode ans = item(ul, "Answers"); 444// if (i.getAnswerValueSet().startsWith("#")) { 445// ValueSet vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)); 446// if (vs == null) { 447// ans.tx(i.getAnswerValueSet()); 448// } else { 449// ans.ah(vs.getWebPath()).tx(vs.present()); 450// } 451// } else { 452// ValueSet vs = context.getWorker().findTxResource(ValueSet.class, i.getAnswerValueSet()); 453// if (vs == null || !vs.hasWebPath()) { 454// ans.tx(i.getAnswerValueSet()); 455// } else { 456// ans.ah(vs.getWebPath()).tx(vs.present()); 457// } 458// } 459// } 460// if (i.hasAnswerOption()) { 461// item(ul, "Answers", Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), context.getDefinitionsTarget()+"#item."+i.getLinkId()); 462// } 463// if (i.hasInitial()) { 464// XhtmlNode vi = item(ul, "Initial Values"); 465// boolean first = true; 466// for (QuestionnaireItemInitialComponent v : i.getInitial()) { 467// if (first) first = false; else vi.tx(", "); 468// if (v.getValue().isPrimitive()) { 469// vi.tx(v.getValue().primitiveValue()); 470// } else { 471// vi.tx("{todo}"); 472// } 473// } 474// } 475// if (!hasFlag) { 476// ul.remove(flags); 477// } 478//// if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-enableWhenExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-itemContext") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-calculatedExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-contextExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-candidateExpression") || i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-initialExpression")) { 479//// if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); 480//// defn.getPieces().add(gen.new Piece(null, "Expressions: ", null)); 481//// Piece p = gen.new Piece("ul"); 482//// defn.getPieces().add(p); 483//// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-initialExpression")) { 484//// addExpression(p, e.getValueExpression(), "Initial Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-initialExpression"); 485//// } 486//// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-contextExpression")) { 487//// addExpression(p, e.getValueExpression(), "Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-contextExpression"); 488//// } 489//// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-itemContext")) { 490//// addExpression(p, e.getValueExpression(), "Item Context", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-itemContext"); 491//// } 492//// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-enableWhenExpression")) { 493//// addExpression(p, e.getValueExpression(), "Enable When", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-enableWhenExpression"); 494//// } 495//// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-calculatedExpression")) { 496//// addExpression(p, e.getValueExpression(), "Calculated Value", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-calculatedExpression"); 497//// } 498//// for (Extension e : i.getExtensionsByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-candidateExpression")) { 499//// addExpression(p, e.getValueExpression(), "Candidates", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-candidateExpression"); 500//// } 501//// } 502//// 503// 504// int t = 1; 505// for (QuestionnaireItemComponent c : i.getItem()) { 506// hasExt = renderFormItem(x, q, c, pfx == null ? null : pfx+"."+Integer.toString(t), indent+1) || hasExt; 507// t++; 508// } 509// return hasExt; 510// } 511// 512// private void item(XhtmlNode ul, String name, String value, String valueLink) { 513// if (!Utilities.noString(value)) { 514// ul.li().style("font-size: 10px").ah(valueLink).tx(name+": "+value); 515// } 516// } 517// 518// private void item(XhtmlNode ul, String name, String value) { 519// if (!Utilities.noString(value)) { 520// ul.li().style("font-size: 10px").tx(name+": "+value); 521// } 522// } 523// private XhtmlNode item(XhtmlNode ul, String name) { 524// XhtmlNode li = ul.li(); 525// li.style("font-size: 10px").tx(name+": "); 526// return li; 527// } 528// 529// 530// private void listOptions(QuestionnaireResponse q, QuestionnaireItemComponent i, XhtmlNode select) { 531// if (i.hasAnswerValueSet()) { 532// ValueSet vs = null; 533// if (i.getAnswerValueSet().startsWith("#")) { 534// vs = (ValueSet) q.getContained(i.getAnswerValueSet().substring(1)).copy(); 535// if (vs != null && !vs.hasUrl()) { 536// vs.setUrl("urn:uuid:"+UUID.randomUUID().toString().toLowerCase()); 537// } 538// } else { 539// vs = context.getContext().findTxResource(ValueSet.class, i.getAnswerValueSet()); 540// } 541// if (vs != null) { 542// ValueSetExpansionOutcome exp = context.getContext().expandVS(vs, true, false); 543// if (exp.getValueset() != null) { 544// for (ValueSetExpansionContainsComponent cc : exp.getValueset().getExpansion().getContains()) { 545// select.option(cc.getCode(), cc.hasDisplay() ? cc.getDisplay() : cc.getCode(), false); 546// } 547// return; 548// } 549// } 550// } else if (i.hasAnswerOption()) { 551// 552// } 553// select.option("a", "??", false); 554// } 555// 556// public String display(Resource dr) throws UnsupportedEncodingException, IOException { 557// return display((QuestionnaireResponse) dr); 558// } 559// 560// public String display(QuestionnaireResponse q) throws UnsupportedEncodingException, IOException { 561// return "QuestionnaireResponse "+q.present(); 562// } 563// 564 private boolean renderLinks(RenderingStatus status, XhtmlNode x, ResourceWrapper q) { 565 x.para().tx(context.formatPhrase(RenderingContext.QUEST_TRY_QUEST)); 566 XhtmlNode ul = x.ul(); 567 ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx(context.formatPhrase(RenderingContext.QUEST_NLM)); 568 return false; 569 } 570 571// private boolean renderDefns(XhtmlNode x, QuestionnaireResponse q) throws IOException { 572// XhtmlNode tbl = x.table("dict"); 573// boolean ext = false; 574// ext = renderRootDefinition(tbl, q, new ArrayList<>()) || ext; 575// for (QuestionnaireItemComponent qi : q.getItem()) { 576// ext = renderDefinition(tbl, q, qi, new ArrayList<>()) || ext; 577// } 578// return ext; 579// } 580// 581// private boolean renderRootDefinition(XhtmlNode tbl, QuestionnaireResponse q, List<QuestionnaireItemComponent> parents) throws IOException { 582// boolean ext = false; 583// XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent"); 584// td.an(q.getId()); 585// td.img(Utilities.path(context.getLocalPrefix(), "icon_q_root.gif")); 586// td.tx(" QuestionnaireResponse "); 587// td.b().tx(q.getId()); 588// 589// // general information 590// defn(tbl, "URL", q.getUrl()); 591// defn(tbl, "Version", q.getVersion()); 592// defn(tbl, "Name", q.getName()); 593// defn(tbl, "Title", q.getTitle()); 594// if (q.hasDerivedFrom()) { 595// td = defn(tbl, "Derived From"); 596// boolean first = true; 597// for (CanonicalType c : q.getDerivedFrom()) { 598// if (first) first = false; else td.tx(", "); 599// td.tx(c.asStringValue()); // todo: make these a reference 600// } 601// } 602// defn(tbl, "Status", q.getStatus().getDisplay()); 603// defn(tbl, "Experimental", q.getExperimental()); 604// defn(tbl, "Publication Date", q.getDateElement().primitiveValue()); 605// defn(tbl, "Approval Date", q.getApprovalDateElement().primitiveValue()); 606// defn(tbl, "Last Review Date", q.getLastReviewDateElement().primitiveValue()); 607// if (q.hasEffectivePeriod()) { 608// renderPeriod(defn(tbl, "Effective Period"), q.getEffectivePeriod()); 609// } 610// 611// if (q.hasSubjectType()) { 612// td = defn(tbl, "Subject Type"); 613// boolean first = true; 614// for (CodeType c : q.getSubjectType()) { 615// if (first) first = false; else td.tx(", "); 616// td.tx(c.asStringValue()); 617// } 618// } 619// defn(tbl, "Description", q.getDescription()); 620// defn(tbl, "Purpose", q.getPurpose()); 621// defn(tbl, "Copyright", q.getCopyright()); 622// if (q.hasCode()) { 623// td = defn(tbl, Utilities.pluralize("Code", q.getCode().size())); 624// boolean first = true; 625// for (Coding c : q.getCode()) { 626// if (first) first = false; else td.tx(", "); 627// renderCodingWithDetails(td, c); 628// } 629// } 630// return false; 631// } 632 633// private boolean renderDefinition(XhtmlNode tbl, QuestionnaireResponse q, QuestionnaireItemComponent qi, List<QuestionnaireItemComponent> parents) throws IOException { 634// boolean ext = false; 635// XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent"); 636// td.an("item."+qi.getLinkId()); 637// for (QuestionnaireItemComponent p : parents) { 638// td.ah("#item."+p.getLinkId()).img(Utilities.path(context.getLocalPrefix(), "icon_q_item.png")); 639// td.tx(" > "); 640// } 641// td.img(Utilities.path(context.getLocalPrefix(), "icon_q_item.png")); 642// td.tx(" Item "); 643// td.b().tx(qi.getLinkId()); 644// 645// // general information 646// defn(tbl, "Link Id", qi.getLinkId()); 647// defn(tbl, "Prefix", qi.getPrefix()); 648// defn(tbl, "Text", qi.getText()); 649// defn(tbl, "Type", qi.getType().getDisplay()); 650// defn(tbl, "Required", qi.getRequired(), true); 651// defn(tbl, "Repeats", qi.getRepeats(), true); 652// defn(tbl, "Read Only", qi.getReadOnly(), false); 653// if (ToolingExtensions.readBoolExtension(qi, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-isSubject")) { 654// defn(tbl, "Subject", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-isSubject", "This element changes who the subject of the question is", null); 655// } 656// 657// // content control 658// defn(tbl, "Max Length", qi.getMaxLength()); 659// if (qi.hasAnswerValueSet()) { 660// defn(tbl, "Value Set", qi.getDefinition(), context.getWorker().findTxResource(ValueSet.class, qi.getAnswerValueSet())); 661// } 662// if (qi.hasAnswerOption()) { 663// XhtmlNode tr = tbl.tr(); 664// tr.td().tx(context.formatPhrase(RenderingContext.QUEST_ALLOWED)); 665// XhtmlNode ul = tr.td().ul(); 666// for (QuestionnaireItemAnswerOptionComponent ans : qi.getAnswerOption()) { 667// XhtmlNode li = ul.li(); 668// render(li, ans.getValue()); 669// if (ans.getInitialSelected()) { 670// li.tx(context.formatPhrase(RenderingContext.QUEST_INITIALLY)); 671// } 672// } 673// } 674// if (qi.hasInitial()) { 675// XhtmlNode tr = tbl.tr(); 676// tr.td().tx(Utilities.pluralize("Initial Answer", qi.getInitial().size())); 677// if (qi.getInitial().size() == 1) { 678// render(tr.td(), qi.getInitialFirstRep().getValue()); 679// } else { 680// XhtmlNode ul = tr.td().ul(); 681// for (QuestionnaireItemInitialComponent ans : qi.getInitial()) { 682// XhtmlNode li = ul.li(); 683// render(li, ans.getValue()); 684// } 685// } 686// } 687// 688// // appearance 689// if (qi.hasExtension(" http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory")) { 690// XhtmlNode tr = tbl.tr(); 691// tr.td().ah("http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory").tx(context.formatPhrase(RenderingContext.QUEST_DISPLAY_CAT)); 692// render(tr.td(), qi.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory").getValue()); 693// } 694// if (ToolingExtensions.readBoolExtension(qi, "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-hidden")) { 695// defn(tbl, "Hidden Item", "https://hl7.org/fhir/R4/extension-questionnaire-displayCategory.html", "This item is a hidden question", null); 696// } 697// if (ToolingExtensions.readBoolExtension(qi, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-optionalDisplay")) { 698// defn(tbl, "Hidden Item", "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-optionalDisplay", "This item is optional to display", null); 699// } 700// 701// // formal definitions 702// if (qi.hasDefinition()) { 703// genDefinitionLink(defn(tbl, "Definition"), qi); 704// } 705// 706// if (qi.hasCode()) { 707// XhtmlNode tr = tbl.tr(); 708// tr.td().tx(Utilities.pluralize("Code", qi.getCode().size())); 709// XhtmlNode ul = tr.td().ul(); 710// for (Coding c : qi.getCode()) { 711// renderCodingWithDetails(ul.li(), c); 712// } 713// } 714// if (qi.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod")) { 715// XhtmlNode tr = tbl.tr(); 716// tr.td().ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod").tx(context.formatPhrase(RenderingContext.QUEST_OBSERVATION)); 717// render(tr.td(), qi.getExtensionByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod").getValue()); 718// } 719// 720// // dynamic management 721// if (qi.hasEnableWhen()) { 722// XhtmlNode tr = tbl.tr(); 723// tr.td().tx(context.formatPhrase(RenderingContext.QUEST_ENABLE)); 724// td = tr.td(); 725// if (qi.getEnableWhen().size() == 1) { 726// renderEnableWhen(td, qi.getEnableWhen().get(0)); 727// } else { 728// td.tx(qi.getEnableBehavior().getDisplay()+" are true:"); 729// XhtmlNode ul = td.ul(); 730// for (QuestionnaireItemEnableWhenComponent ew : qi.getEnableWhen()) { 731// renderEnableWhen(ul.li(), ew); 732// } 733// } 734// } 735// 736// 737// // other stuff 738// 739// 740// 741// List<QuestionnaireItemComponent> curr = new ArrayList<>(); 742// curr.addAll(parents); 743// curr.add(qi); 744// for (QuestionnaireItemComponent qic : qi.getItem()) { 745// ext = renderDefinition(tbl, q, qic, curr) || ext; 746// } 747// return ext; 748// } 749// 750// private void defn(XhtmlNode tbl, String name, String url, Resource res) throws UnsupportedEncodingException, IOException { 751// if (res != null && res.hasWebPath()) { 752// defn(tbl, "Definition", RendererFactory.factory(res, context).display(res), res.getWebPath()); 753// } else if (Utilities.isAbsoluteUrl(url)) { 754// defn(tbl, "Definition", url, url); 755// } { 756// defn(tbl, "Definition", url); 757// } 758// 759// } 760// 761// private void renderEnableWhen(XhtmlNode x, QuestionnaireItemEnableWhenComponent ew) { 762// x.ah("#item."+ew.getQuestion()).tx(ew.getQuestion()); 763// x.tx(" "); 764// x.tx(ew.getOperator().toCode()); 765// x.tx(" "); 766// x.tx(display(ew.getAnswer())); 767// } 768// 769// private XhtmlNode defn(XhtmlNode tbl, String name) { 770// XhtmlNode tr = tbl.tr(); 771// tr.td().tx(name); 772// return tr.td(); 773// } 774// 775// private void defn(XhtmlNode tbl, String name, int value) { 776// if (value > 0) { 777// XhtmlNode tr = tbl.tr(); 778// tr.td().tx(name); 779// tr.td().tx(value); 780// } 781// } 782// 783// 784// private void defn(XhtmlNode tbl, String name, boolean value) { 785// XhtmlNode tr = tbl.tr(); 786// tr.td().tx(name); 787// tr.td().tx(Boolean.toString(value)); 788// } 789// 790// private void defn(XhtmlNode tbl, String name, String value) { 791// if (!Utilities.noString(value)) { 792// XhtmlNode tr = tbl.tr(); 793// tr.td().tx(name); 794// tr.td().tx(value); 795// } 796// } 797// 798// private void defn(XhtmlNode tbl, String name, String value, String url) { 799// if (!Utilities.noString(value)) { 800// XhtmlNode tr = tbl.tr(); 801// tr.td().tx(name); 802// tr.td().ah(url).tx(value); 803// } 804// } 805// 806// private void defn(XhtmlNode tbl, String name, String nurl, String value, String url) { 807// if (!Utilities.noString(value)) { 808// XhtmlNode tr = tbl.tr(); 809// tr.td().ah(nurl).tx(name); 810// if (url != null) { 811// tr.td().ah(url).tx(value); 812// } else { 813// tr.td().tx(value); 814// } 815// } 816// } 817// 818// private void defn(XhtmlNode tbl, String name, boolean value, boolean ifFalse) { 819// if (ifFalse || value) { 820// XhtmlNode tr = tbl.tr(); 821// tr.td().tx(name); 822// tr.td().tx(Boolean.toString(value)); 823// } 824// } 825 826 827}