diff --git a/Model/lib/rng/wdkModel.rng b/Model/lib/rng/wdkModel.rng
index a1524fa48..b76975532 100644
--- a/Model/lib/rng/wdkModel.rng
+++ b/Model/lib/rng/wdkModel.rng
@@ -1685,6 +1685,10 @@
+
+
+
+
@@ -1709,6 +1713,10 @@
+
+
+
+
diff --git a/Model/src/main/java/org/gusdb/wdk/core/api/JsonKeys.java b/Model/src/main/java/org/gusdb/wdk/core/api/JsonKeys.java
index 667b21465..abcaba552 100644
--- a/Model/src/main/java/org/gusdb/wdk/core/api/JsonKeys.java
+++ b/Model/src/main/java/org/gusdb/wdk/core/api/JsonKeys.java
@@ -61,6 +61,7 @@ public class JsonKeys {
public static final String HELP = "help";
public static final String HTML_HELP = "htmlHelp";
public static final String SUGGEST_TEXT = "suggestText";
+ public static final String TOOLTIP = "tooltip";
public static final String DESCRIPTION = "description";
public static final String SHORT_DESCRIPTION = "shortDescription";
public static final String SUMMARY = "summary";
diff --git a/Model/src/main/java/org/gusdb/wdk/model/ModelXmlParser.java b/Model/src/main/java/org/gusdb/wdk/model/ModelXmlParser.java
index 2a809961c..34ea8a791 100644
--- a/Model/src/main/java/org/gusdb/wdk/model/ModelXmlParser.java
+++ b/Model/src/main/java/org/gusdb/wdk/model/ModelXmlParser.java
@@ -1038,6 +1038,8 @@ private static void configureAttributeFields(Digester digester) {
digester.addCallMethod("*/linkAttribute/url", "setText", 0);
configureNode(digester, "*/linkAttribute/displayText", WdkModelText.class, "addDisplayText");
digester.addCallMethod("*/linkAttribute/displayText", "setText", 0);
+ configureNode(digester, "*/linkAttribute/tooltip", WdkModelText.class, "addTooltip");
+ digester.addCallMethod("*/linkAttribute/tooltip", "setText", 0);
configureAttributeReporters(digester, "linkAttribute");
// text attribute
@@ -1047,6 +1049,8 @@ private static void configureAttributeFields(Digester digester) {
digester.addCallMethod("*/textAttribute/text", "setText", 0);
configureNode(digester, "*/textAttribute/display", WdkModelText.class, "addDisplay");
digester.addCallMethod("*/textAttribute/display", "setText", 0);
+ configureNode(digester, "*/linkAttribute/tooltip", WdkModelText.class, "addTooltip");
+ digester.addCallMethod("*/linkAttribute/tooltip", "setText", 0);
configureAttributeReporters(digester, "textAttribute");
}
diff --git a/Model/src/main/java/org/gusdb/wdk/model/record/attribute/LinkAttributeField.java b/Model/src/main/java/org/gusdb/wdk/model/record/attribute/LinkAttributeField.java
index 69d06f556..57408482c 100644
--- a/Model/src/main/java/org/gusdb/wdk/model/record/attribute/LinkAttributeField.java
+++ b/Model/src/main/java/org/gusdb/wdk/model/record/attribute/LinkAttributeField.java
@@ -33,12 +33,14 @@ public class LinkAttributeField extends DerivedAttributeField {
private static final String DEFAULT_TYPE = "link";
// fields set by XML parsing
- private List _urls = new ArrayList();
- private List _displayTexts = new ArrayList();
+ private List _urls = new ArrayList<>();
+ private List _displayTexts = new ArrayList<>();
+ private List _tooltips = new ArrayList<>();
// resolved fields
private String _url;
private String _displayText;
+ private String _tooltip;
private boolean _newWindow = false;
@@ -78,11 +80,20 @@ public String getDisplayText() {
return _displayText;
}
+ public void addTooltip(WdkModelText tooltip) {
+ _tooltips.add(tooltip);
+ }
+
+ public String getTooltip() {
+ return _tooltip == null ? "" : _tooltip;
+ }
+
@Override
public void excludeResources(String projectId) throws WdkModelException {
super.excludeResources(projectId);
_url = excludeModelText(_urls, projectId, "url", true);
_displayText = excludeModelText(_displayTexts, projectId, "displayText", true);
+ _tooltip = excludeModelText(_tooltips, projectId, "tooltip", false);
}
@Override
@@ -90,6 +101,7 @@ protected Collection getDependencies() throws WdkModelException
Map dependents = new LinkedHashMap<>();
if (_displayText != null) dependents.putAll(parseFields(_displayText));
if (_url != null) dependents.putAll(parseFields(_url));
+ if (_tooltip != null) dependents.putAll(parseFields(_tooltip));
return dependents.values();
}
}
diff --git a/Model/src/main/java/org/gusdb/wdk/model/record/attribute/LinkAttributeValue.java b/Model/src/main/java/org/gusdb/wdk/model/record/attribute/LinkAttributeValue.java
index 8c2fd5b48..f50d968c4 100644
--- a/Model/src/main/java/org/gusdb/wdk/model/record/attribute/LinkAttributeValue.java
+++ b/Model/src/main/java/org/gusdb/wdk/model/record/attribute/LinkAttributeValue.java
@@ -19,6 +19,7 @@ public class LinkAttributeValue extends DerivedAttributeValue {
private String _displayText;
private String _url;
+ private String _tooltip;
public LinkAttributeValue(LinkAttributeField field, AttributeValueContainer container) {
super(field, container);
@@ -38,6 +39,13 @@ public String getUrl() throws WdkModelException, WdkUserException {
return _url;
}
+ public String getTooltip() throws WdkModelException, WdkUserException {
+ if (_tooltip == null) {
+ _tooltip = populateMacros(((TextAttributeField)_field).getTooltip());
+ }
+ return _tooltip;
+ }
+
/**
* Get the text representation of the url (e.g. for reports).
*/
diff --git a/Model/src/main/java/org/gusdb/wdk/model/record/attribute/TextAttributeField.java b/Model/src/main/java/org/gusdb/wdk/model/record/attribute/TextAttributeField.java
index e59f312dd..d676e682d 100644
--- a/Model/src/main/java/org/gusdb/wdk/model/record/attribute/TextAttributeField.java
+++ b/Model/src/main/java/org/gusdb/wdk/model/record/attribute/TextAttributeField.java
@@ -22,14 +22,17 @@ public class TextAttributeField extends DerivedAttributeField {
// fields set by XML parsing
private final List _texts;
private final List _displays;
+ private final List _tooltips;
// resolved fields
private String _text;
private String _display;
+ private String _tooltip;
public TextAttributeField() {
_texts = new ArrayList<>();
_displays = new ArrayList<>();
+ _tooltips = new ArrayList<>();
_dataType = AttributeFieldDataType.STRING;
}
@@ -49,11 +52,20 @@ public String getDisplay() {
return (_display != null) ? _display : _text;
}
+ public void addTooltip(WdkModelText tooltip) {
+ _tooltips.add(tooltip);
+ }
+
+ public String getTooltip() {
+ return _tooltip == null ? "" : _tooltip;
+ }
+
@Override
public void excludeResources(String projectId) throws WdkModelException {
super.excludeResources(projectId);
_text = excludeModelText(_texts, projectId, "text", true);
_display = excludeModelText(_displays, projectId, "display", false);
+ _tooltip = excludeModelText(_tooltips, projectId, "tooltip", false);
}
@Override
@@ -62,6 +74,7 @@ public Collection getDependencies() throws WdkModelException {
Map dependents = new LinkedHashMap<>();
if (_display!= null) dependents.putAll(parseFields(_display));
if (_text != null) dependents.putAll(parseFields(_text));
+ if (_tooltip != null) dependents.putAll(parseFields(_tooltip));
return dependents.values();
}
}
diff --git a/Model/src/main/java/org/gusdb/wdk/model/record/attribute/TextAttributeValue.java b/Model/src/main/java/org/gusdb/wdk/model/record/attribute/TextAttributeValue.java
index 7a6fe10eb..320538a51 100644
--- a/Model/src/main/java/org/gusdb/wdk/model/record/attribute/TextAttributeValue.java
+++ b/Model/src/main/java/org/gusdb/wdk/model/record/attribute/TextAttributeValue.java
@@ -25,6 +25,11 @@ public class TextAttributeValue extends DerivedAttributeValue {
*/
private String _display;
+ /**
+ * Optional value that can be used to display extra information about this data value in a UI.
+ */
+ private String _tooltip;
+
/**
* @param field
* @param container
@@ -49,4 +54,10 @@ public String getDisplay() throws WdkModelException, WdkUserException {
return _display;
}
+ public String getTooltip() throws WdkModelException, WdkUserException {
+ if (_tooltip == null) {
+ _tooltip = populateMacros(((TextAttributeField)_field).getTooltip());
+ }
+ return _tooltip;
+ }
}
diff --git a/Model/src/main/java/org/gusdb/wdk/model/report/config/AnswerDetails.java b/Model/src/main/java/org/gusdb/wdk/model/report/config/AnswerDetails.java
index 8b4711323..bfc6c14cd 100644
--- a/Model/src/main/java/org/gusdb/wdk/model/report/config/AnswerDetails.java
+++ b/Model/src/main/java/org/gusdb/wdk/model/report/config/AnswerDetails.java
@@ -15,7 +15,7 @@ public class AnswerDetails {
public static final Integer ALL_RECORDS = -1;
public enum AttributeFormat {
- TEXT, DISPLAY;
+ TEXT, DISPLAY, EXPANDED;
}
// use factory method to construct from JSON
diff --git a/Model/src/main/java/org/gusdb/wdk/model/report/config/AnswerDetailsFactory.java b/Model/src/main/java/org/gusdb/wdk/model/report/config/AnswerDetailsFactory.java
index b28c362d9..f72227ee3 100644
--- a/Model/src/main/java/org/gusdb/wdk/model/report/config/AnswerDetailsFactory.java
+++ b/Model/src/main/java/org/gusdb/wdk/model/report/config/AnswerDetailsFactory.java
@@ -81,7 +81,7 @@ public static AnswerDetails createDefault(Question question) {
* tables: [ tableName: String ], or special string,
* sorting: [ { attributeName: String, direction: Enum[ASC,DESC] } ],
* contentDisposition: 'inline' (default) OR 'attachment'
- * attributeFormat: 'display' (default) OR 'text'
+ * attributeFormat: 'display' (default) OR 'text' OR 'expanded'
* }
*
* All values are optional.
diff --git a/Model/src/main/java/org/gusdb/wdk/model/report/util/RecordFormatter.java b/Model/src/main/java/org/gusdb/wdk/model/report/util/RecordFormatter.java
index 2c0dce59b..5165078ce 100644
--- a/Model/src/main/java/org/gusdb/wdk/model/report/util/RecordFormatter.java
+++ b/Model/src/main/java/org/gusdb/wdk/model/report/util/RecordFormatter.java
@@ -109,33 +109,40 @@ public static JSONArray getTableRowsJson(RecordInstance record, String tableName
private static Object getAttributeValueJson(AttributeValue attr, AttributeFormat attributeFormat) throws WdkModelException, WdkUserException {
- if (attributeFormat == AttributeFormat.DISPLAY) {
- // for display format, show
- if (attr instanceof LinkAttributeValue) {
- LinkAttributeValue linkAttr = (LinkAttributeValue)attr;
- String displayText = linkAttr.getDisplayText();
-
- // Treat an empty displayText as null
- if (displayText == null || displayText.isEmpty()) {
- return JSONObject.NULL;
- }
-
- return new JSONObject()
- .put(JsonKeys.URL, linkAttr.getUrl())
- .put(JsonKeys.DISPLAY_TEXT, displayText);
- }
-
- if (attr instanceof TextAttributeValue){
- return attr.getDisplay();
+ if (attr instanceof LinkAttributeValue ) {
+ LinkAttributeValue linkAttr = (LinkAttributeValue)attr;
+ switch(attributeFormat) {
+ case TEXT:
+ return linkAttr.getUrl();
+ case DISPLAY:
+ case EXPANDED:
+ // return JSON object with each of the values for proper display in a UI
+ return new JSONObject()
+ .put(JsonKeys.URL, linkAttr.getUrl())
+ .put(JsonKeys.DISPLAY_TEXT, linkAttr.getDisplayText())
+ .put(JsonKeys.TOOLTIP, nullIfEmpty(linkAttr.getTooltip()));
}
}
- else {
- if (attr instanceof LinkAttributeValue) {
- return ((LinkAttributeValue)attr).getUrl();
+
+ if (attr instanceof TextAttributeValue) {
+ TextAttributeValue textAttr = (TextAttributeValue)attr;
+ switch(attributeFormat) {
+ case TEXT: return nullIfEmpty(textAttr.getValue());
+ case DISPLAY: return textAttr.getDisplay();
+ case EXPANDED:
+ // return JSON object with each of the values for proper display in a UI
+ return new JSONObject()
+ .put(JsonKeys.VALUE, textAttr.getValue())
+ .put(JsonKeys.DISPLAY, nullIfEmpty(textAttr.getDisplay()))
+ .put(JsonKeys.TOOLTIP, nullIfEmpty(textAttr.getTooltip()));
}
}
+
// outside of above cases, return value of attribute or JSON null if empty
- String value = attr.getValue();
- return value == null ? JSONObject.NULL : value;
+ return nullIfEmpty(attr.getValue());
+ }
+
+ private static Object nullIfEmpty(String str) {
+ return str == null || str.isBlank() ? JSONObject.NULL : str;
}
}