Java tutorial
/* * Copyright 2013 serso aka se.solovyev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Contact details * * Email: se.solovyev@gmail.com * Site: http://se.solovyev.org */ package org.solovyev.android.calculator.history; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.FragmentActivity; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import com.actionbarsherlock.app.SherlockListFragment; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.menu.*; import org.solovyev.android.sherlock.menu.SherlockMenuHelper; import org.solovyev.common.JPredicate; import org.solovyev.common.collections.Collections; import org.solovyev.common.equals.Equalizer; import org.solovyev.common.filter.Filter; import org.solovyev.common.filter.FilterRulesChain; import org.solovyev.common.text.Strings; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import static org.solovyev.android.calculator.CalculatorEventType.clear_history_requested; /** * User: serso * Date: 10/15/11 * Time: 1:13 PM */ public abstract class AbstractCalculatorHistoryFragment extends SherlockListFragment implements CalculatorEventListener { /* ********************************************************************** * * CONSTANTS * ********************************************************************** */ @Nonnull private static final String TAG = "CalculatorHistoryFragment"; public static final Comparator<CalculatorHistoryState> COMPARATOR = new Comparator<CalculatorHistoryState>() { @Override public int compare(CalculatorHistoryState state1, CalculatorHistoryState state2) { if (state1.isSaved() == state2.isSaved()) { long l = state2.getTime() - state1.getTime(); return l > 0l ? 1 : (l < 0l ? -1 : 0); } else if (state1.isSaved()) { return -1; } else if (state2.isSaved()) { return 1; } return 0; } }; /* ********************************************************************** * * FIELDS * ********************************************************************** */ @Nonnull private HistoryArrayAdapter adapter; @Nonnull private CalculatorFragmentHelper fragmentHelper; private final ActivityMenu<Menu, MenuItem> menu = ListActivityMenu.fromResource(R.menu.history_menu, HistoryMenu.class, SherlockMenuHelper.getInstance(), new HistoryMenuFilter()); @Nonnull private final SharedPreferences.OnSharedPreferenceChangeListener preferencesListener = new HistoryOnPreferenceChangeListener(); protected AbstractCalculatorHistoryFragment(@Nonnull CalculatorFragmentType fragmentType) { fragmentHelper = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId(), false); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); fragmentHelper.onCreate(this); setHasOptionsMenu(true); logDebug("onCreate"); } private int logDebug(@Nonnull String msg) { return Log.d(TAG + ": " + getTag(), msg); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return fragmentHelper.onCreateView(this, inflater, container); } @Override public void onViewCreated(View root, Bundle savedInstanceState) { super.onViewCreated(root, savedInstanceState); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); final Boolean showDatetime = CalculatorPreferences.History.showDatetime.getPreference(preferences); fragmentHelper.onViewCreated(this, root); adapter = new HistoryArrayAdapter(this.getActivity(), getItemLayoutId(), org.solovyev.android.calculator.R.id.history_item, new ArrayList<CalculatorHistoryState>(), showDatetime); setListAdapter(adapter); final ListView lv = getListView(); lv.setTextFilterEnabled(true); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) { useHistoryItem((CalculatorHistoryState) parent.getItemAtPosition(position)); } }); lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) { final CalculatorHistoryState historyState = (CalculatorHistoryState) parent .getItemAtPosition(position); final FragmentActivity activity = getActivity(); final HistoryItemMenuData data = new HistoryItemMenuData(historyState, adapter); final List<HistoryItemMenuItem> menuItems = Collections.asList(HistoryItemMenuItem.values()); if (historyState.isSaved()) { menuItems.remove(HistoryItemMenuItem.save); } else { if (isAlreadySaved(historyState)) { menuItems.remove(HistoryItemMenuItem.save); } menuItems.remove(HistoryItemMenuItem.remove); menuItems.remove(HistoryItemMenuItem.edit); } if (historyState.getDisplayState().isValid() && Strings.isEmpty(historyState.getDisplayState().getEditorState().getText())) { menuItems.remove(HistoryItemMenuItem.copy_result); } final ContextMenuBuilder<HistoryItemMenuItem, HistoryItemMenuData> menuBuilder = ContextMenuBuilder .newInstance(activity, "history-menu", ListContextMenu.newInstance(menuItems)); menuBuilder.build(data).show(); return true; } }); } @Override public void onResume() { super.onResume(); this.fragmentHelper.onResume(this); updateAdapter(); PreferenceManager.getDefaultSharedPreferences(getActivity()) .registerOnSharedPreferenceChangeListener(preferencesListener); } @Override public void onPause() { PreferenceManager.getDefaultSharedPreferences(getActivity()) .unregisterOnSharedPreferenceChangeListener(preferencesListener); this.fragmentHelper.onPause(this); super.onPause(); } @Override public void onDestroy() { logDebug("onDestroy"); fragmentHelper.onDestroy(this); super.onDestroy(); } protected abstract int getItemLayoutId(); private void updateAdapter() { final List<CalculatorHistoryState> historyList = getHistoryList(); final ArrayAdapter<CalculatorHistoryState> adapter = getAdapter(); try { adapter.setNotifyOnChange(false); adapter.clear(); for (CalculatorHistoryState historyState : historyList) { adapter.add(historyState); } } finally { adapter.setNotifyOnChange(true); } adapter.notifyDataSetChanged(); } public static boolean isAlreadySaved(@Nonnull CalculatorHistoryState historyState) { assert !historyState.isSaved(); boolean result = false; try { historyState.setSaved(true); if (Collections.contains(historyState, Locator.getInstance().getHistory().getSavedHistory(), new Equalizer<CalculatorHistoryState>() { @Override public boolean areEqual(@Nullable CalculatorHistoryState first, @Nullable CalculatorHistoryState second) { return first != null && second != null && first.getTime() == second.getTime() && first.getDisplayState().equals(second.getDisplayState()) && first.getEditorState().equals(second.getEditorState()); } })) { result = true; } } finally { historyState.setSaved(false); } return result; } public static void useHistoryItem(@Nonnull final CalculatorHistoryState historyState) { Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.use_history_state, historyState); } @Nonnull private List<CalculatorHistoryState> getHistoryList() { final List<CalculatorHistoryState> calculatorHistoryStates = getHistoryItems(); java.util.Collections.sort(calculatorHistoryStates, COMPARATOR); final FilterRulesChain<CalculatorHistoryState> filterRulesChain = new FilterRulesChain<CalculatorHistoryState>(); filterRulesChain.addFilterRule(new JPredicate<CalculatorHistoryState>() { @Override public boolean apply(CalculatorHistoryState object) { return object == null || Strings.isEmpty(object.getEditorState().getText()); } }); new Filter<CalculatorHistoryState>(filterRulesChain).filter(calculatorHistoryStates.iterator()); return calculatorHistoryStates; } @Nonnull protected abstract List<CalculatorHistoryState> getHistoryItems(); @Nonnull public static String getHistoryText(@Nonnull CalculatorHistoryState state) { final StringBuilder result = new StringBuilder(); result.append(state.getEditorState().getText()); result.append(getIdentitySign(state.getDisplayState().getJsclOperation())); final String expressionResult = state.getDisplayState().getEditorState().getText(); if (expressionResult != null) { result.append(expressionResult); } return result.toString(); } @Nonnull private static String getIdentitySign(@Nonnull JsclOperation jsclOperation) { return jsclOperation == JsclOperation.simplify ? "" : "="; } protected abstract void clearHistory(); @Nonnull protected HistoryArrayAdapter getAdapter() { return adapter; } @Override public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { switch (calculatorEventType) { case history_state_added: getActivity().runOnUiThread(new Runnable() { @Override public void run() { logDebug("onCalculatorEvent"); updateAdapter(); } }); break; case clear_history_requested: getActivity().runOnUiThread(new Runnable() { @Override public void run() { clearHistory(); } }); break; } } /* ********************************************************************** * * MENU * ********************************************************************** */ @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { this.menu.onCreateOptionsMenu(this.getActivity(), menu); } @Override public void onPrepareOptionsMenu(Menu menu) { this.menu.onPrepareOptionsMenu(this.getActivity(), menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { return this.menu.onOptionsItemSelected(this.getActivity(), item); } private static enum HistoryMenu implements IdentifiableMenuItem<MenuItem> { clear_history(R.id.menu_history_clear_history) { @Override public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { Locator.getInstance().getCalculator().fireCalculatorEvent(clear_history_requested, null); } }, toggle_datetime(R.id.menu_history_toggle_datetime) { @Override public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { final SharedPreferences preferences = PreferenceManager .getDefaultSharedPreferences(CalculatorApplication.getInstance()); final Boolean showDatetime = CalculatorPreferences.History.showDatetime.getPreference(preferences); CalculatorPreferences.History.showDatetime.putPreference(preferences, !showDatetime); } }, fullscreen(R.id.menu_history_fullscreen) { @Override public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { context.startActivity(new Intent(context, CalculatorHistoryActivity.class)); } }; private final int itemId; HistoryMenu(int itemId) { this.itemId = itemId; } @Nonnull @Override public Integer getItemId() { return this.itemId; } } private class HistoryMenuFilter implements JPredicate<AMenuItem<MenuItem>> { @Override public boolean apply(@Nullable AMenuItem<MenuItem> menuItem) { boolean result = false; if (menuItem instanceof IdentifiableMenuItem<?>) { switch (((IdentifiableMenuItem) menuItem).getItemId()) { case R.id.menu_history_fullscreen: result = !fragmentHelper.isPane(AbstractCalculatorHistoryFragment.this); break; } } return result; } } /* ********************************************************************** * * STATIC/INNER * ********************************************************************** */ private final class HistoryOnPreferenceChangeListener implements SharedPreferences.OnSharedPreferenceChangeListener { @Override public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { if (CalculatorPreferences.History.showDatetime.isSameKey(key)) { getAdapter().setShowDatetime(CalculatorPreferences.History.showDatetime.getPreference(preferences)); } } } }