use of org.javarosa.core.model.FormIndex in project javarosa by opendatakit.
the class FormIndexSerializationTest method testOnFormController.
@Test
public void testOnFormController() throws IOException, ClassNotFoundException {
FormParseInit formParseInit = new FormParseInit();
formParseInit.setFormToParse(Paths.get(PathConst.getTestResourcePath().getAbsolutePath(), "formindex-serialization.xml").toString());
FormEntryController formEntryController = formParseInit.getFormEntryController();
FormIndex formIndex = formEntryController.getModel().getFormIndex();
assertFormIndex(formIndex, deserializeFormIndex(serializeObject(formIndex)));
do {
formIndex = formEntryController.getModel().incrementIndex(formIndex);
assertFormIndex(formIndex, deserializeFormIndex(serializeObject(formIndex)));
} while (!formIndex.isEndOfFormIndex());
}
use of org.javarosa.core.model.FormIndex in project javarosa by opendatakit.
the class FormIndexSerializationTest method testLocalAndInstanceNonNullReference.
@Test
public void testLocalAndInstanceNonNullReference() throws IOException, ClassNotFoundException {
TreeReference treeReference = TreeReference.rootRef();
FormIndex formIndexToSerialize = new FormIndex(1, 2, treeReference);
byte[] serializedObject = serializeObject(formIndexToSerialize);
FormIndex formIndexDeserialized = deserializeFormIndex(serializedObject);
assertFormIndex(formIndexToSerialize, formIndexDeserialized);
}
use of org.javarosa.core.model.FormIndex in project collect by opendatakit.
the class FormEntryViewModelTest method setup.
@Before
public void setup() {
formController = mock(FormController.class);
startingIndex = new FormIndex(null, 0, 0, new TreeReference());
when(formController.getFormIndex()).thenReturn(startingIndex);
when(formController.getFormDef()).thenReturn(new FormDef());
AuditEventLogger auditEventLogger = mock(AuditEventLogger.class);
when(formController.getAuditEventLogger()).thenReturn(auditEventLogger);
viewModel = new FormEntryViewModel(mock(Supplier.class));
viewModel.formLoaded(formController);
}
use of org.javarosa.core.model.FormIndex in project collect by opendatakit.
the class FormEntryActivity method updateFieldListQuestions.
/**
* Saves the form and updates displayed widgets accordingly:
* - removes widgets corresponding to questions that are no longer relevant
* - adds widgets corresponding to questions that are newly-relevant
* - removes and rebuilds widgets corresponding to questions that have changed in some way. For
* example, the question text or hint may have updated due to a value they refer to changing.
* <p>
* The widget corresponding to the {@param lastChangedIndex} is never changed.
*/
private void updateFieldListQuestions(FormIndex lastChangedIndex) throws RepeatsInFieldListException {
// Save the user-visible state for all questions in this field-list
FormEntryPrompt[] questionsBeforeSave = getFormController().getQuestionPrompts();
List<ImmutableDisplayableQuestion> immutableQuestionsBeforeSave = new ArrayList<>();
for (FormEntryPrompt questionBeforeSave : questionsBeforeSave) {
immutableQuestionsBeforeSave.add(new ImmutableDisplayableQuestion(questionBeforeSave));
}
saveAnswersForCurrentScreen(questionsBeforeSave, immutableQuestionsBeforeSave);
FormEntryPrompt[] questionsAfterSave = getFormController().getQuestionPrompts();
Map<FormIndex, FormEntryPrompt> questionsAfterSaveByIndex = new HashMap<>();
for (FormEntryPrompt question : questionsAfterSave) {
questionsAfterSaveByIndex.put(question.getIndex(), question);
}
// Identify widgets to remove or rebuild (by removing and re-adding). We'd like to do the
// identification and removal in the same pass but removal has to be done in a loop that
// starts from the end and itemset-based select choices will only be correctly recomputed
// if accessed from beginning to end because the call on sameAs is what calls
// populateDynamicChoices. See https://github.com/getodk/javarosa/issues/436
List<FormEntryPrompt> questionsThatHaveNotChanged = new ArrayList<>();
List<FormIndex> formIndexesToRemove = new ArrayList<>();
for (ImmutableDisplayableQuestion questionBeforeSave : immutableQuestionsBeforeSave) {
FormEntryPrompt questionAtSameFormIndex = questionsAfterSaveByIndex.get(questionBeforeSave.getFormIndex());
// bypass SelectChoices stored in ImmutableDisplayableQuestion
if (questionBeforeSave.sameAs(questionAtSameFormIndex) && !getFormController().usesDatabaseExternalDataFeature(questionBeforeSave.getFormIndex())) {
questionsThatHaveNotChanged.add(questionAtSameFormIndex);
} else if (!lastChangedIndex.equals(questionBeforeSave.getFormIndex())) {
formIndexesToRemove.add(questionBeforeSave.getFormIndex());
}
}
for (int i = immutableQuestionsBeforeSave.size() - 1; i >= 0; i--) {
ImmutableDisplayableQuestion questionBeforeSave = immutableQuestionsBeforeSave.get(i);
if (formIndexesToRemove.contains(questionBeforeSave.getFormIndex())) {
odkView.removeWidgetAt(i);
}
}
for (int i = 0; i < questionsAfterSave.length; i++) {
if (!questionsThatHaveNotChanged.contains(questionsAfterSave[i]) && !questionsAfterSave[i].getIndex().equals(lastChangedIndex)) {
// The values of widgets in intent groups are set by the view so widgetValueChanged
// is never called. This means readOnlyOverride can always be set to false.
odkView.addWidgetForQuestion(questionsAfterSave[i], i);
}
}
}
use of org.javarosa.core.model.FormIndex in project collect by opendatakit.
the class FormEntryActivity method loadingComplete.
/**
* Given a {@link FormLoaderTask} which has created a {@link FormController} for either a new or
* existing instance, shows that instance to the user. Either launches {@link FormHierarchyActivity}
* if an existing instance is being edited or builds the view for the current question(s) if a
* new instance is being created.
* <p>
* May do some or all of these depending on current state:
* - Ensures phone state permissions are given if this form needs them
* - Cleans up {@link #formLoaderTask}
* - Sets the global form controller and database manager for search()/pulldata()
* - Restores the last-used language
* - Handles activity results that may have come in while the form was loading
* - Alerts the user of a recovery from savepoint
* - Verifies whether an instance folder exists and creates one if not
* - Initializes background location capture (only if the instance being loaded is a new one)
*/
@Override
public void loadingComplete(FormLoaderTask task, FormDef formDef, String warningMsg) {
DialogFragmentUtils.dismissDialog(FormLoadingDialogFragment.class, getSupportFragmentManager());
final FormController formController = task.getFormController();
if (formController != null) {
if (readPhoneStatePermissionRequestNeeded) {
permissionsProvider.requestReadPhoneStatePermission(this, true, new PermissionListener() {
@Override
public void granted() {
readPhoneStatePermissionRequestNeeded = false;
loadForm();
}
@Override
public void denied() {
finish();
}
});
} else {
formLoaderTask.setFormLoaderListener(null);
FormLoaderTask t = formLoaderTask;
formLoaderTask = null;
t.cancel(true);
t.destroy();
Collect.getInstance().setFormController(formController);
backgroundLocationViewModel.formFinishedLoading();
Collect.getInstance().setExternalDataManager(task.getExternalDataManager());
// Set the language if one has already been set in the past
String[] languageTest = formController.getLanguages();
if (languageTest != null) {
String defaultLanguage = formController.getLanguage();
Form form = formsRepository.getOneByPath(formPath);
if (form != null) {
String newLanguage = form.getLanguage();
try {
formController.setLanguage(newLanguage);
} catch (Exception e) {
// if somehow we end up with a bad language, set it to the default
Timber.i("Ended up with a bad language. %s", newLanguage);
formController.setLanguage(defaultLanguage);
}
}
}
boolean pendingActivityResult = task.hasPendingActivityResult();
if (pendingActivityResult) {
Timber.w("Calling onActivityResult from loadingComplete");
formControllerAvailable(formController);
onScreenRefresh();
onActivityResult(task.getRequestCode(), task.getResultCode(), task.getIntent());
return;
}
// it can be a normal flow for a pending activity result to restore from a savepoint
// (the call flow handled by the above if statement). For all other use cases, the
// user should be notified, as it means they wandered off doing other things then
// returned to ODK Collect and chose Edit Saved Form, but that the savepoint for
// that form is newer than the last saved version of their form data.
boolean hasUsedSavepoint = task.hasUsedSavepoint();
if (hasUsedSavepoint) {
runOnUiThread(() -> showLongToast(this, R.string.savepoint_used));
}
if (formController.getInstanceFile() == null) {
FormInstanceFileCreator formInstanceFileCreator = new FormInstanceFileCreator(storagePathProvider, System::currentTimeMillis);
File instanceFile = formInstanceFileCreator.createInstanceFile(formPath);
if (instanceFile != null) {
formController.setInstanceFile(instanceFile);
} else {
showFormLoadErrorAndExit(getString(R.string.loading_form_failed));
}
formControllerAvailable(formController);
identityPromptViewModel.requiresIdentityToContinue().observe(this, requiresIdentity -> {
if (!requiresIdentity) {
formController.getAuditEventLogger().logEvent(AuditEvent.AuditEventType.FORM_START, true, System.currentTimeMillis());
startFormEntry(formController, warningMsg);
}
});
} else {
Intent reqIntent = getIntent();
boolean showFirst = reqIntent.getBooleanExtra("start", false);
if (!showFirst) {
// we've just loaded a saved form, so start in the hierarchy view
String formMode = reqIntent.getStringExtra(ApplicationConstants.BundleKeys.FORM_MODE);
if (formMode == null || ApplicationConstants.FormModes.EDIT_SAVED.equalsIgnoreCase(formMode)) {
formControllerAvailable(formController);
identityPromptViewModel.requiresIdentityToContinue().observe(this, requiresIdentity -> {
if (!requiresIdentity) {
if (!allowMovingBackwards) {
// we aren't allowed to jump around the form so attempt to
// go directly to the question we were on last time the
// form was saved.
// TODO: revisit the fallback. If for some reason the index
// wasn't saved, we can now jump around which doesn't seem right.
FormIndex formIndex = SaveFormIndexTask.loadFormIndexFromFile();
if (formIndex != null) {
formController.jumpToIndex(formIndex);
onScreenRefresh();
return;
}
}
formController.getAuditEventLogger().logEvent(AuditEvent.AuditEventType.FORM_RESUME, true, System.currentTimeMillis());
formController.getAuditEventLogger().logEvent(AuditEvent.AuditEventType.HIERARCHY, true, System.currentTimeMillis());
startActivityForResult(new Intent(this, FormHierarchyActivity.class), RequestCodes.HIERARCHY_ACTIVITY);
}
});
formSaveViewModel.editingForm();
} else {
if (ApplicationConstants.FormModes.VIEW_SENT.equalsIgnoreCase(formMode)) {
startActivity(new Intent(this, ViewOnlyFormHierarchyActivity.class));
}
finish();
}
} else {
formControllerAvailable(formController);
identityPromptViewModel.requiresIdentityToContinue().observe(this, requiresIdentity -> {
if (!requiresIdentity) {
formController.getAuditEventLogger().logEvent(AuditEvent.AuditEventType.FORM_RESUME, true, System.currentTimeMillis());
startFormEntry(formController, warningMsg);
}
});
}
}
}
} else {
Timber.e("FormController is null");
showLongToast(this, R.string.loading_form_failed);
finish();
}
}
Aggregations