calculator refactor
This commit is contained in:
parent
bbd5b00af0
commit
4343d04039
@ -1,59 +1,42 @@
|
|||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.ClipboardManager;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.view.*;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import bsh.EvalError;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.android.view.*;
|
||||||
|
import org.solovyev.util.StringUtils;
|
||||||
|
import org.solovyev.util.math.Point2d;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.text.ClipboardManager;
|
|
||||||
import android.text.InputType;
|
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.view.*;
|
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.solovyev.android.view.*;
|
|
||||||
import org.solovyev.util.StringUtils;
|
|
||||||
import org.solovyev.util.math.MathEntityType;
|
|
||||||
|
|
||||||
import bsh.EvalError;
|
|
||||||
import bsh.Interpreter;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import org.solovyev.util.math.MathUtils;
|
|
||||||
import org.solovyev.util.math.Point2d;
|
|
||||||
|
|
||||||
public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
||||||
|
|
||||||
private static final int HVGA_WIDTH_PIXELS = 320;
|
private static final int HVGA_WIDTH_PIXELS = 320;
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private EditText editText;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private TextView resultEditText;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private Interpreter interpreter;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private HistoryHelper<CalculatorHistoryState> historyHelper;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private BroadcastReceiver preferencesChangesReceiver;
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private List<SimpleOnDragListener> onDragListeners = new ArrayList<SimpleOnDragListener>();
|
private List<SimpleOnDragListener> onDragListeners = new ArrayList<SimpleOnDragListener>();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private CalculatorView view;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private CalculatorModel calculator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the activity is first created.
|
* Called when the activity is first created.
|
||||||
*/
|
*/
|
||||||
@ -62,25 +45,14 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.main);
|
setContentView(R.layout.main);
|
||||||
|
|
||||||
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
try {
|
||||||
|
this.calculator = new CalculatorModel();
|
||||||
this.editText = (EditText) findViewById(R.id.editText);
|
} catch (EvalError evalError) {
|
||||||
this.editText.setInputType(InputType.TYPE_NULL);
|
// todo serso: create serso runtime exception
|
||||||
imm.hideSoftInputFromWindow(this.editText.getWindowToken(), 0);
|
throw new RuntimeException("Could not initialize interpreter!");
|
||||||
|
|
||||||
this.resultEditText = (TextView) findViewById(R.id.resultEditText);
|
|
||||||
this.resultEditText.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
final CharSequence text = ((TextView) v).getText();
|
|
||||||
if (!StringUtils.isEmpty(text)) {
|
|
||||||
final ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
|
||||||
clipboard.setText(text);
|
|
||||||
Toast.makeText(CalculatorActivity.this, "Result copied to clipboard!", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
this.view = new CalculatorView(this, this.calculator);
|
||||||
|
|
||||||
final DragButtonCalibrationActivity.Preferences dragPreferences = DragButtonCalibrationActivity.getPreferences(this);
|
final DragButtonCalibrationActivity.Preferences dragPreferences = DragButtonCalibrationActivity.getPreferences(this);
|
||||||
|
|
||||||
@ -88,7 +60,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
|||||||
@Override
|
@Override
|
||||||
public boolean processDragEvent(@NotNull DragDirection dragDirection, @NotNull DragButton dragButton, @NotNull Point2d startPoint2d, @NotNull MotionEvent motionEvent) {
|
public boolean processDragEvent(@NotNull DragDirection dragDirection, @NotNull DragButton dragButton, @NotNull Point2d startPoint2d, @NotNull MotionEvent motionEvent) {
|
||||||
assert dragButton instanceof DirectionDragButton;
|
assert dragButton instanceof DirectionDragButton;
|
||||||
processButtonAction(dragButton, getActionText((DirectionDragButton) dragButton, dragDirection));
|
view.processButtonAction(getActionText((DirectionDragButton) dragButton, dragDirection));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,9 +99,9 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
|||||||
if (dragButton instanceof DirectionDragButton) {
|
if (dragButton instanceof DirectionDragButton) {
|
||||||
String text = ((DirectionDragButton) dragButton).getText(dragDirection);
|
String text = ((DirectionDragButton) dragButton).getText(dragDirection);
|
||||||
if ("↞".equals(text)) {
|
if ("↞".equals(text)) {
|
||||||
CalculatorActivity.this.editText.setSelection(0);
|
CalculatorActivity.this.view.setCursorOnStart();
|
||||||
} else if ("↠".equals(text)) {
|
} else if ("↠".equals(text)) {
|
||||||
CalculatorActivity.this.editText.setSelection(CalculatorActivity.this.editText.getText().length());
|
CalculatorActivity.this.view.setCursorOnEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,18 +112,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
|||||||
((DragButton) findViewById(R.id.leftButton)).setOnDragListener(toPositionOnDragListener);
|
((DragButton) findViewById(R.id.leftButton)).setOnDragListener(toPositionOnDragListener);
|
||||||
onDragListeners.add(toPositionOnDragListener);
|
onDragListeners.add(toPositionOnDragListener);
|
||||||
|
|
||||||
this.interpreter = new Interpreter();
|
|
||||||
|
|
||||||
try {
|
final BroadcastReceiver preferencesChangesReceiver = new BroadcastReceiver() {
|
||||||
interpreter.eval(Preprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
|
|
||||||
} catch (EvalError e) {
|
|
||||||
Log.e(CalculatorActivity.class.getName(), e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.historyHelper = new SimpleHistoryHelper<CalculatorHistoryState>();
|
|
||||||
saveHistoryState();
|
|
||||||
|
|
||||||
this.preferencesChangesReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
|
||||||
@ -164,94 +126,67 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
registerReceiver(this.preferencesChangesReceiver, new IntentFilter(DragButtonCalibrationActivity.INTENT_ACTION));
|
registerReceiver(preferencesChangesReceiver, new IntentFilter(DragButtonCalibrationActivity.INTENT_ACTION));
|
||||||
}
|
|
||||||
|
|
||||||
private void saveHistoryState() {
|
|
||||||
historyHelper.addState(getCurrentHistoryState());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public void elementaryButtonClickHandler(@NotNull View v) {
|
public void elementaryButtonClickHandler(@NotNull View v) {
|
||||||
eval(JsclOperation.elementary, true);
|
throw new UnsupportedOperationException("Not implemented yet!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public void numericButtonClickHandler(@NotNull View v) {
|
public void numericButtonClickHandler(@NotNull View v) {
|
||||||
eval(JsclOperation.numeric, true);
|
this.view.evaluate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public void eraseButtonClickHandler(@NotNull View v) {
|
public void eraseButtonClickHandler(@NotNull View v) {
|
||||||
if (editText.getSelectionStart() > 0) {
|
view.doTextOperation(new CalculatorView.TextOperation() {
|
||||||
editText.getText().delete(editText.getSelectionStart() - 1, editText.getSelectionStart());
|
@Override
|
||||||
saveHistoryState();
|
public void doOperation(@NotNull EditText editor) {
|
||||||
|
if (editor.getSelectionStart() > 0) {
|
||||||
|
editor.getText().delete(editor.getSelectionStart() - 1, editor.getSelectionStart());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public void simplifyButtonClickHandler(@NotNull View v) {
|
public void simplifyButtonClickHandler(@NotNull View v) {
|
||||||
eval(JsclOperation.simplify, true);
|
throw new UnsupportedOperationException("Not implemented yet!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public void moveLeftButtonClickHandler(@NotNull View v) {
|
public void moveLeftButtonClickHandler(@NotNull View v) {
|
||||||
if (editText.getSelectionStart() > 0) {
|
view.moveCursorLeft();
|
||||||
editText.setSelection(editText.getSelectionStart() - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public void moveRightButtonClickHandler(@NotNull View v) {
|
public void moveRightButtonClickHandler(@NotNull View v) {
|
||||||
if (editText.getSelectionStart() < editText.getText().length()) {
|
view.moveCursorRight();
|
||||||
editText.setSelection(editText.getSelectionStart() + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public void pasteButtonClickHandler(@NotNull View v) {
|
public void pasteButtonClickHandler(@NotNull View v) {
|
||||||
|
view.doTextOperation(new CalculatorView.TextOperation() {
|
||||||
|
@Override
|
||||||
|
public void doOperation(@NotNull EditText editor) {
|
||||||
final ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
final ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||||
if (clipboard.hasText()) {
|
if (clipboard.hasText()) {
|
||||||
editText.getText().insert(editText.getSelectionStart(), clipboard.getText());
|
editor.getText().insert(editor.getSelectionStart(), clipboard.getText());
|
||||||
eval(JsclOperation.numeric, false);
|
|
||||||
saveHistoryState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public void clearButtonClickHandler(@NotNull View v) {
|
public void clearButtonClickHandler(@NotNull View v) {
|
||||||
if (!StringUtils.isEmpty(editText.getText()) || !StringUtils.isEmpty(resultEditText.getText())) {
|
view.clear();
|
||||||
editText.getText().clear();
|
|
||||||
resultEditText.setText("");
|
|
||||||
saveHistoryState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void eval(@NotNull JsclOperation operation, boolean showError) {
|
|
||||||
try {
|
|
||||||
final String preprocessedString = Preprocessor.process(String.valueOf(editText.getText()));
|
|
||||||
|
|
||||||
String result = String.valueOf(interpreter.eval(Preprocessor.wrap(operation, preprocessedString))).trim();
|
|
||||||
|
|
||||||
try {
|
|
||||||
final Double dResult = Double.valueOf(result);
|
|
||||||
result = String.valueOf(MathUtils.round(dResult, 5));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
resultEditText.setText(result);
|
|
||||||
|
|
||||||
// result editor might be changed (but main editor - no) => make undo and add new state with saved result
|
|
||||||
CalculatorHistoryState currentHistoryState = getCurrentHistoryState();
|
|
||||||
if (this.historyHelper.isUndoAvailable()) {
|
|
||||||
this.historyHelper.undo(currentHistoryState);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.historyHelper.addState(currentHistoryState);
|
|
||||||
|
|
||||||
} catch (EvalError e) {
|
|
||||||
if (showError) {
|
|
||||||
Toast.makeText(CalculatorActivity.this, R.string.syntax_error, Toast.LENGTH_SHORT).show();
|
|
||||||
Log.e(CalculatorActivity.class.getName(), e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public void digitButtonClickHandler(@NotNull View v) {
|
public void digitButtonClickHandler(@NotNull View v) {
|
||||||
processButtonAction(v, ((DirectionDragButton) v).getTextMiddle());
|
view.processButtonAction(((DirectionDragButton) v).getTextMiddle());
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class HistoryDragProcessor implements SimpleOnDragListener.DragProcessor {
|
private final class HistoryDragProcessor implements SimpleOnDragListener.DragProcessor {
|
||||||
@ -269,7 +204,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
|||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
final HistoryAction historyAction = HistoryAction.valueOf(actionText);
|
final HistoryAction historyAction = HistoryAction.valueOf(actionText);
|
||||||
doHistoryAction(historyAction);
|
view.doHistoryAction(historyAction);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
Log.e(String.valueOf(dragButton.getId()), "Unsupported history action: " + actionText);
|
Log.e(String.valueOf(dragButton.getId()), "Unsupported history action: " + actionText);
|
||||||
}
|
}
|
||||||
@ -279,15 +214,6 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doHistoryAction(@NotNull HistoryAction historyAction) {
|
|
||||||
if (historyHelper.isActionAvailable(historyAction)) {
|
|
||||||
final CalculatorHistoryState newState = historyHelper.doAction(historyAction, getCurrentHistoryState());
|
|
||||||
if (newState != null) {
|
|
||||||
setCurrentHistoryState(newState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String getActionText(@NotNull DirectionDragButton dragButton, @NotNull DragDirection direction) {
|
private static String getActionText(@NotNull DirectionDragButton dragButton, @NotNull DragDirection direction) {
|
||||||
final String result;
|
final String result;
|
||||||
@ -309,67 +235,10 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
|
|
||||||
setValuesFromHistory(this.editText, editorHistoryState.getEditorState());
|
|
||||||
setValuesFromHistory(this.resultEditText, editorHistoryState.getResultEditorState());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setValuesFromHistory(@NotNull TextView editText, EditorHistoryState editorHistoryState) {
|
|
||||||
editText.setText(editorHistoryState.getText());
|
|
||||||
if (editText instanceof EditText) {
|
|
||||||
((EditText) editText).setSelection(editorHistoryState.getCursorPosition());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public CalculatorHistoryState getCurrentHistoryState() {
|
|
||||||
return new CalculatorHistoryState(getEditorHistoryState(this.editText), getEditorHistoryState(this.resultEditText));
|
|
||||||
}
|
|
||||||
|
|
||||||
private EditorHistoryState getEditorHistoryState(@NotNull TextView textView) {
|
|
||||||
final EditorHistoryState result = new EditorHistoryState();
|
|
||||||
|
|
||||||
result.setText(String.valueOf(textView.getText()));
|
|
||||||
result.setCursorPosition(textView.getSelectionStart());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processButtonAction(@NotNull View v, @Nullable String text) {
|
|
||||||
//Toast.makeText(CalculatorActivity.this, text, Toast.LENGTH_SHORT).show();
|
|
||||||
|
|
||||||
if (!StringUtils.isEmpty(text)) {
|
|
||||||
final MathEntityType type = MathEntityType.getType(text);
|
|
||||||
|
|
||||||
int cursorPositionOffset = 0;
|
|
||||||
|
|
||||||
if (type != null) {
|
|
||||||
switch (type) {
|
|
||||||
case function:
|
|
||||||
text += "()";
|
|
||||||
cursorPositionOffset = -1;
|
|
||||||
break;
|
|
||||||
case group_symbols:
|
|
||||||
cursorPositionOffset = -1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
this.editText.getText().insert(this.editText.getSelectionStart(), text);
|
|
||||||
this.editText.setSelection(this.editText.getSelectionStart() + cursorPositionOffset, this.editText.getSelectionEnd() + cursorPositionOffset);
|
|
||||||
saveHistoryState();
|
|
||||||
eval(JsclOperation.numeric, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
doHistoryAction(HistoryAction.undo);
|
view.doHistoryAction(HistoryAction.undo);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return super.onKeyDown(keyCode, event);
|
return super.onKeyDown(keyCode, event);
|
||||||
@ -392,9 +261,11 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster {
|
|||||||
case R.id.menu_item_settings:
|
case R.id.menu_item_settings:
|
||||||
showSettings();
|
showSettings();
|
||||||
result = true;
|
result = true;
|
||||||
|
break;
|
||||||
case R.id.menu_item_help:
|
case R.id.menu_item_help:
|
||||||
showHelp();
|
showHelp();
|
||||||
result = true;
|
result = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
result = super.onOptionsItemSelected(item);
|
result = super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,11 @@ public class CalculatorHistoryState {
|
|||||||
private EditorHistoryState editorState;
|
private EditorHistoryState editorState;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private EditorHistoryState resultEditorState;
|
private EditorHistoryState displayState;
|
||||||
|
|
||||||
public CalculatorHistoryState(@NotNull EditorHistoryState editorState, @NotNull EditorHistoryState resultEditorState) {
|
public CalculatorHistoryState(@NotNull EditorHistoryState editorState, @NotNull EditorHistoryState displayState) {
|
||||||
this.editorState = editorState;
|
this.editorState = editorState;
|
||||||
this.resultEditorState = resultEditorState;
|
this.displayState = displayState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@ -30,11 +30,11 @@ public class CalculatorHistoryState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public EditorHistoryState getResultEditorState() {
|
public EditorHistoryState getDisplayState() {
|
||||||
return resultEditorState;
|
return displayState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResultEditorState(@NotNull EditorHistoryState resultEditorState) {
|
public void setDisplayState(@NotNull EditorHistoryState displayState) {
|
||||||
this.resultEditorState = resultEditorState;
|
this.displayState = displayState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import bsh.EvalError;
|
||||||
|
import bsh.Interpreter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.solovyev.util.math.MathUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 9/12/11
|
||||||
|
* Time: 11:38 PM
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CalculatorModel {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Interpreter interpreter;
|
||||||
|
|
||||||
|
private int NUMBER_OF_FRACTION_DIGITS = 5;
|
||||||
|
|
||||||
|
public CalculatorModel() throws EvalError {
|
||||||
|
interpreter = new Interpreter();
|
||||||
|
|
||||||
|
interpreter.eval(Preprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String evaluate(@NotNull JsclOperation operation, @NotNull String expression ) throws EvalError {
|
||||||
|
|
||||||
|
final String preprocessedString = Preprocessor.process(String.valueOf(expression));
|
||||||
|
|
||||||
|
String result = String.valueOf(interpreter.eval(Preprocessor.wrap(operation, preprocessedString))).trim();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Double dResult = Double.valueOf(result);
|
||||||
|
result = String.valueOf(MathUtils.round(dResult, NUMBER_OF_FRACTION_DIGITS));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// do nothing => it's normal if sometimes we don't have doubles as result
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,206 @@
|
|||||||
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.ClipboardManager;
|
||||||
|
import android.text.InputType;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import bsh.EvalError;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.util.StringUtils;
|
||||||
|
import org.solovyev.util.math.MathEntityType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 9/12/11
|
||||||
|
* Time: 11:15 PM
|
||||||
|
*/
|
||||||
|
public class CalculatorView implements CursorControl{
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final EditText editor;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final TextView display;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final Activity activity;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final CalculatorModel calculator;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private HistoryHelper<CalculatorHistoryState> history;
|
||||||
|
|
||||||
|
public CalculatorView(@NotNull final Activity activity, @NotNull CalculatorModel calculator) {
|
||||||
|
this.activity = activity;
|
||||||
|
this.calculator = calculator;
|
||||||
|
|
||||||
|
final InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
|
||||||
|
this.editor = (EditText) activity.findViewById(R.id.editText);
|
||||||
|
this.editor.setInputType(InputType.TYPE_NULL);
|
||||||
|
imm.hideSoftInputFromWindow(this.editor.getWindowToken(), 0);
|
||||||
|
|
||||||
|
this.display = (TextView) activity.findViewById(R.id.resultEditText);
|
||||||
|
this.display.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
final CharSequence text = ((TextView) v).getText();
|
||||||
|
if (!StringUtils.isEmpty(text)) {
|
||||||
|
final ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Activity.CLIPBOARD_SERVICE);
|
||||||
|
clipboard.setText(text);
|
||||||
|
Toast.makeText(activity, "Result copied to clipboard!", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.history = new SimpleHistoryHelper<CalculatorHistoryState>();
|
||||||
|
saveHistoryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveHistoryState() {
|
||||||
|
history.addState(getCurrentHistoryState());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setCursorOnStart() {
|
||||||
|
editor.setSelection(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCursorOnEnd() {
|
||||||
|
editor.setSelection(editor.getText().length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveCursorLeft() {
|
||||||
|
if (editor.getSelectionStart() > 0) {
|
||||||
|
editor.setSelection(editor.getSelectionStart() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveCursorRight() {
|
||||||
|
if (editor.getSelectionStart() < editor.getText().length()) {
|
||||||
|
editor.setSelection(editor.getSelectionStart() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doTextOperation(@NotNull TextOperation operation) {
|
||||||
|
final String editorStateBefore = this.editor.getText().toString();
|
||||||
|
|
||||||
|
operation.doOperation(this.editor);
|
||||||
|
|
||||||
|
final String editorStateAfter = this.editor.getText().toString();
|
||||||
|
if (!editorStateBefore.equals(editorStateAfter)) {
|
||||||
|
try {
|
||||||
|
evaluate(editorStateAfter);
|
||||||
|
} catch (EvalError evalError) {
|
||||||
|
// actually nothing shall be logged while text operations are done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evaluate(@Nullable String expression) throws EvalError {
|
||||||
|
if (!StringUtils.isEmpty(expression)) {
|
||||||
|
display.setText(calculator.evaluate(JsclOperation.numeric, expression));
|
||||||
|
saveHistoryState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
if (!StringUtils.isEmpty(editor.getText()) || !StringUtils.isEmpty(editor.getText())) {
|
||||||
|
editor.getText().clear();
|
||||||
|
display.setText("");
|
||||||
|
saveHistoryState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evaluate() {
|
||||||
|
try {
|
||||||
|
evaluate(editor.getText().toString());
|
||||||
|
} catch (EvalError evalError) {
|
||||||
|
Toast.makeText(this.activity, R.string.syntax_error, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processButtonAction(@Nullable final String text) {
|
||||||
|
//Toast.makeText(CalculatorActivity.this, text, Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
if (!StringUtils.isEmpty(text)) {
|
||||||
|
doTextOperation(new CalculatorView.TextOperation() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doOperation(@NotNull EditText editor) {
|
||||||
|
|
||||||
|
final MathEntityType type = MathEntityType.getType(text);
|
||||||
|
|
||||||
|
int cursorPositionOffset = 0;
|
||||||
|
final StringBuilder textToBeInserted = new StringBuilder(text);
|
||||||
|
if (type != null) {
|
||||||
|
switch (type) {
|
||||||
|
case function:
|
||||||
|
textToBeInserted.append("()");
|
||||||
|
cursorPositionOffset = -1;
|
||||||
|
break;
|
||||||
|
case group_symbols:
|
||||||
|
cursorPositionOffset = -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.getText().insert(editor.getSelectionStart(), textToBeInserted.toString());
|
||||||
|
editor.setSelection(editor.getSelectionStart() + cursorPositionOffset, editor.getSelectionEnd() + cursorPositionOffset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface TextOperation {
|
||||||
|
|
||||||
|
void doOperation(@NotNull EditText editor);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doHistoryAction(@NotNull HistoryAction historyAction) {
|
||||||
|
if (history.isActionAvailable(historyAction)) {
|
||||||
|
final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState());
|
||||||
|
if (newState != null) {
|
||||||
|
setCurrentHistoryState(newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
|
||||||
|
setValuesFromHistory(this.editor, editorHistoryState.getEditorState());
|
||||||
|
setValuesFromHistory(this.display, editorHistoryState.getDisplayState());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setValuesFromHistory(@NotNull TextView editText, EditorHistoryState editorHistoryState) {
|
||||||
|
editText.setText(editorHistoryState.getText());
|
||||||
|
if (editText instanceof EditText) {
|
||||||
|
((EditText) editText).setSelection(editorHistoryState.getCursorPosition());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public CalculatorHistoryState getCurrentHistoryState() {
|
||||||
|
return new CalculatorHistoryState(getEditorHistoryState(this.editor), getEditorHistoryState(this.display));
|
||||||
|
}
|
||||||
|
|
||||||
|
private EditorHistoryState getEditorHistoryState(@NotNull TextView textView) {
|
||||||
|
final EditorHistoryState result = new EditorHistoryState();
|
||||||
|
|
||||||
|
result.setText(String.valueOf(textView.getText()));
|
||||||
|
result.setCursorPosition(textView.getSelectionStart());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 9/13/11
|
||||||
|
* Time: 12:08 AM
|
||||||
|
*/
|
||||||
|
public interface CursorControl {
|
||||||
|
|
||||||
|
public void setCursorOnStart();
|
||||||
|
|
||||||
|
public void setCursorOnEnd();
|
||||||
|
|
||||||
|
public void moveCursorLeft();
|
||||||
|
|
||||||
|
public void moveCursorRight();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user