package com.lateensoft.pathfinder.toolkit.views; import com.lateensoft.pathfinder.toolkit.R; import android.app.ActionBar; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; import android.os.Parcelable; import android.util.Log; import android.view.Gravity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View.OnTouchListener; import android.widget.ArrayAdapter; import android.widget.Spinner; import roboguice.activity.RoboActivity; /** * Base class for any activity which can edit a Parcelable, and return it as a result. * * The base does not hold any reference to the Parcelable itself, but requires implementations * to provide a reference to one. * * @author trevsiemens * */ public abstract class ParcelableEditorActivity extends RoboActivity { private static final String TAG = ParcelableEditorActivity.class.getSimpleName(); /** * Returned as a result code if the item originally passed should be deleted */ public static final int RESULT_DELETE = RESULT_FIRST_USER; /** * Key to be used when adding extra Parcelable to the activity's intent * Also used as key for extra Parcelable when returning data */ public static final String INTENT_EXTRAS_KEY_EDITABLE_PARCELABLE = "parcelable_to_edit"; public static final int DEFAULT_REQUEST_CODE = 14692; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActionBar actionBar = getActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); } setParcelableToEdit(getParcelableFromIntent(getIntent())); setupContentView(); invalidateOptionsMenu(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.base_editor_menu, menu); menu.findItem(R.id.mi_delete).setVisible(isParcelableDeletable()); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.mi_done) { try { updateEditedParcelableValues(); Log.v(TAG, "Add/Edit done"); Intent resultData = new Intent(); resultData.putExtra(INTENT_EXTRAS_KEY_EDITABLE_PARCELABLE, getEditedParcelable()); setResult(RESULT_OK, resultData); finish(); } catch (InvalidValueException e) { showErrorDialog(e.getMessage()); } } else if (item.getItemId() == R.id.mi_cancel || item.getItemId() == android.R.id.home) { setResult(RESULT_CANCELED); finish(); } else if (item.getItemId() == R.id.mi_delete) { showDeleteConfirmationDialog(); } else { return super.onOptionsItemSelected(item); } return true; } private void showErrorDialog(String message) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.error_alert_title); builder.setMessage(message); builder.setNeutralButton(R.string.ok_button_text, null); builder.show(); } private void showDeleteConfirmationDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.delete_alert_title); builder.setMessage(R.string.delete_alert_message); OnClickListener ocl = new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_NEGATIVE) { setResult(RESULT_DELETE); finish(); } } }; builder.setPositiveButton(R.string.cancel_button_text, ocl); builder.setNegativeButton(R.string.ok_button_text, ocl); builder.show(); } protected void setupSpinner(Spinner spinner, int optionResourceId, int defaultSelection, OnTouchListener touchListener) { ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, optionResourceId, android.R.layout.simple_spinner_item); setupSpinner(spinner, adapter, defaultSelection, touchListener); } protected void setupSpinner(Spinner spinner, String[] options, int defaultSelection, OnTouchListener touchListener) { ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, options); setupSpinner(spinner, adapter, defaultSelection, touchListener); } protected void setupSpinner(Spinner spinner, ArrayAdapter adapter, int defaultSelection, OnTouchListener touchListener) { adapter.setDropDownViewResource(R.layout.spinner_centered_wrapped); spinner.setGravity(Gravity.CENTER); spinner.setAdapter(adapter); spinner.setOnTouchListener(touchListener); spinner.setSelection(defaultSelection, false); } /** * Called by the ParcelableEditorActivity * Must perform all view setup, including calling setContentView */ protected abstract void setupContentView(); /** * Called by the ParcelableEditorActivity when the done button is pressed. * * This should update the values of the parcelable object (retrieved with getEditedParcelable) * from the current values shown by the UI * * @throws InvalidValueException - This should occur if the update failed, * and the ParcelableEditorActivity should not finish yet. The message given in the exception * will be shown as an error dialog */ protected abstract void updateEditedParcelableValues() throws InvalidValueException; /** * @return A direct reference to the parcelable object which is being edited. * The object provided by setParcelableToEdit, or a copy, should be returned if called just before. */ protected abstract Parcelable getEditedParcelable(); /** * Allow the ParcelableEditorActivity to set the value of * the Parcelable to be edited. This will only and always be called once onCreate. * @param p */ protected abstract void setParcelableToEdit(Parcelable p); /** * @return True if when the activity can return RESULT_DELETE as a result code, and show a delete button. False otherwise. */ protected abstract boolean isParcelableDeletable(); /** * Convenience method for safely extracting the edited parcelable from a returned intent * @return parcelable contained in extras of the intent */ public static <T extends Parcelable> T getParcelableFromIntent(Intent data) { Bundle extras = data.getExtras(); if (extras != null) { return extras.getParcelable(INTENT_EXTRAS_KEY_EDITABLE_PARCELABLE); } return null; } public static class InvalidValueException extends Exception { private static final long serialVersionUID = 5193787377071717441L; public InvalidValueException() { super("Invalid value"); } public InvalidValueException(String message) { super(message); } } }