Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jt/visually segmented case search group #1389

Merged
merged 16 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/cli/java/org/commcare/util/screen/QueryScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.commcare.session.RemoteQuerySessionManager;
import org.commcare.suite.model.RemoteQueryDatum;
import org.commcare.suite.model.QueryPrompt;
import org.commcare.suite.model.QueryGroup;
import org.javarosa.core.model.instance.ExternalDataInstance;
import org.javarosa.core.model.instance.ExternalDataInstanceSource;
import org.javarosa.core.services.locale.Localization;
Expand All @@ -44,6 +45,7 @@ public class QueryScreen extends Screen {

private RemoteQuerySessionManager remoteQuerySessionManager;
protected OrderedHashtable<String, QueryPrompt> userInputDisplays;
protected Hashtable<String, QueryGroup> groupHeaders;
private SessionWrapper sessionWrapper;
private String[] fields;
private String mTitle;
Expand Down Expand Up @@ -94,6 +96,7 @@ public void init(SessionWrapper sessionWrapper) throws CommCareSessionException
mTitle = getTitleLocaleString();
description = getDescriptionLocaleString();
dynamicSearch = getQueryDatum().getDynamicSearch();
groupHeaders = getQueryDatum().getUserQueryGroupHeaders();
}

private String getTitleLocaleString() {
Expand Down Expand Up @@ -262,6 +265,21 @@ public OrderedHashtable<String, QueryPrompt> getUserInputDisplays() {
return userInputDisplays;
}

public Hashtable<String, QueryGroup> getGroupHeaders() {
return groupHeaders;
}

public Hashtable<String, String> evalGroupHeaders() {
Hashtable<String, String> queryGroupMap = new Hashtable<>();
for (Map.Entry<String, QueryGroup> entry : groupHeaders.entrySet()) {
String key = entry.getKey();
QueryGroup queryGroupItem = entry.getValue();
String text = queryGroupItem.getDisplay().getText().evaluate(sessionWrapper.getEvaluationContext());
queryGroupMap.put(key, text);
}
return queryGroupMap;
}

public String getCurrentMessage() {
return currentMessage;
}
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/org/commcare/suite/model/QueryGroup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.commcare.suite.model;

import org.javarosa.core.util.externalizable.DeserializationException;
import org.javarosa.core.util.externalizable.ExtUtil;
import org.javarosa.core.util.externalizable.Externalizable;
import org.javarosa.core.util.externalizable.PrototypeFactory;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

// Model for <group> node
public class QueryGroup implements Externalizable {

private String key;
private DisplayUnit display;

@SuppressWarnings("unused")
public QueryGroup() {
}

public QueryGroup(String key, DisplayUnit display) {
this.key = key;
this.display = display;
}

@Override
public void readExternal(DataInputStream in, PrototypeFactory pf)
throws IOException, DeserializationException {
key = (String)ExtUtil.read(in, String.class, pf);
display = (DisplayUnit)ExtUtil.read(in, DisplayUnit.class, pf);
}

@Override
public void writeExternal(DataOutputStream out) throws IOException {
ExtUtil.write(out, key);
ExtUtil.write(out, display);
}

public String getKey() {
return key;
}

public DisplayUnit getDisplay() {
return display;
}
}
13 changes: 12 additions & 1 deletion src/main/java/org/commcare/suite/model/QueryPrompt.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,17 @@ public class QueryPrompt implements Externalizable {
@Nullable
private QueryPromptCondition validation;

@Nullable
private String groupKey;

@SuppressWarnings("unused")
public QueryPrompt() {
}

public QueryPrompt(String key, String appearance, String input, String receive,
String hidden, DisplayUnit display, ItemsetBinding itemsetBinding,
XPathExpression defaultValueExpr, boolean allowBlankValue, XPathExpression exclude,
QueryPromptCondition required, QueryPromptCondition validation) {
QueryPromptCondition required, QueryPromptCondition validation, String groupKey) {
this.key = key;
this.appearance = appearance;
this.input = input;
Expand All @@ -94,6 +97,7 @@ public QueryPrompt(String key, String appearance, String input, String receive,
this.exclude = exclude;
this.required = required;
this.validation = validation;
this.groupKey = groupKey;
}

@Override
Expand All @@ -111,6 +115,7 @@ public void readExternal(DataInputStream in, PrototypeFactory pf)
exclude = (XPathExpression)ExtUtil.read(in, new ExtWrapNullable(new ExtWrapTagged()), pf);
validation = (QueryPromptCondition)ExtUtil.read(in, new ExtWrapNullable(QueryPromptCondition.class), pf);
required = (QueryPromptCondition)ExtUtil.read(in, new ExtWrapNullable(QueryPromptCondition.class), pf);
groupKey = (String)ExtUtil.read(in, new ExtWrapNullable(String.class), pf);
}

@Override
Expand All @@ -128,6 +133,7 @@ public void writeExternal(DataOutputStream out) throws IOException {
ExtUtil.write(out, new ExtWrapNullable(exclude == null ? null : new ExtWrapTagged(exclude)));
ExtUtil.write(out, new ExtWrapNullable(validation));
ExtUtil.write(out, new ExtWrapNullable(required));
ExtUtil.write(out, new ExtWrapNullable(groupKey));
}

public String getKey() {
Expand Down Expand Up @@ -186,6 +192,11 @@ public QueryPromptCondition getValidation() {
return validation;
}

@Nullable
public String getGroupKey() {
return groupKey;
}

/**
* @return whether the prompt has associated choices to select from
*/
Expand Down
16 changes: 14 additions & 2 deletions src/main/java/org/commcare/suite/model/RemoteQueryDatum.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.commcare.suite.model;

import org.javarosa.core.util.OrderedHashtable;
import java.util.Hashtable;
import org.javarosa.core.util.externalizable.DeserializationException;
import org.javarosa.core.util.externalizable.ExtUtil;
import org.javarosa.core.util.externalizable.ExtWrapBase;
Expand Down Expand Up @@ -28,6 +29,7 @@
public class RemoteQueryDatum extends SessionDatum {
private List<QueryData> hiddenQueryValues;
private OrderedHashtable<String, QueryPrompt> userQueryPrompts;
private Hashtable<String, QueryGroup> userQueryGroupHeaders;
private boolean useCaseTemplate;
private boolean defaultSearch;
private boolean dynamicSearch;
Expand All @@ -45,11 +47,13 @@ public RemoteQueryDatum() {
*/
public RemoteQueryDatum(URL url, String storageInstance,
List<QueryData> hiddenQueryValues,
OrderedHashtable<String, QueryPrompt> userQueryPrompts,
boolean useCaseTemplate, boolean defaultSearch, boolean dynamicSearch, Text title, Text description) {
OrderedHashtable<String, QueryPrompt> userQueryPrompts, boolean useCaseTemplate,
boolean defaultSearch, boolean dynamicSearch, Text title, Text description,
Hashtable<String, QueryGroup> userQueryGroupHeaders) {
super(storageInstance, url.toString());
this.hiddenQueryValues = hiddenQueryValues;
this.userQueryPrompts = userQueryPrompts;
this.userQueryGroupHeaders = userQueryGroupHeaders;
this.useCaseTemplate = useCaseTemplate;
this.defaultSearch = defaultSearch;
this.dynamicSearch = dynamicSearch;
Expand All @@ -61,6 +65,10 @@ public OrderedHashtable<String, QueryPrompt> getUserQueryPrompts() {
return userQueryPrompts;
}

public Hashtable<String, QueryGroup> getUserQueryGroupHeaders() {
return userQueryGroupHeaders;
}

public List<QueryData> getHiddenQueryValues() {
return hiddenQueryValues;
}
Expand Down Expand Up @@ -104,6 +112,9 @@ public void readExternal(DataInputStream in, PrototypeFactory pf)
userQueryPrompts =
(OrderedHashtable<String, QueryPrompt>)ExtUtil.read(in,
new ExtWrapMap(String.class, QueryPrompt.class, ExtWrapMap.TYPE_ORDERED), pf);
userQueryGroupHeaders =
(Hashtable<String, QueryGroup>)ExtUtil.read(in,
new ExtWrapMap(String.class, QueryGroup.class, ExtWrapMap.TYPE_ORDERED), pf);
title = (Text) ExtUtil.read(in, new ExtWrapNullable(Text.class), pf);
description = (Text) ExtUtil.read(in, new ExtWrapNullable(Text.class), pf);
useCaseTemplate = ExtUtil.readBool(in);
Expand All @@ -116,6 +127,7 @@ public void writeExternal(DataOutputStream out) throws IOException {
super.writeExternal(out);
ExtUtil.write(out, new ExtWrapList(hiddenQueryValues, new ExtWrapTagged()));
ExtUtil.write(out, new ExtWrapMap(userQueryPrompts));
ExtUtil.write(out, new ExtWrapMap(userQueryGroupHeaders));
ExtUtil.write(out, new ExtWrapNullable(title));
ExtUtil.write(out, new ExtWrapNullable(description));
ExtUtil.writeBool(out, useCaseTemplate);
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/org/commcare/xml/QueryGroupParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.commcare.xml;

import org.commcare.suite.model.DisplayUnit;
import org.commcare.suite.model.QueryGroup;
import org.javarosa.xml.util.InvalidStructureException;
import org.javarosa.xml.util.UnfullfilledRequirementsException;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;

public class QueryGroupParser extends CommCareElementParser<QueryGroup> {

public static final String NAME_GROUP = "group";
private static final String ATTR_KEY = "key";
private static final String NAME_DISPLAY = "display";

public QueryGroupParser(KXmlParser parser) {
super(parser);
}

@Override
public QueryGroup parse() throws InvalidStructureException, IOException, XmlPullParserException,
UnfullfilledRequirementsException {
checkNode(NAME_GROUP);

String key = parser.getAttributeValue(null, ATTR_KEY);
DisplayUnit display = null;

while (nextTagInBlock(NAME_GROUP)) {
if (NAME_DISPLAY.equalsIgnoreCase(parser.getName())) {
display = parseDisplayBlock();
} else {
throw new InvalidStructureException(
"Unrecognised node " + parser.getName() + "in validation for group " + key);
}
}

if (key == null) {
throw new InvalidStructureException("<group> block must define a 'key' attribute", parser);
}
if (display == null) {
throw new InvalidStructureException("<group> block must define a <display> element", parser);
}

return new QueryGroup(key, display);
shubham1g5 marked this conversation as resolved.
Show resolved Hide resolved
}
}
4 changes: 3 additions & 1 deletion src/main/java/org/commcare/xml/QueryPromptParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class QueryPromptParser extends CommCareElementParser<QueryPrompt> {
private static final String ATTR_REQUIRED = "required";
private static final String ATTR_VALIDATION_TEST = "test";
private static final String NAME_TEXT = "text";
private static final String ATTR_GROUP_KEY = "group_key";

public QueryPromptParser(KXmlParser parser) {
super(parser);
Expand All @@ -60,6 +61,7 @@ public QueryPrompt parse() throws InvalidStructureException, IOException, XmlPul
XPathExpression defaultValue = xpathPropertyValue(defaultValueString);
String excludeValueString = parser.getAttributeValue(null, ATTR_EXCLUDE);
XPathExpression exclude = xpathPropertyValue(excludeValueString);
String groupKey = parser.getAttributeValue(null, ATTR_GROUP_KEY);
XPathExpression oldRequired = xpathPropertyValue(parser.getAttributeValue(null, ATTR_REQUIRED));

QueryPromptCondition validation = null;
Expand All @@ -86,7 +88,7 @@ public QueryPrompt parse() throws InvalidStructureException, IOException, XmlPul

return new QueryPrompt(key, appearance, input, receive, hidden, display,
itemsetBinding, defaultValue, allowBlankValue, exclude,
required, validation);
required, validation, groupKey);
}

private QueryPromptCondition parseRequiredBlock(String key)
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/org/commcare/xml/SessionDatumParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.commcare.suite.model.FormIdDatum;
import org.commcare.suite.model.MultiSelectEntityDatum;
import org.commcare.suite.model.QueryData;
import org.commcare.suite.model.QueryGroup;
import org.commcare.suite.model.QueryPrompt;
import org.commcare.suite.model.RemoteQueryDatum;
import org.commcare.suite.model.SessionDatum;
Expand All @@ -20,6 +21,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;

/**
* @author ctsims
Expand Down Expand Up @@ -129,6 +131,7 @@ private RemoteQueryDatum parseRemoteQueryDatum()
boolean dynamicSearch = "true".equals(parser.getAttributeValue(null, "dynamic_search"));
Text title = null;
Text description = null;
Hashtable<String, QueryGroup> groupPrompts = new Hashtable<>();
ArrayList<QueryData> hiddenQueryValues = new ArrayList<QueryData>();
while (nextTagInBlock("query")) {
String tagName = parser.getName();
Expand All @@ -143,9 +146,12 @@ private RemoteQueryDatum parseRemoteQueryDatum()
} else if ("description".equals(tagName)) {
nextTagInBlock("description");
description = new TextParser(parser).parse();
} else if (QueryGroupParser.NAME_GROUP.equals(tagName)){
QueryGroup queryGroup = new QueryGroupParser(parser).parse();
groupPrompts.put(queryGroup.getKey(), queryGroup);
}
}
return new RemoteQueryDatum(queryUrl, queryResultStorageInstance, hiddenQueryValues,
userQueryPrompts, useCaseTemplate, defaultSearch, dynamicSearch, title, description);
userQueryPrompts, useCaseTemplate, defaultSearch, dynamicSearch, title, description, groupPrompts);
}
}
23 changes: 23 additions & 0 deletions src/test/java/org/commcare/xml/QueryDataParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import org.commcare.suite.model.QueryData;
import org.commcare.suite.model.QueryPrompt;
import org.commcare.suite.model.QueryGroup;
import org.javarosa.core.model.condition.EvaluationContext;
import org.javarosa.core.model.instance.DataInstance;
import org.javarosa.xml.util.InvalidStructureException;
Expand Down Expand Up @@ -143,4 +144,26 @@ public void testParseQueryData_badNesting() throws XmlPullParserException, IOExc
} catch (InvalidStructureException ignored) {
}
}

@Test
public void testParseValueData_withGroupKeyAttribute()
throws InvalidStructureException, XmlPullParserException,
IOException, UnfullfilledRequirementsException {
String query = "<prompt key=\"name\" group_key=\"group_header_1\"></prompt>";
QueryPromptParser parser = ParserTestUtils.buildParser(query, QueryPromptParser.class);
QueryPrompt queryData = parser.parse();
assertEquals("group_header_1", queryData.getGroupKey());
}

@Test
public void testParseValueData_withGroup()
throws InvalidStructureException, XmlPullParserException,
IOException, UnfullfilledRequirementsException {
String query = "<group key=\"group_header_0\">"
+ "<display><text><locale id=\"search_property.m0.group_header_0\"/></text></display>"
+ "</group>";
QueryGroupParser parser = ParserTestUtils.buildParser(query, QueryGroupParser.class);
QueryGroup queryData = parser.parse();
assertEquals("group_header_0", queryData.getKey());
}
}