android_calculator-4: Extend history functionality

This commit is contained in:
Sergey Solovyev 2011-12-18 00:47:58 +04:00
parent 8d6d6bc044
commit 38152fe80d
26 changed files with 940 additions and 215 deletions

View File

@ -28,6 +28,7 @@
<string name="p_calc_round_result">true</string>
<string name="p_calc_vars">org.solovyev.android.calculator.CalculatorModel_vars</string>
<string name="p_calc_history">org.solovyev.android.calculator.CalculatorModel_history</string>
<string name="p_calc_angle_units_key">org.solovyev.android.calculator.CalculatorActivity_angle_units</string>
<string name="p_calc_angle_units">deg</string>

View File

@ -299,4 +299,7 @@ Check the \'Round result\' preference in application settings - it should be tur
<string name="c_swipe_distance">Swipe distance for buttons</string>
<string name="c_swipe_distance_summary">Sets swipe distance for buttons that support additional swipe actions</string>
<string name="c_comment">Comment</string>
<string name="c_history_item_saved">Saved</string>
</resources>

View File

@ -1,27 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import java.util.Date;
/**
* User: serso
* Date: 10/15/11
* Time: 1:45 PM
*/
public class AbstractHistoryState {
@NotNull
private final Date time = new Date();
@NotNull
public Date getTime() {
return time;
}
}

View File

@ -26,6 +26,7 @@ import jscl.AngleUnit;
import jscl.NumeralBase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.history.CalculatorHistoryState;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.view.FontSizeAdjuster;

View File

