This commit is contained in:
Sergey Solovyev 2012-10-06 00:16:05 +04:00
parent 31c5551b4e
commit d4cff84040
3 changed files with 362 additions and 320 deletions

View File

@ -91,6 +91,8 @@ public enum CalculatorEventType {
// @NotNull CalculatorHistoryState // @NotNull CalculatorHistoryState
use_history_state, use_history_state,
clear_history_requested,
/* /*
********************************************************************** **********************************************************************
* *

View File

@ -9,6 +9,7 @@
<menu xmlns:a="http://schemas.android.com/apk/res/android"> <menu xmlns:a="http://schemas.android.com/apk/res/android">
<item a:id="@+id/history_menu_clear_history" <item a:id="@+id/history_menu_clear_history"
a:title="@string/c_clear_history"/> a:title="@string/c_clear_history"
a:showAsAction="always"/>
</menu> </menu>

View File

@ -1,319 +1,358 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ListView; import android.widget.ListView;
import com.actionbarsherlock.app.SherlockListFragment; import com.actionbarsherlock.app.SherlockListFragment;
import org.jetbrains.annotations.NotNull; import com.actionbarsherlock.view.Menu;
import org.jetbrains.annotations.Nullable; import com.actionbarsherlock.view.MenuInflater;
import org.solovyev.android.calculator.*; import com.actionbarsherlock.view.MenuItem;
import org.solovyev.android.calculator.about.CalculatorFragmentType; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.menu.AMenuBuilder; import org.solovyev.android.calculator.*;
import org.solovyev.android.menu.MenuImpl; import org.solovyev.android.calculator.about.CalculatorFragmentType;
import org.solovyev.common.collections.CollectionsUtils; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.equals.Equalizer; import org.solovyev.android.menu.*;
import org.solovyev.common.filter.Filter; import org.solovyev.android.sherlock.menu.SherlockMenuHelper;
import org.solovyev.common.filter.FilterRule; import org.solovyev.common.collections.CollectionsUtils;
import org.solovyev.common.filter.FilterRulesChain; import org.solovyev.common.equals.Equalizer;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.filter.Filter;
import org.solovyev.common.filter.FilterRule;
import java.util.ArrayList; import org.solovyev.common.filter.FilterRulesChain;
import java.util.Collections; import org.solovyev.common.text.StringUtils;
import java.util.Comparator;
import java.util.List; import java.util.ArrayList;
import java.util.Collections;
/** import java.util.Comparator;
* User: serso import java.util.List;
* Date: 10/15/11
* Time: 1:13 PM /**
*/ * User: serso
public abstract class AbstractCalculatorHistoryFragment extends SherlockListFragment implements CalculatorEventListener { * Date: 10/15/11
* Time: 1:13 PM
/* */
********************************************************************** public abstract class AbstractCalculatorHistoryFragment extends SherlockListFragment implements CalculatorEventListener {
*
* CONSTANTS /*
* **********************************************************************
********************************************************************** *
*/ * CONSTANTS
*
@NotNull **********************************************************************
private static final String TAG = "CalculatorHistoryFragment"; */
public static final Comparator<CalculatorHistoryState> COMPARATOR = new Comparator<CalculatorHistoryState>() { @NotNull
@Override private static final String TAG = "CalculatorHistoryFragment";
public int compare(CalculatorHistoryState state1, CalculatorHistoryState state2) {
if (state1.isSaved() == state2.isSaved()) { public static final Comparator<CalculatorHistoryState> COMPARATOR = new Comparator<CalculatorHistoryState>() {
long l = state2.getTime() - state1.getTime(); @Override
return l > 0l ? 1 : (l < 0l ? -1 : 0); public int compare(CalculatorHistoryState state1, CalculatorHistoryState state2) {
} else if (state1.isSaved()) { if (state1.isSaved() == state2.isSaved()) {
return -1; long l = state2.getTime() - state1.getTime();
} else if (state2.isSaved()) { return l > 0l ? 1 : (l < 0l ? -1 : 0);
return 1; } else if (state1.isSaved()) {
} return -1;
return 0; } else if (state2.isSaved()) {
} return 1;
}; }
return 0;
/* }
********************************************************************** };
*
* FIELDS /*
* **********************************************************************
********************************************************************** *
*/ * FIELDS
*
**********************************************************************
@NotNull */
private ArrayAdapter<CalculatorHistoryState> adapter;
@NotNull @NotNull
private CalculatorFragmentHelper fragmentHelper; private ArrayAdapter<CalculatorHistoryState> adapter;
protected AbstractCalculatorHistoryFragment(@NotNull CalculatorFragmentType fragmentType) { @NotNull
fragmentHelper = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId(), false); private CalculatorFragmentHelper fragmentHelper;
}
private ActivityMenu<Menu, MenuItem> menu = ListActivityMenu.fromResource(org.solovyev.android.calculator.R.menu.history_menu, HistoryMenu.class, SherlockMenuHelper.getInstance());
@Override
public void onCreate(Bundle savedInstanceState) { protected AbstractCalculatorHistoryFragment(@NotNull CalculatorFragmentType fragmentType) {
super.onCreate(savedInstanceState); fragmentHelper = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId(), false);
}
fragmentHelper.onCreate(this);
@Override
logDebug("onCreate"); public void onCreate(Bundle savedInstanceState) {
} super.onCreate(savedInstanceState);
private int logDebug(@NotNull String msg) { fragmentHelper.onCreate(this);
return Log.d(TAG + ": " + getTag(), msg);
} setHasOptionsMenu(true);
@Override logDebug("onCreate");
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { }
return fragmentHelper.onCreateView(this, inflater, container);
} private int logDebug(@NotNull String msg) {
return Log.d(TAG + ": " + getTag(), msg);
@Override }
public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState); @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
logDebug("onViewCreated"); return fragmentHelper.onCreateView(this, inflater, container);
}
fragmentHelper.onViewCreated(this, root);
@Override
adapter = new HistoryArrayAdapter(this.getActivity(), getItemLayoutId(), R.id.history_item, new ArrayList<CalculatorHistoryState>()); public void onViewCreated(View root, Bundle savedInstanceState) {
setListAdapter(adapter); super.onViewCreated(root, savedInstanceState);
final ListView lv = getListView(); logDebug("onViewCreated");
lv.setTextFilterEnabled(true);
fragmentHelper.onViewCreated(this, root);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(final AdapterView<?> parent, adapter = new HistoryArrayAdapter(this.getActivity(), getItemLayoutId(), org.solovyev.android.calculator.R.id.history_item, new ArrayList<CalculatorHistoryState>());
final View view, setListAdapter(adapter);
final int position,
final long id) { final ListView lv = getListView();
lv.setTextFilterEnabled(true);
useHistoryItem((CalculatorHistoryState) parent.getItemAtPosition(position));
} lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
}); public void onItemClick(final AdapterView<?> parent,
final View view,
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { final int position,
@Override final long id) {
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position); useHistoryItem((CalculatorHistoryState) parent.getItemAtPosition(position));
}
final Context context = getActivity(); });
final HistoryItemMenuData data = new HistoryItemMenuData(historyState, adapter); lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
final List<HistoryItemMenuItem> menuItems = CollectionsUtils.asList(HistoryItemMenuItem.values()); public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position);
if (historyState.isSaved()) {
menuItems.remove(HistoryItemMenuItem.save); final Context context = getActivity();
} else {
if (isAlreadySaved(historyState)) { final HistoryItemMenuData data = new HistoryItemMenuData(historyState, adapter);
menuItems.remove(HistoryItemMenuItem.save);
} final List<HistoryItemMenuItem> menuItems = CollectionsUtils.asList(HistoryItemMenuItem.values());
menuItems.remove(HistoryItemMenuItem.remove);
menuItems.remove(HistoryItemMenuItem.edit); if (historyState.isSaved()) {
} menuItems.remove(HistoryItemMenuItem.save);
} else {
if (historyState.getDisplayState().isValid() && StringUtils.isEmpty(historyState.getDisplayState().getEditorState().getText())) { if (isAlreadySaved(historyState)) {
menuItems.remove(HistoryItemMenuItem.copy_result); menuItems.remove(HistoryItemMenuItem.save);
} }
menuItems.remove(HistoryItemMenuItem.remove);
final AMenuBuilder<HistoryItemMenuItem, HistoryItemMenuData> menuBuilder = AMenuBuilder.newInstance(context, MenuImpl.newInstance(menuItems)); menuItems.remove(HistoryItemMenuItem.edit);
menuBuilder.create(data).show(); }
return true; if (historyState.getDisplayState().isValid() && StringUtils.isEmpty(historyState.getDisplayState().getEditorState().getText())) {
} menuItems.remove(HistoryItemMenuItem.copy_result);
}); }
}
final AMenuBuilder<HistoryItemMenuItem, HistoryItemMenuData> menuBuilder = AMenuBuilder.newInstance(context, MenuImpl.newInstance(menuItems));
@Override menuBuilder.create(data).show();
public void onResume() {
super.onResume(); return true;
}
this.fragmentHelper.onResume(this); });
}
updateAdapter();
} @Override
public void onResume() {
@Override super.onResume();
public void onPause() {
this.fragmentHelper.onPause(this); this.fragmentHelper.onResume(this);
super.onPause(); updateAdapter();
} }
@Override @Override
public void onDestroy() { public void onPause() {
logDebug("onDestroy"); this.fragmentHelper.onPause(this);
fragmentHelper.onDestroy(this); super.onPause();
}
super.onDestroy();
} @Override
public void onDestroy() {
protected abstract int getItemLayoutId(); logDebug("onDestroy");
private void updateAdapter() { fragmentHelper.onDestroy(this);
final List<CalculatorHistoryState> historyList = getHistoryList();
super.onDestroy();
final ArrayAdapter<CalculatorHistoryState> adapter = getAdapter(); }
try {
adapter.setNotifyOnChange(false); protected abstract int getItemLayoutId();
adapter.clear();
for (CalculatorHistoryState historyState : historyList) { private void updateAdapter() {
adapter.add(historyState); final List<CalculatorHistoryState> historyList = getHistoryList();
}
} finally { final ArrayAdapter<CalculatorHistoryState> adapter = getAdapter();
adapter.setNotifyOnChange(true); try {
} adapter.setNotifyOnChange(false);
adapter.clear();
adapter.notifyDataSetChanged(); for (CalculatorHistoryState historyState : historyList) {
} adapter.add(historyState);
}
public static boolean isAlreadySaved(@NotNull CalculatorHistoryState historyState) { } finally {
assert !historyState.isSaved(); adapter.setNotifyOnChange(true);
}
boolean result = false;
try { adapter.notifyDataSetChanged();
historyState.setSaved(true); }
if ( CollectionsUtils.contains(historyState, CalculatorLocatorImpl.getInstance().getHistory().getSavedHistory(), new Equalizer<CalculatorHistoryState>() {
@Override public static boolean isAlreadySaved(@NotNull CalculatorHistoryState historyState) {
public boolean equals(@Nullable CalculatorHistoryState first, @Nullable CalculatorHistoryState second) { assert !historyState.isSaved();
return first != null && second != null &&
first.getTime() == second.getTime() && boolean result = false;
first.getDisplayState().equals(second.getDisplayState()) && try {
first.getEditorState().equals(second.getEditorState()); historyState.setSaved(true);
} if ( CollectionsUtils.contains(historyState, CalculatorLocatorImpl.getInstance().getHistory().getSavedHistory(), new Equalizer<CalculatorHistoryState>() {
}) ) { @Override
result = true; public boolean equals(@Nullable CalculatorHistoryState first, @Nullable CalculatorHistoryState second) {
} return first != null && second != null &&
} finally { first.getTime() == second.getTime() &&
historyState.setSaved(false); first.getDisplayState().equals(second.getDisplayState()) &&
} first.getEditorState().equals(second.getEditorState());
return result; }
} }) ) {
result = true;
public static void useHistoryItem(@NotNull final CalculatorHistoryState historyState) { }
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.use_history_state, historyState); } finally {
} historyState.setSaved(false);
}
@NotNull return result;
private List<CalculatorHistoryState> getHistoryList() { }
final List<CalculatorHistoryState> calculatorHistoryStates = getHistoryItems();
public static void useHistoryItem(@NotNull final CalculatorHistoryState historyState) {
Collections.sort(calculatorHistoryStates, COMPARATOR); CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.use_history_state, historyState);
}
final FilterRulesChain<CalculatorHistoryState> filterRulesChain = new FilterRulesChain<CalculatorHistoryState>();
filterRulesChain.addFilterRule(new FilterRule<CalculatorHistoryState>() { @NotNull
@Override private List<CalculatorHistoryState> getHistoryList() {
public boolean isFiltered(CalculatorHistoryState object) { final List<CalculatorHistoryState> calculatorHistoryStates = getHistoryItems();
return object == null || StringUtils.isEmpty(object.getEditorState().getText());
} Collections.sort(calculatorHistoryStates, COMPARATOR);
});
final FilterRulesChain<CalculatorHistoryState> filterRulesChain = new FilterRulesChain<CalculatorHistoryState>();
new Filter<CalculatorHistoryState>(filterRulesChain).filter(calculatorHistoryStates.iterator()); filterRulesChain.addFilterRule(new FilterRule<CalculatorHistoryState>() {
@Override
return calculatorHistoryStates; public boolean isFiltered(CalculatorHistoryState object) {
} return object == null || StringUtils.isEmpty(object.getEditorState().getText());
}
@NotNull });
protected abstract List<CalculatorHistoryState> getHistoryItems();
new Filter<CalculatorHistoryState>(filterRulesChain).filter(calculatorHistoryStates.iterator());
@NotNull
public static String getHistoryText(@NotNull CalculatorHistoryState state) { return calculatorHistoryStates;
final StringBuilder result = new StringBuilder(); }
result.append(state.getEditorState().getText());
result.append(getIdentitySign(state.getDisplayState().getJsclOperation())); @NotNull
final String expressionResult = state.getDisplayState().getEditorState().getText(); protected abstract List<CalculatorHistoryState> getHistoryItems();
if (expressionResult != null) {
result.append(expressionResult); @NotNull
} public static String getHistoryText(@NotNull CalculatorHistoryState state) {
return result.toString(); final StringBuilder result = new StringBuilder();
} result.append(state.getEditorState().getText());
result.append(getIdentitySign(state.getDisplayState().getJsclOperation()));
@NotNull final String expressionResult = state.getDisplayState().getEditorState().getText();
private static String getIdentitySign(@NotNull JsclOperation jsclOperation) { if (expressionResult != null) {
return jsclOperation == JsclOperation.simplify ? "" : "="; result.append(expressionResult);
} }
return result.toString();
// todo serso: menu }
/* @Override
public boolean onCreateOptionsMenu(android.view.Menu menu) { @NotNull
final MenuInflater menuInflater = getMenuInflater(); private static String getIdentitySign(@NotNull JsclOperation jsclOperation) {
menuInflater.inflate(R.menu.history_menu, menu); return jsclOperation == JsclOperation.simplify ? "" : "=";
return true; }
}
protected abstract void clearHistory();
@Override
public boolean onOptionsItemSelected(MenuItem item) { @NotNull
boolean result; protected ArrayAdapter<CalculatorHistoryState> getAdapter() {
return adapter;
switch (item.getItemId()) { }
case R.id.history_menu_clear_history:
clearHistory(); @Override
result = true; public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
break; switch (calculatorEventType) {
default: case history_state_added:
result = super.onOptionsItemSelected(item); getActivity().runOnUiThread(new Runnable() {
} @Override
public void run() {
return result; logDebug("onCalculatorEvent");
}*/ updateAdapter();
}
protected abstract void clearHistory(); });
break;
@NotNull
protected ArrayAdapter<CalculatorHistoryState> getAdapter() { case clear_history_requested:
return adapter; getActivity().runOnUiThread(new Runnable() {
} @Override
public void run() {
@Override clearHistory();
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) { }
if ( calculatorEventType == CalculatorEventType.history_state_added ) { });
break;
getActivity().runOnUiThread(new Runnable() { }
@Override
public void run() { }
logDebug("onCalculatorEvent");
updateAdapter(); /*
} **********************************************************************
}); *
} * 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(org.solovyev.android.calculator.R.id.history_menu_clear_history) {
@Override
public void onClick(@NotNull MenuItem data, @NotNull Context context) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.clear_history_requested, null);
}
};
private final int itemId;
HistoryMenu(int itemId) {
this.itemId = itemId;
}
@NotNull
@Override
public Integer getItemId() {
return this.itemId;
}
}
}