package org.commcare.activities; import android.app.ActionBar; import android.app.ListActivity; import android.os.Bundle; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import org.commcare.adapters.HierarchyListAdapter; import org.commcare.dalvik.R; import org.commcare.logging.XPathErrorLogger; import org.commcare.logic.FormHierarchyBuilder; import org.commcare.logic.HierarchyElement; import org.commcare.logic.HierarchyEntryType; import org.commcare.utils.SessionActivityRegistration; import org.javarosa.core.model.FormIndex; import org.javarosa.core.services.locale.Localization; import org.javarosa.form.api.FormEntryController; import org.javarosa.xpath.XPathTypeMismatchException; import java.util.ArrayList; import java.util.List; public class FormHierarchyActivity extends ListActivity { private Button jumpPreviousButton; private List<HierarchyElement> formList; private TextView mPath; public final static int RESULT_XPATH_ERROR = RESULT_FIRST_USER + 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.hierarchy_layout); addActionBarBackArrow(); setTitle(Localization.get("form.hierarchy")); mPath = (TextView)findViewById(R.id.pathtext); jumpPreviousButton = (Button)findViewById(R.id.jumpPreviousButton); jumpPreviousButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { goUpLevel(); } }); Button jumpBeginningButton = (Button)findViewById(R.id.jumpBeginningButton); jumpBeginningButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { FormEntryActivity.mFormController.jumpToIndex(FormIndex .createBeginningOfFormIndex()); setResult(RESULT_OK); finish(); } }); Button jumpEndButton = (Button)findViewById(R.id.jumpEndButton); jumpEndButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { FormEntryActivity.mFormController.jumpToIndex(FormIndex.createEndOfFormIndex()); setResult(RESULT_OK); finish(); } }); // We use a static FormEntryController to make jumping faster. final FormIndex mStartIndex = FormEntryActivity.mFormController.getFormIndex(); // kinda slow, but works. // this scrolls to the last question the user was looking at getListView().post(new Runnable() { @Override public void run() { int position = 0; ListAdapter adapter = getListAdapter(); if (adapter != null) { for (int i = 0; i < adapter.getCount(); i++) { HierarchyElement he = (HierarchyElement)getListAdapter().getItem(i); if (mStartIndex.equals(he.getFormIndex())) { position = i; break; } } getListView().setSelection(position); } } }); refreshView(); } private void addActionBarBackArrow() { if (android.os.Build.VERSION.SDK_INT >= 11) { ActionBar bar = getActionBar(); if (bar != null) { bar.setDisplayShowHomeEnabled(true); bar.setDisplayHomeAsUpEnabled(true); } } } @Override protected void onResume() { super.onResume(); SessionActivityRegistration.handleOrListenForSessionExpiration(this); } @Override protected void onPause() { super.onPause(); SessionActivityRegistration.unregisterSessionExpirationReceiver(this); } private void goUpLevel() { FormIndex index = stepIndexOut(FormEntryActivity.mFormController.getFormIndex()); int currentEvent = FormEntryActivity.mFormController.getEvent(); // Step out of any group indexes that are present. while (index != null && FormEntryActivity.mFormController.getEvent(index) == FormEntryController.EVENT_GROUP) { index = stepIndexOut(index); } if (index == null) { FormEntryActivity.mFormController.jumpToIndex(FormIndex.createBeginningOfFormIndex()); } else { if (currentEvent == FormEntryController.EVENT_REPEAT) { // We were at a repeat, so stepping back brought us to then previous level FormEntryActivity.mFormController.jumpToIndex(index); } else { // We were at a question, so stepping back brought us to either: // The beginning. or The start of a repeat. So we need to step // out again to go passed the repeat. index = stepIndexOut(index); if (index == null) { FormEntryActivity.mFormController.jumpToIndex(FormIndex .createBeginningOfFormIndex()); } else { FormEntryActivity.mFormController.jumpToIndex(index); } } } refreshView(); } public static String getCurrentPath() { FormIndex index = stepIndexOut(FormEntryActivity.mFormController.getFormIndex()); String path = ""; while (index != null) { path = FormEntryActivity.mFormController.getCaptionPrompt(index).getLongText() + " (" + (FormEntryActivity.mFormController.getCaptionPrompt(index) .getMultiplicity() + 1) + ") > " + path; index = stepIndexOut(index); } // return path? return path.substring(0, path.length() - 2); } private void refreshView() { // Record the current index so we can return to the same place if the user hits 'back'. FormIndex currentIndex = FormEntryActivity.mFormController.getFormIndex(); formList = new ArrayList<>(); String hierarchyPath; try { hierarchyPath = FormHierarchyBuilder.populateHierarchyList(this, formList); } catch (XPathTypeMismatchException e) { XPathErrorLogger.INSTANCE.logErrorToCurrentApp(e); final String errorMsg = "Encounted xpath error: " + e.getMessage(); Toast.makeText(this, errorMsg, Toast.LENGTH_LONG).show(); setResult(RESULT_XPATH_ERROR); finish(); return; } setGoUpButton(hierarchyPath); HierarchyListAdapter itla = new HierarchyListAdapter(this); itla.setListItems(formList); setListAdapter(itla); // set the controller back to the current index in case the user hits 'back' FormEntryActivity.mFormController.jumpToIndex(currentIndex); } private void setGoUpButton(String hierarchyPath) { if ("".equals(hierarchyPath)) { mPath.setVisibility(View.GONE); jumpPreviousButton.setEnabled(false); jumpPreviousButton.setTextColor(getResources().getColor(R.color.edit_text_color)); } else { mPath.setVisibility(View.VISIBLE); mPath.setText(hierarchyPath); jumpPreviousButton.setEnabled(true); jumpPreviousButton.setTextColor(getResources().getColor(R.color.cc_brand_color)); } } /** * used to go up one level in the formIndex. That is, if you're at 5_0, 1 (the second question * in a repeating group), this method will return a FormInex of 5_0 (the start of the repeating * group). If your at index 16 or 5_0, this will return null; */ public static FormIndex stepIndexOut(FormIndex index) { if (index.isTerminal()) { return null; } else { return new FormIndex(stepIndexOut(index.getNextLevel()), index); } } @Override protected void onListItemClick(ListView l, View v, int position, long id) { HierarchyElement h = (HierarchyElement)l.getItemAtPosition(position); if (h.getFormIndex() == null) { goUpLevel(); return; } switch (h.getType()) { case expanded: h.setType(HierarchyEntryType.collapsed); ArrayList<HierarchyElement> children = h.getChildren(); for (int i = 0; i < children.size(); i++) { formList.remove(position + 1); } h.setIcon(getResources().getDrawable(R.drawable.expander_ic_minimized)); break; case collapsed: h.setType(HierarchyEntryType.expanded); ArrayList<HierarchyElement> children1 = h.getChildren(); for (int i = 0; i < children1.size(); i++) { formList.add(position + 1 + i, children1.get(i)); } h.setIcon(getResources().getDrawable(R.drawable.expander_ic_maximized)); break; case question: FormEntryActivity.mFormController.jumpToIndex(h.getFormIndex()); setResult(RESULT_OK); finish(); return; case child: FormEntryActivity.mFormController.jumpToIndex(h.getFormIndex()); refreshView(); return; } // Should only get here if we've expanded or collapsed a group HierarchyListAdapter itla = new HierarchyListAdapter(this); itla.setListItems(formList); setListAdapter(itla); getListView().setSelection(position); } @Override public void onBackPressed() { if (FormEntryActivity.mFormController.getFormIndex().isTerminal()) { super.onBackPressed(); } else { goUpLevel(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { this.onBackPressed(); return true; } return super.onOptionsItemSelected(item); } }