diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..d0fa12e68 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,14 @@ +Validator: + +* Add support for $index on aggregators in FHIRPath +* don't fail with an exception if an unknown resource type appears in contained resource +* improved validation for some value sets that are based on unknown code systems +* add the -verbose parameter, and add additional verbose messages + +Other code changes: + +* Fix rendering of slices so type on slicer is not hidden +* Fix rendering for most resources - remove empty tables (e.g. text element, that shouldn't render) +* Fix NPE rendering code systems with some kinds of properties +* Improve rendering of questionnaires (icons, option sets) + diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java index a4bb9aeeb..fc9efb397 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java @@ -14,6 +14,7 @@ import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.Expression; import org.hl7.fhir.r5.model.Extension; +import org.hl7.fhir.r5.model.PrimitiveType; import org.hl7.fhir.r5.model.Questionnaire; import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; @@ -60,7 +61,11 @@ public class QuestionnaireRenderer extends TerminologyRenderer { public boolean renderTree(XhtmlNode x, Questionnaire q) throws UnsupportedEncodingException, IOException { boolean hasFlags = checkForFlags(q.getItem()); + boolean doOpts = context.getDefinitionsTarget() == null && hasAnyOptions(q.getItem()); + if (doOpts) { + x.b().tx("Structure"); + } HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context.getDestDir(), context.isInlineGraphics(), true); TableModel model = gen.new TableModel("qtree="+q.getId(), !forResource); model.setAlternating(true); @@ -83,9 +88,79 @@ public class QuestionnaireRenderer extends TerminologyRenderer { } XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); x.getChildNodes().add(xn); + if (doOpts) { + renderOptions(q, x); + } return hasExt; } + private void renderOptions(Questionnaire q, XhtmlNode x) { + if (hasAnyOptions(q.getItem())) { + x.hr(); + x.para().b().tx("Option Sets"); + renderOptions(q.getItem(), x); + } + } + + private void renderOptions(List items, XhtmlNode x) { + for (QuestionnaireItemComponent i : items) { + renderItemOptions(x, i); + renderOptions(i.getItem(), x); + } + } + + public void renderItemOptions(XhtmlNode x, QuestionnaireItemComponent i) { + if (i.hasAnswerOption()) { + boolean useSelect = false; + for (QuestionnaireItemAnswerOptionComponent opt : i.getAnswerOption()) { + useSelect = useSelect || opt.getInitialSelected(); + } + x.an("opt-item."+i.getLinkId()); + x.para().b().tx("Answer options for "+i.getLinkId()); + XhtmlNode ul = x.ul(); + for (QuestionnaireItemAnswerOptionComponent opt : i.getAnswerOption()) { + XhtmlNode li = ul.li(); + li.style("font-size: 11px"); + if (useSelect) { + if (opt.getInitialSelected()) { + li.img("icon-selected.png"); + } else { + li.img("icon-not-selected.png"); + } + } + if (opt.getValue().isPrimitive()) { + li.tx(opt.getValue().primitiveValue()); + } else if (opt.getValue() instanceof Coding) { + Coding c = (Coding) opt.getValue(); + String link = context.getWorker().getLinkForUrl(context.getSpecificationLink(), c.getSystem()); + if (link == null) { + li.tx(c.getSystem()+"#"+c.getCode()); + } else { + li.ah(link).tx(describeSystem(c.getSystem())); + li.tx(": "+c.getCode()); + } + if (c.hasDisplay()) { + li.tx(" (\""+c.getDisplay()+"\")"); + } + } else { + li.tx("??"); + } + } + } + } + + private boolean hasAnyOptions(List items) { + for (QuestionnaireItemComponent i : items) { + if (i.hasAnswerOption()) { + return true; + } + if (hasAnyOptions(i.getItem())) { + return true; + } + } + return false; + } + private boolean checkForFlags(List items) { for (QuestionnaireItemComponent i : items) { if (checkForFlags(i)) { @@ -228,7 +303,12 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (i.hasAnswerOption()) { if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); defn.getPieces().add(gen.new Piece(null, "Options: ", null)); - defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); + if (context.getDefinitionsTarget() == null) { + // if we don't have a definitions target, we'll add them below. + defn.getPieces().add(gen.new Piece("#opt-item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); + } else { + defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); + } } if (i.hasInitial()) { for (QuestionnaireItemInitialComponent v : i.getInitial()) { @@ -725,7 +805,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { } } } else if (i.hasAnswerOption()) { - + renderItemOptions(select, i); } select.option("a", "??", false); } diff --git a/pom.xml b/pom.xml index a9e72df6c..d64c81ba9 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 5.1.0 - 1.1.64 + 1.1.65-SNAPSHOT 5.7.1 1.7.1 3.0.0-M4