package org.odk.collect.android.widgets; import java.util.Vector; import org.javarosa.core.model.SelectChoice; import org.javarosa.core.model.data.IAnswerData; import org.javarosa.core.model.data.SelectMultiData; import org.javarosa.core.model.data.helper.Selection; import org.javarosa.form.api.FormEntryPrompt; import org.odk.collect.android.R; import org.odk.collect.android.utilities.StringUtils; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.util.TypedValue; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.TextView; /** * SpinnerMultiWidget, like SelectMultiWidget handles multiple selection fields using checkboxes, * but the user clicks a button to see the checkboxes. The goal is to be more compact. If images, * audio, or video are specified in the select answers they are ignored. WARNING: There is a bug in * android versions previous to 2.0 that affects this widget. You can find the report here: * http://code.google.com/p/android/issues/detail?id=922 This bug causes text to be white in alert * boxes, which makes the select options invisible in this widget. For this reason, this widget * should not be used on phones with android versions lower than 2.0. * * @author Jeff Beorse (jeff@beorse.net) */ public class SpinnerMultiWidget extends QuestionWidget { Vector<SelectChoice> mItems; // The possible select answers CharSequence[] answer_items; // The button to push to display the answers to choose from Button button; // Defines which answers are selected boolean[] selections; // The alert box that contains the answer selection view AlertDialog.Builder alert_builder; // Displays the current selections below the button TextView selectionText; @SuppressWarnings("unchecked") public SpinnerMultiWidget(final Context context, FormEntryPrompt prompt) { super(context, prompt); mItems = prompt.getSelectChoices(); mPrompt = prompt; selections = new boolean[mItems.size()]; answer_items = new CharSequence[mItems.size()]; alert_builder = new AlertDialog.Builder(context); button = new Button(context); selectionText = new TextView(getContext()); // Build View for (int i = 0; i < mItems.size(); i++) { answer_items[i] = prompt.getSelectChoiceText(mItems.get(i)); } selectionText.setText(StringUtils.getStringRobust(context, R.string.selected)); selectionText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mQuestionFontsize); selectionText.setVisibility(View.GONE); button.setText(StringUtils.getStringRobust(context, R.string.select_answer)); button.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mQuestionFontsize); button.setPadding(0, 0, 0, 7); // Give the button a click listener. This defines the alert as well. All the // click and selection behavior is defined here. button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { alert_builder.setTitle(mPrompt.getQuestionText()).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { boolean first = true; selectionText.setText(""); for (int i = 0; i < selections.length; i++) { if (selections[i]) { if (first) { first = false; selectionText.setText(StringUtils.getStringRobust(context, R.string.selected) + answer_items[i].toString()); selectionText.setVisibility(View.VISIBLE); } else { selectionText.setText(selectionText.getText() + ", " + answer_items[i].toString()); } } } if(hasListener){ widgetChangedListener.widgetEntryChanged(); } } }); alert_builder.setMultiChoiceItems(answer_items, selections, new DialogInterface.OnMultiChoiceClickListener() { /* * (non-Javadoc) * @see android.content.DialogInterface.OnMultiChoiceClickListener#onClick(android.content.DialogInterface, int, boolean) */ @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { selections[which] = isChecked; if(hasListener){ widgetChangedListener.widgetEntryChanged(); } } }); AlertDialog alert = alert_builder.create(); alert.show(); widgetEntryChanged(); } }); // Fill in previous answers Vector<Selection> ve = new Vector<Selection>(); if (prompt.getAnswerValue() != null) { ve = (Vector<Selection>) prompt.getAnswerValue().getValue(); } if (ve != null) { boolean first = true; for (int i = 0; i < selections.length; ++i) { String value = prompt.getSelectChoices().get(i).getValue(); boolean found = false; for (Selection s : ve) { if (value.equals(s.getValue())) { found = true; break; } } selections[i] = found; if (found) { if (first) { first = false; selectionText.setText(StringUtils.getStringRobust(context, R.string.selected) + answer_items[i].toString()); selectionText.setVisibility(View.VISIBLE); } else { selectionText.setText(selectionText.getText() + ", " + answer_items[i].toString()); } } } } addView(button); addView(selectionText); } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#getAnswer() */ @Override public IAnswerData getAnswer() { Vector<Selection> vc = new Vector<Selection>(); for (int i = 0; i < mItems.size(); i++) { if (selections[i]) { SelectChoice sc = mItems.get(i); vc.add(new Selection(sc)); } } if (vc.size() == 0) { return null; } else { return new SelectMultiData(vc); } } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#clearAnswer() */ @Override public void clearAnswer() { selectionText.setText(R.string.selected); selectionText.setVisibility(View.GONE); for (int i = 0; i < selections.length; i++) { selections[i] = false; } } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#setFocus(android.content.Context) */ @Override public void setFocus(Context context) { // Hide the soft keyboard if it's showing. InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); inputManager.hideSoftInputFromWindow(this.getWindowToken(), 0); } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#setOnLongClickListener(android.view.View.OnLongClickListener) */ @Override public void setOnLongClickListener(OnLongClickListener l) { button.setOnLongClickListener(l); } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#cancelLongPress() */ @Override public void cancelLongPress() { super.cancelLongPress(); button.cancelLongPress(); } }