Java tutorial
/* * Copyright (C) 2011 Tim Kramp * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package nl.spellenclubeindhoven.dominionshuffle; import android.app.AlertDialog; import android.app.Dialog; import android.app.TabActivity; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnKeyListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.Button; import android.widget.ListView; import android.widget.TabHost; import android.widget.Toast; import org.json.JSONException; import java.util.Collections; import java.util.LinkedList; import java.util.List; import nl.spellenclubeindhoven.dominionshuffle.data.Card; import nl.spellenclubeindhoven.dominionshuffle.data.CardComparator; import nl.spellenclubeindhoven.dominionshuffle.data.CardSelector; import nl.spellenclubeindhoven.dominionshuffle.data.Data; import nl.spellenclubeindhoven.dominionshuffle.data.Group; import nl.spellenclubeindhoven.dominionshuffle.data.Limit; import nl.spellenclubeindhoven.dominionshuffle.data.SectionedCardOrGroupAdapter; import nl.spellenclubeindhoven.dominionshuffle.data.SolveError; import nl.spellenclubeindhoven.dominionshuffle.widget.CustomFastScrollView; public class SelectActivity extends TabActivity implements OnScrollListener { private static final int MENU_SORT = 1; private static final int MENU_SHUFFLE = 2; private static final int MENU_LAST_RESULT = 3; private static final int MENU_CLEAR_ALL = 4; private static final int MENU_LOAD = 5; private static final int MENU_SAVE = 6; private static final int MENU_SETTINGS = 7; private static final int MENU_ABOUT = 8; private static final int DIALOG_SOLVE_ERROR = 1; private static final int DIALOG_NO_RESULT_ERROR = 2; private static final int DIALOG_SORT = 3; private static final int DIALOG_MINMAX = 4; private static final int DIALOG_MINIMUM = 100; private static final int DIALOG_MAXIMUM = 200; private ListView inexList; private ListView constraintList; private DataReader dataReader; private CardSelector cardSelector; private Application application; private InExAdapter inExAdapter; private ConstraintAdapter constraintAdapter; private CustomFastScrollView inexFastScrollView, constraintFastScrollView; @SuppressWarnings("unused") private DialogInterface dialog; private List<Object> groupsAndCards; private int dialogMimimumCount; private int dialogMaximumCount; private float lastActionUpX; // State will be remembered of the following variables private String dialogMessage; private Group selectedGroup; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.select); PreferenceManager.setDefaultValues(this, R.xml.preferences, false); application = (Application) getApplication(); dataReader = application.getDataReader(); cardSelector = application.getCardSelector(); TabHost tabs = getTabHost(); TabHost.TabSpec spec = tabs.newTabSpec("inex"); spec.setContent(R.id.inex_fastscrollview); spec.setIndicator(getResources().getString(R.string.tab_select), getResources().getDrawable(R.drawable.select_tab)); tabs.addTab(spec); spec = tabs.newTabSpec("constraint"); spec.setContent(R.id.constraint_fastscrollview); spec.setIndicator(getResources().getString(R.string.tab_constraints), getResources().getDrawable(R.drawable.limits_tab)); tabs.addTab(spec); spec = tabs.newTabSpec("generate"); spec.setContent(R.id.generateButtons); spec.setIndicator(getResources().getString(R.string.tab_generate), getResources().getDrawable(R.drawable.shuffle_tab)); tabs.addTab(spec); inexFastScrollView = ((CustomFastScrollView) findViewById(R.id.inex_fastscrollview)); inexFastScrollView.setOnScrollListener(this); constraintFastScrollView = ((CustomFastScrollView) findViewById(R.id.constraint_fastscrollview)); constraintFastScrollView.setOnScrollListener(this); groupsAndCards = new LinkedList<Object>(); inExAdapter = new InExAdapter(this, groupsAndCards, cardSelector, getPreferredCardComparator()); inexList = (ListView) findViewById(R.id.inexList); inexList.setAdapter(inExAdapter); inexList.setOnItemClickListener(onItemClickListener); inexList.setOnItemLongClickListener(onItemLongClickListener); constraintList = (ListView) findViewById(R.id.constraintList); constraintAdapter = new ConstraintAdapter(this, groupsAndCards, cardSelector, getPreferredCardComparator()); constraintList.setAdapter(constraintAdapter); constraintList.setOnItemClickListener(onItemClickListener); constraintList.setOnTouchListener(onConstraintListTouchListener); constraintList.setOnKeyListener(onConstraintKeyListener); constraintList.setOnItemLongClickListener(onItemLongClickListener); Button generateButton = (Button) findViewById(R.id.generateButton); generateButton.setOnClickListener(onGenerateClickListener); Button lastResultButton = (Button) findViewById(R.id.lastResultButton); lastResultButton.setOnClickListener(onLastResultClickListener); if (savedInstanceState != null) { dialogMessage = savedInstanceState.getString("dialogMessage"); if (dataReader.getData() != null) { selectedGroup = dataReader.getData().getGroup(savedInstanceState.getString("selectedGroup")); } } SharedPreferences prefs = getPreferences(MODE_PRIVATE); dialogMimimumCount = getResources().getStringArray(R.array.minumum_items_conditional).length; dialogMaximumCount = getResources().getStringArray(R.array.maximum_items).length; } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { switch (view.getId()) { case R.id.inexList: constraintList.setSelection(firstVisibleItem); break; case R.id.constraintList: inexList.setSelection(firstVisibleItem); break; } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // do nothing } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("dialogMessage", dialogMessage); if (selectedGroup != null) { outState.putString("selectedGroup", selectedGroup.getName()); } } @Override protected void onPause() { dataReader.saveCardSelectorState(this, cardSelector); super.onPause(); } @Override protected void onResume() { super.onResume(); loadData(); } @Override protected void onDestroy() { super.onDestroy(); } private static String[] subArray(String[] array, int start, int end) { int len = end - start; String[] result = new String[len]; System.arraycopy(array, start, result, 0, len); return result; } @Override protected Dialog onCreateDialog(int id) { if (DIALOG_MINIMUM <= id && id <= DIALOG_MINIMUM + dialogMimimumCount) { AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog alertDialog = builder .setSingleChoiceItems( subArray(getResources().getStringArray(R.array.minumum_items_conditional), 0, id - DIALOG_MINIMUM), cardSelector.getLimitMinimum(selectedGroup), onMinClickListener) .create(); alertDialog.setCanceledOnTouchOutside(true); return alertDialog; } else if (DIALOG_MAXIMUM <= id && id <= DIALOG_MAXIMUM + dialogMaximumCount) { AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog alertDialog = builder.setSingleChoiceItems( subArray(getResources().getStringArray(R.array.maximum_items), 0, id - DIALOG_MAXIMUM), cardSelector.getLimitMaximum(selectedGroup), onMaxClickListener).create(); alertDialog.setCanceledOnTouchOutside(true); return alertDialog; } switch (id) { case DIALOG_SOLVE_ERROR: { AlertDialog.Builder builder = new AlertDialog.Builder(this); return builder.setTitle(R.string.solve_dialog_title).setMessage(dialogMessage) .setIcon(android.R.drawable.ic_dialog_alert).setPositiveButton(R.string.ok, null).create(); } case DIALOG_NO_RESULT_ERROR: { AlertDialog.Builder builder = new AlertDialog.Builder(this); return builder.setTitle(R.string.display_result_dialog_title).setMessage(R.string.result_no_result) .setPositiveButton(R.string.ok, null).setIcon(android.R.drawable.ic_dialog_info).create(); } case DIALOG_SORT: { SharedPreferences prefs = getPreferences(MODE_PRIVATE); AlertDialog.Builder builder = new AlertDialog.Builder(this); return builder.setTitle(R.string.sort_cards_dialog_title) .setSingleChoiceItems(getResources().getStringArray(R.array.sort_items), prefs.getInt("sort", CardComparator.SORT_SET_COST_NAME), onSortClickListener) .create(); } case DIALOG_MINMAX: { AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog alertDialog = builder .setItems(getResources().getStringArray(R.array.minmax_array), onMinMaxClickListener).create(); alertDialog.setCanceledOnTouchOutside(true); return alertDialog; } default: return super.onCreateDialog(id); } } @Override protected void onPrepareDialog(int id, Dialog dialog) { if (DIALOG_MINIMUM <= id && id <= DIALOG_MINIMUM + dialogMimimumCount) { AlertDialog alertDialog = (AlertDialog) dialog; ListView list = alertDialog.getListView(); int pos; if (cardSelector.getCondition(selectedGroup) == null) { pos = cardSelector.getLimitMinimum(selectedGroup); if (pos >= 1) pos++; } else { pos = 1; } list.clearChoices(); list.setItemChecked(pos, true); list.setSelectionFromTop(pos, list.getHeight() / 2); } else if (DIALOG_MAXIMUM <= id && id <= DIALOG_MAXIMUM + dialogMaximumCount) { AlertDialog alertDialog = (AlertDialog) dialog; ListView list = alertDialog.getListView(); int pos = cardSelector.getLimitMaximum(selectedGroup); list.clearChoices(); list.setItemChecked(pos, true); list.setSelectionFromTop(pos, list.getHeight() / 2); } switch (id) { case DIALOG_SOLVE_ERROR: { AlertDialog alertDialog = (AlertDialog) dialog; alertDialog.setMessage(dialogMessage); break; } default: break; } super.onPrepareDialog(id, dialog); } private void loadCardSelectorState() { Data data = dataReader.getData(); if (data == null) return; try { String selectorData = DataReader.readStringFromFile(this, "card_selector.json"); if (selectorData == null || "".equals(selectorData)) { // Load Default Settings instead cardSelector.addIncludedGroup(data.getGroup("All")); cardSelector.setLimitMaximum(data.getGroup("Events_Landmarks"), 2); } else { cardSelector.fromJson(selectorData, dataReader.getData()); } } catch (JSONException ignore) { ignore.printStackTrace(); } } private void showSolveErrorDialog(String errorMessage) { this.dialogMessage = errorMessage; showDialog(DIALOG_SOLVE_ERROR); } private void showMinimumDialog(int maxValue) { if (maxValue != 0) maxValue++; if (maxValue >= dialogMimimumCount) { maxValue = dialogMimimumCount - 1; } showDialog(DIALOG_MINIMUM + maxValue + 1); } private void showMaximumDialog(int maxValue) { if (maxValue >= dialogMaximumCount) { maxValue = dialogMaximumCount - 1; } showDialog(DIALOG_MAXIMUM + maxValue + 1); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuItem item = menu.add(Menu.NONE, MENU_SORT, Menu.NONE, R.string.menu_sort); item.setIcon(android.R.drawable.ic_menu_sort_alphabetically); item = menu.add(Menu.NONE, MENU_CLEAR_ALL, Menu.NONE, R.string.menu_clear_all); item.setIcon(R.drawable.clear_all); item = menu.add(Menu.NONE, MENU_LOAD, Menu.NONE, R.string.menu_load); item.setIcon(android.R.drawable.ic_menu_upload); item = menu.add(Menu.NONE, MENU_SAVE, Menu.NONE, R.string.menu_save); item.setIcon(android.R.drawable.ic_menu_save); item = menu.add(Menu.NONE, MENU_SETTINGS, Menu.NONE, R.string.menu_settings); item.setIcon(R.drawable.globe); item = menu.add(Menu.NONE, MENU_LAST_RESULT, Menu.NONE, R.string.menu_last_result); item.setIcon(R.drawable.last_result); item = menu.add(Menu.NONE, MENU_ABOUT, Menu.NONE, R.string.menu_about); item.setIcon(android.R.drawable.stat_sys_warning); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_SORT: showDialog(DIALOG_SORT); return true; case MENU_LAST_RESULT: showLastResult(); return true; case MENU_CLEAR_ALL: clearAll(); return true; case MENU_LOAD: doLoadSelection(); return true; case MENU_SAVE: doSaveSelection(); return true; case MENU_SETTINGS: showSettings(); return true; case MENU_ABOUT: showAbout(); return true; default: return super.onOptionsItemSelected(item); } } private void doSaveSelection() { Intent intent = new Intent(this, LoadSaveActivity.class); intent.putExtra("load", false); startActivity(intent); } private void doLoadSelection() { Intent intent = new Intent(this, LoadSaveActivity.class); intent.putExtra("load", true); startActivity(intent); } private void clearAll() { cardSelector.clear(); constraintAdapter.notifyDataSetChanged(); inExAdapter.notifyDataSetChanged(); Toast.makeText(this, R.string.toast_all_cleared, Toast.LENGTH_SHORT).show(); } private void doShuffle() { Application application = (Application) getApplication(); try { application.setResult(cardSelector.generate(dataReader.getData())); startActivity(new Intent(getApplicationContext(), ResultActivity.class)); } catch (SolveError e) { showSolveErrorDialog(getResources().getString(e.getResourceId())); } } private void showAbout() { startActivity(new Intent(getApplicationContext(), ReleaseNotesActivity.class)); } private void showLastResult() { Application application = (Application) getApplication(); if (application.getResult() == null) { showDialog(DIALOG_NO_RESULT_ERROR); } else { startActivity(new Intent(getApplicationContext(), ResultActivity.class)); } } private void showLimitActivity() { Intent intent = new Intent(getApplicationContext(), LimitActivity.class); intent.putExtra("source", selectedGroup.getName()); startActivity(intent); } private void showSettings() { startActivity(new Intent(getApplicationContext(), SettingsActivity.class)); } private OnItemClickListener onItemClickListener = new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (parent.getId() == R.id.inexList) { Object cardOrGroup = inExAdapter.getItem(position); cardSelector.cycleIncludeExclude(cardOrGroup); CardOrGroupHolder holder = (CardOrGroupHolder) view.getTag(); holder.setCheckBox(cardSelector, cardOrGroup); } else if (parent.getId() == R.id.constraintList) { Object cardOrGroup = inExAdapter.getItem(position); CardOrGroupHolder holder = (CardOrGroupHolder) view.getTag(); if (cardOrGroup instanceof Card) { Card card = (Card) cardOrGroup; if (cardSelector.hasRequiredCard(card)) { cardSelector.removeRequiredCard(card); holder.setRequiredCheckBox(false); } else { cardSelector.addRequiredCard(card); holder.setRequiredCheckBox(true); } } else { // cardOrGroup instanceof Group selectedGroup = (Group) cardOrGroup; if (lastActionUpX < holder.getLeftArea()) { showMinimumDialog(selectedGroup.getCards().size()); } else if (lastActionUpX > holder.getRightArea()) { showMaximumDialog(selectedGroup.getCards().size()); } else { showDialog(DIALOG_MINMAX); } } } } }; private OnItemLongClickListener onItemLongClickListener = new OnItemLongClickListener() { public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { Object cardOrGroup; if (parent.getId() == R.id.inexList) { cardOrGroup = inExAdapter.getItem(position); } else { cardOrGroup = constraintAdapter.getItem(position); } if (cardOrGroup instanceof Group) { Group group = (Group) cardOrGroup; Intent intent = new Intent(getApplicationContext(), ShowGroupActivity.class); intent.putExtra("group", group.getName()); startActivity(intent); return true; } return false; } }; private OnTouchListener onConstraintListTouchListener = new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { lastActionUpX = event.getX(); } return false; } }; private OnKeyListener onConstraintKeyListener = new OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // If dpad click, reset the lastActionUpX lastActionUpX = v.getWidth() / 2; } return false; } }; private OnClickListener onGenerateClickListener = new OnClickListener() { public void onClick(View v) { doShuffle(); } }; private OnClickListener onLastResultClickListener = new OnClickListener() { public void onClick(View v) { showLastResult(); } }; private android.content.DialogInterface.OnClickListener onSortClickListener = new android.content.DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { SharedPreferences prefs = getPreferences(MODE_PRIVATE); SharedPreferences globalPrefs = PreferenceManager.getDefaultSharedPreferences(SelectActivity.this); prefs.edit().putInt("sort", which).commit(); CardComparator comparator = new CardComparator(which, SelectActivity.this); Collections.sort(groupsAndCards, comparator); inExAdapter.setCardComparator(comparator); constraintAdapter.setCardComparator(comparator); inExAdapter.notifyDataSetChanged(); constraintAdapter.notifyDataSetChanged(); inExAdapter.refreshSections(); inexFastScrollView.listItemsChanged(); constraintAdapter.refreshSections(); constraintFastScrollView.listItemsChanged(); dialog.dismiss(); } }; private CardComparator getPreferredCardComparator() { SharedPreferences prefs = getPreferences(MODE_PRIVATE); SharedPreferences globalPrefs = PreferenceManager.getDefaultSharedPreferences(SelectActivity.this); return new CardComparator(prefs.getInt("sort", CardComparator.SORT_SET_NAME), this); } private android.content.DialogInterface.OnClickListener onMinMaxClickListener = new android.content.DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: showMinimumDialog(selectedGroup.getCards().size()); break; case 1: showMaximumDialog(selectedGroup.getCards().size()); break; case 2: showLimitActivity(); break; case 3: cardSelector.removeLimit(selectedGroup); constraintAdapter.notifyDataSetChanged(); } } }; private android.content.DialogInterface.OnClickListener onMinClickListener = new android.content.DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (which == 1) { showLimitActivity(); } else { if (which > 1) which--; cardSelector.setLimitMinimum(selectedGroup, which); cardSelector.setCondition(selectedGroup, null); constraintAdapter.notifyDataSetChanged(); } dialog.dismiss(); } }; private android.content.DialogInterface.OnClickListener onMaxClickListener = new android.content.DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { cardSelector.setLimitMaximum(selectedGroup, which); constraintAdapter.notifyDataSetChanged(); dialog.dismiss(); } }; private void loadData() { dataReader.loadData(); afterDataLoadedStuff(); } private void reloadData() { application.setCardSelectedLoaded(false); dataReader.reset(); loadData(); } private void afterDataLoadedStuff() { groupsAndCards.clear(); groupsAndCards.addAll(dataReader.getData().getAll()); CardComparator comparator = getPreferredCardComparator(); inExAdapter.setCardComparator(comparator); constraintAdapter.setCardComparator(comparator); Collections.sort(groupsAndCards, comparator); if (!application.isCardSelectorLoaded()) { loadCardSelectorState(); application.setCardSelectedLoaded(true); application.loadResult(); } inExAdapter.notifyDataSetChanged(); constraintAdapter.notifyDataSetChanged(); inExAdapter.refreshSections(); inexFastScrollView.listItemsChanged(); } private static class InExAdapter extends SectionedCardOrGroupAdapter { public InExAdapter(Context context, List<Object> list, CardSelector cardSelector, CardComparator comparator) { super(context, R.layout.inex_listitem, list, cardSelector, comparator); } @Override public View getView(int position, View convertView, ViewGroup parent) { CardOrGroupHolder holder; if (convertView == null) { convertView = inflater.inflate(R.layout.inex_listitem, null); holder = new CardOrGroupHolder(convertView); convertView.setTag(holder); holder.hideCheckBoxValue(); } else { holder = (CardOrGroupHolder) convertView.getTag(); } Object cardOrGroup = getItem(position); if (cardOrGroup instanceof Card) { Card card = (Card) cardOrGroup; holder.setName(Localise.getCardName(card.getName(), getContext())); holder.setDescription(Localise.getSetName(card.getSet(), getContext())); holder.setIconValue(card.getCost()); holder.setCheckBox(cardSelector, card); } else if (cardOrGroup instanceof Group) { Group group = (Group) cardOrGroup; holder.setGroupName(Localise.getSetName(group.getName(), getContext()), group.getCards().size()); holder.setDescription(Localise.getSetDescription(group.getName(), getContext())); holder.setIconValue(null); holder.setCheckBox(cardSelector, group); } return convertView; } } private static class ConstraintAdapter extends SectionedCardOrGroupAdapter { public ConstraintAdapter(Context context, List<Object> list, CardSelector cardSelector, CardComparator comparator) { super(context, android.R.layout.simple_list_item_1, list, cardSelector, comparator); } @Override public View getView(int position, View convertView, ViewGroup parent) { CardOrGroupHolder holder; if (convertView == null) { convertView = inflater.inflate(R.layout.inex_listitem, null); holder = new CardOrGroupHolder(convertView); convertView.setTag(holder); } else { holder = (CardOrGroupHolder) convertView.getTag(); } Object cardOrGroup = getItem(position); if (cardOrGroup instanceof Card) { Card card = (Card) cardOrGroup; holder.setName(Localise.getCardName(card.getName(), getContext())); holder.setDescription(Localise.getSetName(card.getSet(), getContext())); holder.setIconValue(card.getCost()); holder.setRequiredCheckBox(cardSelector.hasRequiredCard(card)); } else if (cardOrGroup instanceof Group) { Group group = (Group) cardOrGroup; holder.setGroupName(Localise.getSetName(group.getName(), getContext()), group.getCards().size()); holder.setDescription(Localise.getSetDescription(group.getName(), getContext())); if (cardSelector.hasLimit(group)) { Limit rule = cardSelector.getLimit(group); holder.setMinValue(rule.getMinimum(), rule.getCondition() != null); holder.setMaxValue(rule.getMaximum()); } else { holder.setMinValue(0, false); holder.setMaxValue(0); } } return convertView; } } }