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