Search in sources :

Example 46 with FormIndex

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());
}
Also used : FormEntryController(org.javarosa.form.api.FormEntryController) FormIndex(org.javarosa.core.model.FormIndex) FormParseInit(org.javarosa.core.test.FormParseInit) Test(org.junit.Test)

Example 47 with FormIndex

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);
}
Also used : TreeReference(org.javarosa.core.model.instance.TreeReference) FormIndex(org.javarosa.core.model.FormIndex) Test(org.junit.Test)

Example 48 with FormIndex

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);
}
Also used : FormController(org.odk.collect.android.javarosawrapper.FormController) AuditEventLogger(org.odk.collect.android.formentry.audit.AuditEventLogger) TreeReference(org.javarosa.core.model.instance.TreeReference) FormDef(org.javarosa.core.model.FormDef) FormIndex(org.javarosa.core.model.FormIndex) Before(org.junit.Before)

Example 49 with FormIndex

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);
        }
    }
}
Also used : ImmutableDisplayableQuestion(org.odk.collect.android.logic.ImmutableDisplayableQuestion) FormEntryPrompt(org.javarosa.form.api.FormEntryPrompt) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) FormIndex(org.javarosa.core.model.FormIndex) FailedConstraint(org.odk.collect.android.javarosawrapper.FormController.FailedConstraint)

Example 50 with FormIndex

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();
    }
}
Also used : FormController(org.odk.collect.android.javarosawrapper.FormController) PermissionListener(org.odk.collect.permissions.PermissionListener) FormInstanceFileCreator(org.odk.collect.android.formentry.loading.FormInstanceFileCreator) Form(org.odk.collect.forms.Form) Intent(android.content.Intent) RepeatsInFieldListException(org.odk.collect.android.javarosawrapper.RepeatsInFieldListException) JavaRosaException(org.odk.collect.android.exception.JavaRosaException) FormLoaderTask(org.odk.collect.android.tasks.FormLoaderTask) FormIndex(org.javarosa.core.model.FormIndex) File(java.io.File)

Aggregations

FormIndex (org.javarosa.core.model.FormIndex)63 GroupDef (org.javarosa.core.model.GroupDef)11 JavaRosaException (org.odk.collect.android.exception.JavaRosaException)11 FormController (org.odk.collect.android.javarosawrapper.FormController)11 ArrayList (java.util.ArrayList)10 FormEntryPrompt (org.javarosa.form.api.FormEntryPrompt)10 Test (org.junit.Test)10 IFormElement (org.javarosa.core.model.IFormElement)6 TreeReference (org.javarosa.core.model.instance.TreeReference)6 FormEntryCaption (org.javarosa.form.api.FormEntryCaption)6 File (java.io.File)5 FormController (org.odk.collect.android.logic.FormController)5 HierarchyElement (org.odk.collect.android.logic.HierarchyElement)5 IAnswerData (org.javarosa.core.model.data.IAnswerData)4 HierarchyListAdapter (org.odk.collect.android.adapters.HierarchyListAdapter)4 FormDef (org.javarosa.core.model.FormDef)3 FormEntryModel (org.javarosa.form.api.FormEntryModel)3 Intent (android.content.Intent)2 ObjectInputStream (java.io.ObjectInputStream)2 HashMap (java.util.HashMap)2