@ -24,7 +24,7 @@ import org.solovyev.android.view.AutoResizeTextView;
* Date: 9/17/11
* Time: 10:58 PM
*/
public class CalculatorDisplay extends AutoResizeTextView {
public class CalculatorDisplay extends AutoResizeTextView implements ICalculatorDisplay{
private boolean valid = true;
@ -52,10 +52,12 @@ public class CalculatorDisplay extends AutoResizeTextView {
super(context, attrs, defStyle);
}
@Override
public boolean isValid() {
return valid;
}
@Override
public void setValid(boolean valid) {
this.valid = valid;
if (valid) {
@ -63,19 +65,23 @@ public class CalculatorDisplay extends AutoResizeTextView {
}
}
@Override
@Nullable
public String getErrorMessage() {
return errorMessage;
}
@Override
public void setErrorMessage(@Nullable String errorMessage) {
this.errorMessage = errorMessage;
}
@Override
public void setJsclOperation(@NotNull JsclOperation jsclOperation) {
this.jsclOperation = jsclOperation;
}
@Override
@NotNull
public JsclOperation getJsclOperation() {
return jsclOperation;
@ -111,12 +117,24 @@ public class CalculatorDisplay extends AutoResizeTextView {
resizeText();
}
@Override
public void setGenericResult(@Nullable Generic genericResult) {
this.genericResult = genericResult;
}
@Override
@Nullable
public Generic getGenericResult() {
return genericResult;
}
@Override
public int getSelection() {
return this.getSelectionStart();
}
@Override
public void setSelection(int selection) {
// not supported by TextView
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.utils.history.HistoryAction;
import org.solovyev.common.utils.history.HistoryHelper;
import org.solovyev.common.utils.history.SimpleHistoryHelper;
import java.util.List;
/**
* User: serso
* Date: 10/9/11
* Time: 6:35 PM
*/
public enum CalculatorHistory implements HistoryHelper<CalculatorHistoryState> {
instance;
private final HistoryHelper<CalculatorHistoryState> historyHelper = new SimpleHistoryHelper<CalculatorHistoryState>();
@Override
public boolean isEmpty() {
return this.historyHelper.isEmpty();
}
@Override
public CalculatorHistoryState getLastHistoryState() {
return this.historyHelper.getLastHistoryState();
}
@Override
public boolean isUndoAvailable() {
return historyHelper.isUndoAvailable();
}
@Override
public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) {
return historyHelper.undo(currentState);
}
@Override
public boolean isRedoAvailable() {
return historyHelper.isRedoAvailable();
}
@Override
public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) {
return historyHelper.redo(currentState);
}
@Override
public boolean isActionAvailable(@NotNull HistoryAction historyAction) {
return historyHelper.isActionAvailable(historyAction);
}
@Override
public CalculatorHistoryState doAction(@NotNull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) {
return historyHelper.doAction(historyAction, currentState);
}
@Override
public void addState(@Nullable CalculatorHistoryState currentState) {
historyHelper.addState(currentState);
}
@NotNull
@Override
public List<CalculatorHistoryState> getStates() {
return historyHelper.getStates();
}
@Override
public void clear() {
this.historyHelper.clear();
}
}

View File

@ -6,13 +6,20 @@
package org.solovyev.android.calculator;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.*;
import android.widget.*;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.history.CalculatorHistory;
import org.solovyev.android.calculator.history.CalculatorHistoryState;
import org.solovyev.android.calculator.history.EditorHistoryState;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.view.prefs.ResourceCache;
import org.solovyev.common.utils.Filter;
import org.solovyev.common.utils.FilterRule;
import org.solovyev.common.utils.FilterRulesChain;
@ -31,6 +38,9 @@ import java.util.List;
*/
public class CalculatorHistoryActivity extends ListActivity {
@NotNull
private HistoryArrayAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -43,7 +53,8 @@ public class CalculatorHistoryActivity extends ListActivity {
this.finish();
}
setListAdapter(new HistoryArrayAdapter(this, R.layout.history, R.id.history_item, historyList));
adapter = new HistoryArrayAdapter(this, R.layout.history, R.id.history_item, historyList);
setListAdapter(adapter);
final ListView lv = getListView();
lv.setTextFilterEnabled(true);
@ -70,15 +81,62 @@ public class CalculatorHistoryActivity extends ListActivity {
CalculatorHistoryActivity.this.finish();
}
});
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position);
final Context context = CalculatorHistoryActivity.this;
final CharSequence[] items = {context.getText(R.string.c_save), context.getText(R.string.c_remove)};
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if (item == 0) {
if (!historyState.isSaved()) {
historyState.setSaved(true);
CalculatorHistory.instance.getSavedHistory().addState(historyState);
CalculatorHistory.instance.save(context);
CalculatorHistoryActivity.this.adapter.notifyDataSetChanged();
Toast.makeText(context, "History item was successfully saved!", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "History item was already saved!", Toast.LENGTH_LONG).show();
}
} else if (item == 1) {
if (historyState.isSaved()) {
historyState.setSaved(false);
CalculatorHistory.instance.save(context);
CalculatorHistory.instance.getSavedHistory().clear();
CalculatorHistory.instance.load(context, PreferenceManager.getDefaultSharedPreferences(context));
CalculatorHistoryActivity.this.adapter.notifyDataSetChanged();
Toast.makeText(context, "History item was removed!", Toast.LENGTH_LONG).show();
}
}
}
});
builder.create().show();
return true;
}
});
}
private static List<CalculatorHistoryState> getHistoryList() {
final List<CalculatorHistoryState> calculatorHistoryStates = new ArrayList<CalculatorHistoryState>(CalculatorHistory.instance.getStates());
calculatorHistoryStates.addAll(CalculatorHistory.instance.getSavedHistory().getStates());
Collections.sort(calculatorHistoryStates, new Comparator<CalculatorHistoryState>() {
@Override
public int compare(CalculatorHistoryState state1, CalculatorHistoryState state2) {
return state2.getTime().compareTo(state1.getTime());
if ( state1.isSaved() == state2.isSaved() ) {
return state2.getTime().compareTo(state1.getTime());
} else if ( state1.isSaved() ) {
return -1;
} else if ( state2.isSaved() ) {
return 1;
}
return 0;
}
});
@ -111,7 +169,21 @@ public class CalculatorHistoryActivity extends ListActivity {
time.setText(new SimpleDateFormat().format(state.getTime()));
final TextView editor = (TextView) result.findViewById(R.id.history_item);
editor.setText(state.getEditorState().getText() + getIdentitySign(state.getDisplayState().getJsclOperation()) + state.getDisplayState().getEditorHistoryState().getText());
final StringBuilder historyText = new StringBuilder();
historyText.append(state.getEditorState().getText());
historyText.append(getIdentitySign(state.getDisplayState().getJsclOperation()));
historyText.append(state.getDisplayState().getEditorState().getText());
final String comment = state.getComment();
if (!StringUtils.isEmpty(comment)) {
historyText.append("\n");
historyText.append(ResourceCache.instance.getCaption("c_comment")).append(": ");
historyText.append(comment);
}
if ( state.isSaved() ) {
historyText.append("\n");
historyText.append(ResourceCache.instance.getCaption("c_history_item_saved"));
}
editor.setText(historyText);
return result;
}
@ -147,6 +219,7 @@ public class CalculatorHistoryActivity extends ListActivity {
private void clearHistory() {
CalculatorHistory.instance.clear();
Toast.makeText(this, R.string.c_history_is_empty, Toast.LENGTH_SHORT).show();
this.finish();
}

View File

@ -22,6 +22,9 @@ import jscl.math.Generic;
import jscl.math.function.Constant;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.history.CalculatorHistory;
import org.solovyev.android.calculator.history.CalculatorHistoryState;
import org.solovyev.android.calculator.history.TextViewEditorAdapter;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.CalculatorEngine;
@ -335,8 +338,8 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
synchronized (CalculatorHistory.instance) {
Log.d(this.getClass().getName(), "Saved history found: " + editorHistoryState);
setValuesFromHistory(this.editor, editorHistoryState.getEditorState());
setValuesFromHistory(this.display, editorHistoryState.getDisplayState());
editorHistoryState.setValuesFromHistory(new TextViewEditorAdapter(this.editor), this.display);
final String expression = this.editor.getText().toString();
if ( !StringUtils.isEmpty(expression) ) {
@ -350,37 +353,14 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
}
}
private void setValuesFromHistory(@NotNull CalculatorDisplay display, CalculatorDisplayHistoryState editorHistoryState) {
setValuesFromHistory(display, editorHistoryState.getEditorHistoryState());
display.setValid(editorHistoryState.isValid());
display.setErrorMessage(editorHistoryState.getErrorMessage());
display.setJsclOperation(editorHistoryState.getJsclOperation());
display.setGenericResult(editorHistoryState.getGenericResult());
}
private void setValuesFromHistory(@NotNull TextView editText, EditorHistoryState editorHistoryState) {
editText.setText(editorHistoryState.getText());
if (editText instanceof EditText) {
((EditText) editText).setSelection(editorHistoryState.getCursorPosition());
}
}
@Override
@NotNull
public CalculatorHistoryState getCurrentHistoryState() {
synchronized (CalculatorHistory.instance) {
return new CalculatorHistoryState(getEditorHistoryState(this.editor), getCalculatorDisplayHistoryState(this.display));
return CalculatorHistoryState.newInstance(new TextViewEditorAdapter(this.editor), this.display);
}
}
private EditorHistoryState getEditorHistoryState(@NotNull TextView textView) {
return EditorHistoryState.newInstance(textView);
}
private CalculatorDisplayHistoryState getCalculatorDisplayHistoryState(@NotNull CalculatorDisplay display) {
return CalculatorDisplayHistoryState.newInstance(display);
}
@NotNull
public CalculatorDisplay getDisplay() {
return display;

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.history.Editor;
import org.solovyev.android.calculator.jscl.JsclOperation;
/**
* User: serso
* Date: 12/17/11
* Time: 9:45 PM
*/
public interface ICalculatorDisplay extends Editor{
boolean isValid();
void setValid(boolean valid);
@Nullable
String getErrorMessage();
void setErrorMessage(@Nullable String errorMessage);
void setJsclOperation(@NotNull JsclOperation jsclOperation);
@NotNull
JsclOperation getJsclOperation();
void setGenericResult(@Nullable Generic genericResult);
@Nullable
Generic getGenericResult();
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Transient;
import java.util.Date;
/**
* User: serso
* Date: 10/15/11
* Time: 1:45 PM
*/
public class AbstractHistoryState {
@Element
@NotNull
private Date time = new Date();
@Element(required = false)
@Nullable
private String comment;
@Transient
private boolean saved;
@NotNull
public Date getTime() {
return time;
}
public void setTime(@NotNull Date time) {
this.time = time;
}
@Nullable
public String getComment() {
return comment;
}
public void setComment(@Nullable String comment) {
this.comment = comment;
}
public boolean isSaved() {
return saved;
}
public void setSaved(boolean saved) {
this.saved = saved;
}
}

View File

@ -3,11 +3,15 @@
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator;
package org.solovyev.android.calculator.history;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.Transient;
import org.solovyev.android.calculator.ICalculatorDisplay;
import org.solovyev.android.calculator.jscl.JsclOperation;
/**
@ -15,30 +19,38 @@ import org.solovyev.android.calculator.jscl.JsclOperation;
* Date: 9/17/11
* Time: 11:05 PM
*/
@Root
public class CalculatorDisplayHistoryState {
@Transient
private boolean valid = true;
@Transient
@Nullable
private String errorMessage = null;
@Element
@NotNull
private EditorHistoryState editorHistoryState;
private EditorHistoryState editorState;
@Element
@NotNull
private JsclOperation jsclOperation;
@Transient
@Nullable
private Generic genericResult;
private CalculatorDisplayHistoryState() {
// for xml
}
@NotNull
public static CalculatorDisplayHistoryState newInstance(@NotNull CalculatorDisplay display) {
public static CalculatorDisplayHistoryState newInstance(@NotNull ICalculatorDisplay display) {
final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState();
result.editorHistoryState = EditorHistoryState.newInstance(display);
result.editorState = EditorHistoryState.newInstance(display);
result.valid = display.isValid();
result.jsclOperation = display.getJsclOperation();
result.genericResult = display.getGenericResult();
@ -47,13 +59,22 @@ public class CalculatorDisplayHistoryState {
return result;
}
public void setValuesFromHistory(@NotNull ICalculatorDisplay display) {
this.getEditorState().setValuesFromHistory(display);
display.setValid(this.isValid());
display.setErrorMessage(this.getErrorMessage());
display.setJsclOperation(this.getJsclOperation());
display.setGenericResult(this.getGenericResult());
}
public boolean isValid() {
return valid;
}
@NotNull
public EditorHistoryState getEditorHistoryState() {
return editorHistoryState;
public EditorHistoryState getEditorState() {
return editorState;
}
@NotNull
@ -71,6 +92,7 @@ public class CalculatorDisplayHistoryState {
return genericResult;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -78,9 +100,7 @@ public class CalculatorDisplayHistoryState {
CalculatorDisplayHistoryState that = (CalculatorDisplayHistoryState) o;
if (valid != that.valid) return false;
if (!editorHistoryState.equals(that.editorHistoryState)) return false;
if (errorMessage != null ? !errorMessage.equals(that.errorMessage) : that.errorMessage != null) return false;
if (!editorState.equals(that.editorState)) return false;
if (jsclOperation != that.jsclOperation) return false;
return true;
@ -88,9 +108,7 @@ public class CalculatorDisplayHistoryState {
@Override
public int hashCode() {
int result = (valid ? 1 : 0);
result = 31 * result + (errorMessage != null ? errorMessage.hashCode() : 0);
result = 31 * result + editorHistoryState.hashCode();
int result = editorState.hashCode();
result = 31 * result + jsclOperation.hashCode();
return result;
}
@ -100,7 +118,7 @@ public class CalculatorDisplayHistoryState {
return "CalculatorDisplayHistoryState{" +
"valid=" + valid +
", errorMessage='" + errorMessage + '\'' +
", editorHistoryState=" + editorHistoryState +
", editorHistoryState=" + editorState +
", jsclOperation=" + jsclOperation +
'}';
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
import org.solovyev.common.utils.history.HistoryAction;
import org.solovyev.common.utils.history.HistoryHelper;
import org.solovyev.common.utils.history.SimpleHistoryHelper;
import java.util.List;
/**
* User: serso
* Date: 10/9/11
* Time: 6:35 PM
*/
public enum CalculatorHistory implements HistoryHelper<CalculatorHistoryState> {
instance;
@NotNull
private final HistoryHelper<CalculatorHistoryState> history = new SimpleHistoryHelper<CalculatorHistoryState>();
@NotNull
private final HistoryHelper<CalculatorHistoryState> savedHistory = new SimpleHistoryHelper<CalculatorHistoryState>();
@Override
public boolean isEmpty() {
return this.history.isEmpty();
}
@Override
public CalculatorHistoryState getLastHistoryState() {
return this.history.getLastHistoryState();
}
@Override
public boolean isUndoAvailable() {
return history.isUndoAvailable();
}
@Override
public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) {
return history.undo(currentState);
}
@Override
public boolean isRedoAvailable() {
return history.isRedoAvailable();
}
@Override
public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) {
return history.redo(currentState);
}
@Override
public boolean isActionAvailable(@NotNull HistoryAction historyAction) {
return history.isActionAvailable(historyAction);
}
@Override
public CalculatorHistoryState doAction(@NotNull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) {
return history.doAction(historyAction, currentState);
}
@Override
public void addState(@Nullable CalculatorHistoryState currentState) {
history.addState(currentState);
}
@NotNull
@Override
public List<CalculatorHistoryState> getStates() {
return history.getStates();
}
@Override
public void clear() {
this.history.clear();
}
@NotNull
public HistoryHelper<CalculatorHistoryState> getSavedHistory() {
return savedHistory;
}
public void load(@Nullable Context context, @Nullable SharedPreferences preferences) {
if (context != null && preferences != null) {
final String value = preferences.getString(context.getString(R.string.p_calc_history), null);
HistoryUtils.fromXml(value, this.savedHistory);
}
}
public void save(@NotNull Context context) {
final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
final SharedPreferences.Editor editor = settings.edit();
editor.putString(context.getString(R.string.p_calc_history), HistoryUtils.toXml(this.savedHistory));
editor.commit();
}
}

View File

@ -3,29 +3,46 @@
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator;
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
import org.solovyev.android.calculator.ICalculatorDisplay;
/**
* User: serso
* Date: 9/11/11
* Time: 12:16 AM
*/
public class CalculatorHistoryState extends AbstractHistoryState{
@Root
public class CalculatorHistoryState extends AbstractHistoryState {
@Element
@NotNull
private EditorHistoryState editorState;
@Element
@NotNull
private CalculatorDisplayHistoryState displayState;
public CalculatorHistoryState(@NotNull EditorHistoryState editorState,
private CalculatorHistoryState() {
// for xml
}
private CalculatorHistoryState(@NotNull EditorHistoryState editorState,
@NotNull CalculatorDisplayHistoryState displayState) {
this.editorState = editorState;
this.displayState = displayState;
}
public static CalculatorHistoryState newInstance(@NotNull Editor editor, @NotNull ICalculatorDisplay display) {
final EditorHistoryState editorHistoryState = EditorHistoryState.newInstance(editor);
final CalculatorDisplayHistoryState displayHistoryState = CalculatorDisplayHistoryState.newInstance(display);
return new CalculatorHistoryState(editorHistoryState, displayHistoryState);
}
@NotNull
public EditorHistoryState getEditorState() {
return editorState;
@ -71,4 +88,9 @@ public class CalculatorHistoryState extends AbstractHistoryState{
result = 31 * result + displayState.hashCode();
return result;
}
public void setValuesFromHistory(@NotNull Editor editor, @NotNull ICalculatorDisplay display) {
this.getEditorState().setValuesFromHistory(editor);
this.getDisplayState().setValuesFromHistory(display);
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/17/11
* Time: 9:37 PM
*/
public interface Editor {
@Nullable
CharSequence getText();
void setText(@Nullable CharSequence text);
int getSelection();
void setSelection(int selection);
}

View File

@ -3,33 +3,42 @@
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator;
package org.solovyev.android.calculator.history;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
@Root
public class EditorHistoryState {
@Element
private int cursorPosition;
@Element(required = false)
@Nullable
private String text;
private EditorHistoryState() {
// for xml
}
@NotNull
public static EditorHistoryState newInstance(@NotNull TextView textView) {
public static EditorHistoryState newInstance(@NotNull Editor editor) {
final EditorHistoryState result = new EditorHistoryState();
result.text = String.valueOf(textView.getText());
result.cursorPosition = textView.getSelectionStart();
result.text = String.valueOf(editor.getText());
result.cursorPosition = editor.getSelection();
return result;
}
public void setValuesFromHistory(@NotNull Editor editor) {
editor.setText(this.getText());
editor.setSelection(this.getCursorPosition());
}
@Nullable
public String getText() {
return text;

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;
import java.util.ArrayList;
import java.util.List;
/**
* User: serso
* Date: 12/17/11
* Time: 9:30 PM
*/
@Root
public class History {
@ElementList
private List<CalculatorHistoryState> historyItems = new ArrayList<CalculatorHistoryState>();
public History() {
}
public List<CalculatorHistoryState> getHistoryItems() {
return historyItems;
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import org.solovyev.common.utils.history.HistoryHelper;
import java.io.StringWriter;
/**
* User: serso
* Date: 12/17/11
* Time: 9:59 PM
*/
class HistoryUtils {
// not intended for instantiation
private HistoryUtils() {
throw new AssertionError();
}
public static void fromXml(@Nullable String xml, @NotNull HistoryHelper<CalculatorHistoryState> calculatorHistory) {
if (xml != null) {
final Serializer serializer = new Persister();
try {
final History history = serializer.read(History.class, xml);
for (CalculatorHistoryState historyItem : history.getHistoryItems()) {
calculatorHistory.addState(historyItem);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@NotNull
public static String toXml(@NotNull HistoryHelper<CalculatorHistoryState> calculatorHistory) {
final History history = new History();
for (CalculatorHistoryState historyState : calculatorHistory.getStates()) {
if (historyState.isSaved()) {
history.getHistoryItems().add(historyState);
}
}
final StringWriter xml = new StringWriter();
final Serializer serializer = new Persister();
try {
serializer.write(history, xml);
} catch (Exception e) {
throw new RuntimeException(e);
}
return xml.toString();
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import android.widget.EditText;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/17/11
* Time: 9:39 PM
*/
public class TextViewEditorAdapter implements Editor {
@NotNull
private final TextView textView;
public TextViewEditorAdapter(@NotNull TextView textView) {
this.textView = textView;
}
@Override
public CharSequence getText() {
return textView.getText().toString();
}
@Override
public void setText(@Nullable CharSequence text) {
textView.setText(text);
}
@Override
public int getSelection() {
return textView.getSelectionStart();
}
@Override
public void setSelection(int selection) {
if ( textView instanceof EditText ) {
((EditText) textView).setSelection(selection);
}
}
}

View File

@ -18,6 +18,8 @@ import org.solovyev.android.calculator.model.TextProcessor;
*/
class FromJsclNumericTextProcessor implements TextProcessor<String, Generic> {
public static final FromJsclNumericTextProcessor instance = new FromJsclNumericTextProcessor();
@NotNull
@Override
public String process(@NotNull Generic numeric) throws CalculatorParseException {

View File

@ -16,66 +16,55 @@ import org.solovyev.android.calculator.model.TextProcessor;
public enum JsclOperation {
simplify(new FromJsclSimplifyTextProcessor()) {
@NotNull
@Override
public String evaluate(@NotNull String expression) throws ParseException {
return CalculatorEngine.instance.getEngine().simplify(expression);
}
simplify,
elementary,
numeric;
@NotNull
@Override
public Generic evaluateGeneric(@NotNull String expression) throws ParseException {
return CalculatorEngine.instance.getEngine().simplifyGeneric(expression);
}
},
elementary(DummyTextProcessor.instance) {
@NotNull
@Override
public String evaluate(@NotNull String expression) throws ParseException {
return CalculatorEngine.instance.getEngine().elementary(expression);
}
@NotNull
@Override
public Generic evaluateGeneric(@NotNull String expression) throws ParseException {
return CalculatorEngine.instance.getEngine().elementaryGeneric(expression);
}
},
numeric(new FromJsclNumericTextProcessor()) {
@NotNull
@Override
public String evaluate(@NotNull String expression) throws ParseException {
return CalculatorEngine.instance.getEngine().evaluate(expression);
}
@NotNull
@Override
public Generic evaluateGeneric(@NotNull String expression) throws ParseException {
return CalculatorEngine.instance.getEngine().evaluateGeneric(expression);
}
};
@NotNull
private final TextProcessor<String, Generic> fromProcessor;
JsclOperation(@NotNull TextProcessor<String, Generic> fromProcessor) {
this.fromProcessor = fromProcessor;
JsclOperation() {
}
@NotNull
public TextProcessor<String, Generic> getFromProcessor() {
return fromProcessor;
switch (this) {
case simplify:
return FromJsclSimplifyTextProcessor.instance;
case elementary:
return DummyTextProcessor.instance;
case numeric:
return FromJsclNumericTextProcessor.instance;
default:
throw new UnsupportedOperationException();
}
}
@NotNull
public abstract String evaluate(@NotNull String expression) throws ParseException;
public final String evaluate(@NotNull String expression) throws ParseException {
switch (this) {
case simplify:
return CalculatorEngine.instance.getEngine().simplify(expression);
case elementary:
return CalculatorEngine.instance.getEngine().elementary(expression);
case numeric:
return CalculatorEngine.instance.getEngine().evaluate(expression);
default:
throw new UnsupportedOperationException();
}
}
@NotNull
public abstract Generic evaluateGeneric(@NotNull String expression) throws ParseException;
public final Generic evaluateGeneric(@NotNull String expression) throws ParseException {
switch (this) {
case simplify:
return CalculatorEngine.instance.getEngine().simplifyGeneric(expression);
case elementary:
return CalculatorEngine.instance.getEngine().elementaryGeneric(expression);
case numeric:
return CalculatorEngine.instance.getEngine().evaluateGeneric(expression);
default:
throw new UnsupportedOperationException();
}
}
}

View File

@ -19,7 +19,7 @@ import org.solovyev.common.math.MathRegistry;
*/
public interface AndroidVarsRegistry extends MathRegistry<Var>{
void init(@Nullable Context context, @Nullable SharedPreferences preferences);
void load(@Nullable Context context, @Nullable SharedPreferences preferences);
void save(@NotNull Context context);
}

View File

@ -37,7 +37,7 @@ class AndroidVarsRegistryImpl implements AndroidVarsRegistry {
this.mathRegistry = mathRegistry;
}
public synchronized void init(@Nullable Context context, @Nullable SharedPreferences preferences) {
public synchronized void load(@Nullable Context context, @Nullable SharedPreferences preferences) {
if (context != null && preferences != null) {
final String value = preferences.getString(context.getString(R.string.p_calc_vars), null);

View File

@ -283,7 +283,7 @@ public enum CalculatorEngine {
}
}
varsRegister.init(context, preferences);
varsRegister.load(context, preferences);
}
}

View File

@ -15,6 +15,8 @@ import java.util.List;
*/
public class FromJsclSimplifyTextProcessor implements TextProcessor<String, Generic> {
public static final FromJsclSimplifyTextProcessor instance = new FromJsclSimplifyTextProcessor();
public FromJsclSimplifyTextProcessor() {
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.common;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.utils.Equalizer;
/**
* User: serso
* Date: 12/17/11
* Time: 11:11 PM
*/
public enum SameEqualizer implements Equalizer {
instance;
private SameEqualizer() {
}
@Override
public boolean equals(@Nullable Object first, @Nullable Object second) {
return first == second;
}
}

View File

@ -0,0 +1,306 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import jscl.math.Generic;
import junit.framework.Assert;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.Test;
import org.solovyev.android.calculator.ICalculatorDisplay;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.utils.CollectionEqualizer;
import org.solovyev.common.utils.EqualsTool;
import org.solovyev.common.utils.history.HistoryHelper;
import org.solovyev.common.utils.history.SimpleHistoryHelper;
import java.util.Date;
/**
* User: serso
* Date: 12/17/11
* Time: 10:01 PM
*/
public class HistoryUtilsTest {
@Test
public void testFromXml() throws Exception {
}
private static final String emptyHistory = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\"/>\n" +
"</history>";
private static final String toXml1 = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\">\n" +
" <calculatorHistoryState>\n" +
" <time>1970-01-02 06:46:40.0 MSK</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
private static final String toXml2 = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\">\n" +
" <calculatorHistoryState>\n" +
" <time>1970-01-02 06:46:40.0 MSK</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>1970-01-02 06:46:40.0 MSK</time>\n" +
" <editorState>\n" +
" <cursorPosition>2</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>1970-01-02 06:46:40.0 MSK</time>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text>null</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>elementary</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>1970-01-02 06:46:40.0 MSK</time>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
@Test
public void testToXml() throws Exception {
final Date date = new Date(100000000);
HistoryHelper<CalculatorHistoryState> history = new SimpleHistoryHelper<CalculatorHistoryState>();
ICalculatorDisplay calculatorDisplay = new TestCalculatorDisplay();
calculatorDisplay.setErrorMessage("error_msg1");
calculatorDisplay.setText("Error");
calculatorDisplay.setSelection(1);
calculatorDisplay.setJsclOperation(JsclOperation.simplify);
Editor calculatorEditor = new TestEditor();
calculatorEditor.setSelection(3);
calculatorEditor.setText("1+1");
CalculatorHistoryState state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay);
state.setTime(date);
history.addState(state);
Assert.assertEquals(emptyHistory, HistoryUtils.toXml(history));
state.setSaved(true);
Assert.assertEquals(toXml1, HistoryUtils.toXml(history));
calculatorDisplay = new TestCalculatorDisplay();
calculatorDisplay.setErrorMessage(null);
calculatorDisplay.setText("5/6");
calculatorDisplay.setSelection(3);
calculatorDisplay.setJsclOperation(JsclOperation.numeric);
calculatorEditor = new TestEditor();
calculatorEditor.setSelection(2);
calculatorEditor.setText("5/6");
state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay);
state.setSaved(true);
state.setTime(date);
history.addState(state);
calculatorDisplay = new TestCalculatorDisplay();
calculatorDisplay.setErrorMessage("error_msg2");
calculatorDisplay.setText("Error");
calculatorDisplay.setSelection(1);
calculatorDisplay.setJsclOperation(JsclOperation.elementary);
calculatorEditor = new TestEditor();
calculatorEditor.setSelection(1);
calculatorEditor.setText(null);
state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay);
state.setSaved(true);
state.setTime(date);
history.addState(state);
calculatorDisplay = new TestCalculatorDisplay();
calculatorDisplay.setErrorMessage(null);
calculatorDisplay.setText("4+5/35sin(41)+dfdsfsdfs");
calculatorDisplay.setSelection(1);
calculatorDisplay.setJsclOperation(JsclOperation.numeric);
calculatorEditor = new TestEditor();
calculatorEditor.setSelection(0);
calculatorEditor.setText("4+5/35sin(41)+dfdsfsdfs");
state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay);
state.setSaved(true);
state.setTime(date);
history.addState(state);
String xml = HistoryUtils.toXml(history);
Assert.assertEquals(toXml2, xml);
final HistoryHelper<CalculatorHistoryState> historyFromXml = new SimpleHistoryHelper<CalculatorHistoryState>();
HistoryUtils.fromXml(xml, historyFromXml);
Assert.assertEquals(history.getStates().size(), historyFromXml.getStates().size());
Assert.assertTrue(EqualsTool.areEqual(history.getStates(), historyFromXml.getStates(), new CollectionEqualizer<CalculatorHistoryState>(null)));
}
private static class TestCalculatorDisplay implements ICalculatorDisplay {
@NotNull
private final TestEditor testEditor = new TestEditor();
private boolean valid;
private String errorMessage;
private JsclOperation operation;
private Generic genericResult;
@Override
public boolean isValid() {
return this.valid;
}
@Override
public void setValid(boolean valid) {
this.valid = valid;
}
@Override
public String getErrorMessage() {
return this.errorMessage;
}
@Override
public void setErrorMessage(@Nullable String errorMessage) {
this.errorMessage = errorMessage;
}
@Override
public void setJsclOperation(@NotNull JsclOperation jsclOperation) {
this.operation = jsclOperation;
}
@NotNull
@Override
public JsclOperation getJsclOperation() {
return this.operation;
}
@Override
public void setGenericResult(@Nullable Generic genericResult) {
this.genericResult = genericResult;
}
@Override
public Generic getGenericResult() {
return this.genericResult;
}
@Override
public CharSequence getText() {
return this.testEditor.getText();
}
@Override
public void setText(@Nullable CharSequence text) {
this.testEditor.setText(text);
}
@Override
public int getSelection() {
return this.testEditor.getSelection();
}
@Override
public void setSelection(int selection) {
this.testEditor.setSelection(selection);
}
}
private static class TestEditor implements Editor {
@Nullable
private CharSequence text;
private int selection;
@Nullable
@Override
public CharSequence getText() {
return this.text;
}
@Override
public void setText(@Nullable CharSequence text) {
this.text = text;
}
@Override
public int getSelection() {
return this.selection;
}
@Override
public void setSelection(int selection) {
this.selection = selection;
}
}
}