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