use of org.javarosa.form.api.FormEntryPrompt in project collect by opendatakit.
the class FormEntryActivity method createView.
/**
* Creates and returns a new view based on the event type passed in. The view returned is
* of type {@link View} if the event passed in represents the end of the form or of type
* {@link ODKView} otherwise.
*
* @param advancingPage -- true if this results from advancing through the form
* @return newly created View
*/
private View createView(int event, boolean advancingPage) {
releaseOdkView();
FormController formController = getFormController();
String formTitle = formController.getFormTitle();
setTitle(formTitle);
if (event != FormEntryController.EVENT_QUESTION) {
formController.getAuditEventLogger().logEvent(AuditEvent.getAuditEventTypeFromFecType(event), formController.getFormIndex(), true, null, System.currentTimeMillis(), null);
}
switch(event) {
case FormEntryController.EVENT_BEGINNING_OF_FORM:
return createViewForFormBeginning(formController);
case FormEntryController.EVENT_END_OF_FORM:
return createViewForFormEnd(formController);
case FormEntryController.EVENT_QUESTION:
case FormEntryController.EVENT_GROUP:
case FormEntryController.EVENT_REPEAT:
// should only be a group here if the event_group is a field-list
try {
AuditUtils.logCurrentScreen(formController, formController.getAuditEventLogger(), System.currentTimeMillis());
FormEntryCaption[] groups = formController.getGroupsForCurrentIndex();
FormEntryPrompt[] prompts = formController.getQuestionPrompts();
odkView = createODKView(advancingPage, prompts, groups);
odkView.setWidgetValueChangedListener(this);
Timber.i("Created view for group %s %s", groups.length > 0 ? groups[groups.length - 1].getLongText() : "[top]", prompts.length > 0 ? prompts[0].getQuestionText() : "[no question]");
} catch (RuntimeException | RepeatsInFieldListException e) {
if (e instanceof RuntimeException) {
Timber.e(e);
}
// this is badness to avoid a crash.
try {
event = formController.stepToNextScreenEvent();
createErrorDialog(e.getMessage(), false);
} catch (JavaRosaException e1) {
Timber.d(e1);
createErrorDialog(e.getMessage() + "\n\n" + e1.getCause().getMessage(), false);
}
return createView(event, advancingPage);
}
if (showNavigationButtons) {
updateNavigationButtonVisibility();
}
return odkView;
case EVENT_PROMPT_NEW_REPEAT:
createRepeatDialog();
return new EmptyView(this);
default:
Timber.e("Attempted to create a view that does not exist.");
// this is badness to avoid a crash.
try {
event = formController.stepToNextScreenEvent();
createErrorDialog(getString(R.string.survey_internal_error), true);
} catch (JavaRosaException e) {
Timber.d(e);
createErrorDialog(e.getCause().getMessage(), true);
}
return createView(event, advancingPage);
}
}
use of org.javarosa.form.api.FormEntryPrompt in project collect by opendatakit.
the class FormHierarchyActivity method refreshView.
/**
* @see #refreshView()
*/
private void refreshView(boolean isGoingUp) {
try {
FormController formController = Collect.getInstance().getFormController();
// Save the current index so we can return to the problematic question
// in the event of an error.
currentIndex = formController.getFormIndex();
elementsToDisplay = new ArrayList<>();
jumpToHierarchyStartIndex();
updateOptionsMenu();
int event = formController.getEvent();
if (event == FormEntryController.EVENT_BEGINNING_OF_FORM && !shouldShowRepeatGroupPicker()) {
// The beginning of form has no valid prompt to display.
groupPathTextView.setVisibility(View.GONE);
} else {
groupPathTextView.setVisibility(View.VISIBLE);
groupPathTextView.setText(getCurrentPath());
}
// Refresh the current event in case we did step forward.
event = formController.getEvent();
// Ref to the parent group that's currently being displayed.
//
// Because of the guard conditions below, we will skip
// everything until we exit this group.
TreeReference visibleGroupRef = null;
while (event != FormEntryController.EVENT_END_OF_FORM) {
// get the ref to this element
TreeReference currentRef = formController.getFormIndex().getReference();
// retrieve the current group
TreeReference curGroup = (visibleGroupRef == null) ? contextGroupRef : visibleGroupRef;
if (curGroup != null && !curGroup.isParentOf(currentRef, false)) {
// We have left the current group
if (visibleGroupRef == null) {
// We are done.
break;
} else {
// exit the inner group
visibleGroupRef = null;
}
}
if (visibleGroupRef != null) {
// We're in a group within the one we want to list
// skip this question/group/repeat and move to the next index.
event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
continue;
}
switch(event) {
case FormEntryController.EVENT_QUESTION:
{
// Nothing but repeat group instances should show up in the picker.
if (shouldShowRepeatGroupPicker()) {
break;
}
FormEntryPrompt fp = formController.getQuestionPrompt();
String label = fp.getShortText();
String answerDisplay = FormEntryPromptUtils.getAnswerText(fp, this, formController);
elementsToDisplay.add(new HierarchyElement(FormEntryPromptUtils.markQuestionIfIsRequired(label, fp.isRequired()), answerDisplay, null, HierarchyElement.Type.QUESTION, fp.getIndex()));
break;
}
case FormEntryController.EVENT_GROUP:
{
if (!formController.isGroupRelevant()) {
break;
}
// Nothing but repeat group instances should show up in the picker.
if (shouldShowRepeatGroupPicker()) {
break;
}
FormIndex index = formController.getFormIndex();
// Only display groups with a specific appearance attribute.
if (!formController.isDisplayableGroup(index)) {
break;
}
// Don't render other groups' children.
if (contextGroupRef != null && !contextGroupRef.isParentOf(currentRef, false)) {
break;
}
visibleGroupRef = currentRef;
FormEntryCaption caption = formController.getCaptionPrompt();
HierarchyElement groupElement = new HierarchyElement(caption.getShortText(), getString(R.string.group_label), ContextCompat.getDrawable(this, R.drawable.ic_folder_open), HierarchyElement.Type.VISIBLE_GROUP, caption.getIndex());
elementsToDisplay.add(groupElement);
// Skip to the next item outside the group.
event = formController.stepOverGroup();
continue;
}
case FormEntryController.EVENT_PROMPT_NEW_REPEAT:
{
// ignore it.
break;
}
case FormEntryController.EVENT_REPEAT:
{
boolean forPicker = shouldShowRepeatGroupPicker();
// Only break to exclude non-relevant repeat from picker
if (!formController.isGroupRelevant() && forPicker) {
break;
}
visibleGroupRef = currentRef;
// Don't render other groups' children.
if (contextGroupRef != null && !contextGroupRef.isParentOf(currentRef, false)) {
break;
}
FormEntryCaption fc = formController.getCaptionPrompt();
if (forPicker) {
// Don't render other groups' instances.
String repeatGroupPickerRef = repeatGroupPickerIndex.getReference().toString(false);
if (!currentRef.toString(false).equals(repeatGroupPickerRef)) {
break;
}
int itemNumber = fc.getMultiplicity() + 1;
// e.g. `friends > 1`
String repeatLabel = fc.getShortText() + " > " + itemNumber;
// If the child of the group has a more descriptive label, use that instead.
if (fc.getFormElement().getChildren().size() == 1 && fc.getFormElement().getChild(0) instanceof GroupDef) {
formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
String itemLabel = formController.getCaptionPrompt().getShortText();
if (itemLabel != null) {
// e.g. `1. Alice`
repeatLabel = itemNumber + ".\u200E " + itemLabel;
}
}
HierarchyElement instance = new HierarchyElement(repeatLabel, null, null, HierarchyElement.Type.REPEAT_INSTANCE, fc.getIndex());
elementsToDisplay.add(instance);
} else if (fc.getMultiplicity() == 0) {
// Display the repeat header for the group.
HierarchyElement group = new HierarchyElement(fc.getShortText(), getString(R.string.repeatable_group_label), ContextCompat.getDrawable(this, R.drawable.ic_repeat), HierarchyElement.Type.REPEATABLE_GROUP, fc.getIndex());
elementsToDisplay.add(group);
}
break;
}
}
event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
}
recyclerView.setAdapter(new HierarchyListAdapter(elementsToDisplay, this::onElementClick));
formController.jumpToIndex(currentIndex);
// that use presentation groups to display labels).
if (isDisplayingSingleGroup() && !screenIndex.isBeginningOfFormIndex()) {
if (isGoingUp) {
// Back out once more.
goUpLevel();
} else {
// Enter automatically.
formController.jumpToIndex(elementsToDisplay.get(0).getFormIndex());
refreshView();
}
}
} catch (Exception e) {
Timber.e(e);
createErrorDialog(e.getMessage());
}
}
use of org.javarosa.form.api.FormEntryPrompt in project collect by opendatakit.
the class ODKView method setDataForFields.
/**
* Saves answers for the widgets in this view. Called when the widgets are in an intent group.
*/
public void setDataForFields(Bundle bundle) throws JavaRosaException {
FormController formController = Collect.getInstance().getFormController();
if (formController == null) {
return;
}
if (bundle != null) {
Set<String> keys = bundle.keySet();
for (String key : keys) {
Object answer = bundle.get(key);
if (answer == null) {
continue;
}
for (QuestionWidget questionWidget : widgets) {
FormEntryPrompt prompt = questionWidget.getFormEntryPrompt();
TreeReference treeReference = (TreeReference) prompt.getFormElement().getBind().getReference();
if (treeReference.getNameLast().equals(key)) {
switch(prompt.getDataType()) {
case Constants.DATATYPE_TEXT:
formController.saveAnswer(prompt.getIndex(), ExternalAppsUtils.asStringData(answer));
((StringWidget) questionWidget).setDisplayValueFromModel();
questionWidget.showAnswerContainer();
break;
case Constants.DATATYPE_INTEGER:
formController.saveAnswer(prompt.getIndex(), ExternalAppsUtils.asIntegerData(answer));
((StringWidget) questionWidget).setDisplayValueFromModel();
questionWidget.showAnswerContainer();
break;
case Constants.DATATYPE_DECIMAL:
formController.saveAnswer(prompt.getIndex(), ExternalAppsUtils.asDecimalData(answer));
((StringWidget) questionWidget).setDisplayValueFromModel();
questionWidget.showAnswerContainer();
break;
case Constants.DATATYPE_BINARY:
try {
Uri uri;
if (answer instanceof Uri) {
uri = (Uri) answer;
} else if (answer instanceof String) {
uri = Uri.parse(bundle.getString(key));
} else {
throw new RuntimeException("The value for " + key + " must be a URI but it is " + answer);
}
permissionsProvider.requestReadUriPermission((Activity) getContext(), uri, getContext().getContentResolver(), new PermissionListener() {
@Override
public void granted() {
File destFile = FileUtils.createDestinationMediaFile(formController.getInstanceFile().getParent(), ContentUriHelper.getFileExtensionFromUri(uri));
// TODO might be better to use QuestionMediaManager in the future
FileUtils.saveAnswerFileFromUri(uri, destFile, getContext());
((WidgetDataReceiver) questionWidget).setData(destFile);
questionWidget.showAnswerContainer();
}
@Override
public void denied() {
}
});
} catch (Exception | Error e) {
Timber.w(e);
}
break;
default:
throw new RuntimeException(getContext().getString(R.string.ext_assign_value_error, treeReference.toString(false)));
}
break;
}
}
}
}
}
use of org.javarosa.form.api.FormEntryPrompt in project collect by opendatakit.
the class ODKView method addIntentLaunchButton.
/**
* Adds a button to launch an intent if the group displayed by this view is an intent group.
* An intent group launches an intent and receives multiple values from the launched app.
*/
private void addIntentLaunchButton(Context context, FormEntryPrompt[] questionPrompts, FormEntryCaption c, String intentString) {
final String buttonText;
final String errorString;
String v = c.getSpecialFormQuestionText("buttonText");
buttonText = (v != null) ? v : context.getString(R.string.launch_app);
v = c.getSpecialFormQuestionText("noAppErrorString");
errorString = (v != null) ? v : context.getString(R.string.no_app);
// set button formatting
MaterialButton launchIntentButton = findViewById(R.id.launchIntentButton);
launchIntentButton.setText(buttonText);
launchIntentButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, QuestionFontSizeUtils.getQuestionFontSize() + 2);
launchIntentButton.setVisibility(VISIBLE);
launchIntentButton.setOnClickListener(view -> {
String intentName = ExternalAppsUtils.extractIntentName(intentString);
Map<String, String> parameters = ExternalAppsUtils.extractParameters(intentString);
Intent i = new Intent(intentName);
if (i.resolveActivity(Collect.getInstance().getPackageManager()) == null) {
Intent launchIntent = Collect.getInstance().getPackageManager().getLaunchIntentForPackage(intentName);
if (launchIntent != null) {
// Make sure FLAG_ACTIVITY_NEW_TASK is not set because it doesn't work with startActivityForResult
launchIntent.setFlags(0);
i = launchIntent;
}
}
try {
ExternalAppsUtils.populateParameters(i, parameters, c.getIndex().getReference());
for (FormEntryPrompt p : questionPrompts) {
IFormElement formElement = p.getFormElement();
if (formElement instanceof QuestionDef) {
TreeReference reference = (TreeReference) formElement.getBind().getReference();
IAnswerData answerValue = p.getAnswerValue();
Object value = answerValue == null ? null : answerValue.getValue();
switch(p.getDataType()) {
case Constants.DATATYPE_TEXT:
case Constants.DATATYPE_INTEGER:
case Constants.DATATYPE_DECIMAL:
case Constants.DATATYPE_BINARY:
i.putExtra(reference.getNameLast(), (Serializable) value);
break;
}
}
}
((Activity) getContext()).startActivityForResult(i, RequestCodes.EX_GROUP_CAPTURE);
} catch (ExternalParamsException e) {
Timber.e(e, "ExternalParamsException");
ToastUtils.showShortToast(getContext(), e.getMessage());
} catch (ActivityNotFoundException e) {
Timber.d(e, "ActivityNotFoundExcept");
ToastUtils.showShortToast(getContext(), errorString);
}
});
}
use of org.javarosa.form.api.FormEntryPrompt in project collect by opendatakit.
the class ODKView method getAnswers.
/**
* @return a HashMap of answers entered by the user for this set of widgets
*/
public HashMap<FormIndex, IAnswerData> getAnswers() {
HashMap<FormIndex, IAnswerData> answers = new LinkedHashMap<>();
for (QuestionWidget q : widgets) {
/*
* The FormEntryPrompt has the FormIndex, which is where the answer gets stored. The
* QuestionWidget has the answer the user has entered.
*/
FormEntryPrompt p = q.getFormEntryPrompt();
answers.put(p.getIndex(), q.getAnswer());
}
return answers;
}
Aggregations