/*
* Copyright (C) 2012 - 2013 Niall 'Rivernile' Scott
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors or contributors be held liable for
* any damages arising from the use of this software.
*
* The aforementioned copyright holder(s) hereby grant you a
* non-transferrable right to use this software for any purpose (including
* commercial applications), and to modify it and redistribute it, subject to
* the following conditions:
*
* 1. This notice may not be removed or altered from any file it appears in.
*
* 2. Any modifications made to this software, except those defined in
* clause 3 of this agreement, must be released under this license, and
* the source code of any modifications must be made available on a
* publically accessible (and locateable) website, or sent to the
* original author of this software.
*
* 3. Software modifications that do not alter the functionality of the
* software but are simply adaptations to a specific environment are
* exempt from clause 2.
*/
package uk.org.rivernile.edinburghbustracker.android.fragments.dialogs;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import uk.org.rivernile.edinburghbustracker.android.R;
/**
* This DialogFragment allows the user to select bus services from a list and
* store the user's selection. This may be used to ask the user to filter bus
* services or to say which services they are interested in.
*
* @author Niall Scott
*/
public class ServicesChooserDialogFragment extends DialogFragment {
/** The argument name for services. */
private static final String ARG_SERVICES = "services";
/** The argument name for the default selected services. */
private static final String ARG_SELECTED_SERVICES = "selectedServices";
/** The argument name for the dialog title. */
private static final String ARG_TITLE = "dialogTitle";
/** The argument name for check boxes, stored in the instance state. */
private static final String ARG_CHECK_BOXES = "checkBoxes";
private Callbacks callbacks;
private String[] services;
private boolean[] checkBoxes;
/**
* Create a new instance of this Fragment, providing a list of services to
* select from, a list of services to select by default and a title for the
* Dialog.
*
* @param services The list of services to show to the user.
* @param selectedServices The services to select by default, null if none.
* @param dialogTitle The title to use for the Dialog.
* @return A new instance of this Fragment.
*/
public static ServicesChooserDialogFragment newInstance(
final String[] services, final String[] selectedServices,
final String dialogTitle) {
final ServicesChooserDialogFragment f =
new ServicesChooserDialogFragment();
final Bundle b = new Bundle();
b.putStringArray(ARG_SERVICES, services);
b.putStringArray(ARG_SELECTED_SERVICES, selectedServices);
b.putString(ARG_TITLE, dialogTitle);
f.setArguments(b);
return f;
}
/**
* {@inheritDoc}
*/
@Override
public void onAttach(final Activity activity) {
super.onAttach(activity);
try {
callbacks = (Callbacks) activity;
} catch (ClassCastException e) {
throw new IllegalStateException(activity.getClass().getName() +
" does not implement " + Callbacks.class.getName());
}
}
/**
* {@inheritDoc}
*/
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Bundle args = getArguments();
services = args.getStringArray(ARG_SERVICES);
// Do sanity checks.
if(services == null || services.length == 0) {
throw new IllegalArgumentException("A list of services must " +
"be supplied.");
}
if(savedInstanceState != null) {
// If there is a previous instance, get the args from the saved
// instance state.
checkBoxes = savedInstanceState.getBooleanArray(ARG_CHECK_BOXES);
} else {
final String[] selectedServices = args
.getStringArray(ARG_SELECTED_SERVICES);
checkBoxes = new boolean[services.length];
if (selectedServices != null && selectedServices.length > 0) {
int i;
final int len = services.length;
for (i = 0; i < len; i++) {
for (String s : selectedServices) {
if (services[i].equals(s)) {
checkBoxes[i] = true;
break;
}
}
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
// Save the state.
outState.putBooleanArray(ARG_CHECK_BOXES, checkBoxes);
}
/**
* {@inheritDoc}
*/
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
// Build the Dialog.
final AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity());
builder.setTitle(getArguments().getString(ARG_TITLE));
builder.setMultiChoiceItems(services, checkBoxes,
new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(final DialogInterface dialog,
final int which, boolean isChecked) {
// Change the flag for that service.
checkBoxes[which] = isChecked;
}
});
builder.setPositiveButton(R.string.close, null);
return builder.create();
}
/**
* {@inheritDoc}
*/
@Override
public void onDismiss(final DialogInterface dialog) {
super.onDismiss(dialog);
// Tell the listener that there may be changes.
callbacks.onServicesChosen(getChosenServices());
}
/**
* Get the list of services that was supplied to the constructor.
*
* @return A list of bus services to choose from.
*/
public String[] getServices() {
return services;
}
/**
* Get a String array of the chosen services.
*
* @return A String array of the chosen services.
*/
public String[] getChosenServices() {
int counter = 0;
// Firstly, count the number of chosen services so we know how big to
// make the String array.
for(boolean b : checkBoxes) {
if(b) counter++;
}
// If there's no chosen services, return an empty array.
if(counter == 0) return new String[] { };
// Create the array of the determined size.
final String[] items = new String[counter];
int i = 0;
final int len = checkBoxes.length;
// Loop through the check boxes, if it is selected, add it to the output
// String array.
for(int j = 0; j < len; j++) {
if(checkBoxes[j]) {
items[i] = services[j];
i++;
}
}
return items;
}
/**
* Get a String representation of the chosen services.
*
* @return A String representation of the chosen services.
*/
public String getChosenServicesAsString() {
return getChosenServicesAsString(getChosenServices());
}
/**
* Get a String representation of the chosen services.
*
* @param chosenServices A String array of chosen services.
* @return A String representation of the chosen services.
*/
public static String getChosenServicesAsString(
final String[] chosenServices) {
// If there are no chosen services, return an empty String.
if(chosenServices == null || chosenServices.length == 0) {
return "";
}
final StringBuilder sb = new StringBuilder();
boolean isFirst = true;
for(String s : chosenServices) {
if(isFirst) {
// Used to format the String correctly.
sb.append(s);
isFirst = false;
} else {
sb.append(',').append(' ').append(s);
}
}
return sb.toString();
}
/**
* Any Activities which host this Fragment must implement this interface to
* handle navigation events.
*/
public static interface Callbacks {
/**
* This is called when the user dismisses the service chooser dialog.
* This will get called even when no services are chosen, and may not
* necessarily mean that the user has made a new selection.
*
* @param chosenServices A String array of chosen services.
*/
public void onServicesChosen(String[] chosenServices);
}
}