blob: bd066dea67a969da6178bcac3f721604081d614f [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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.
*/
package com.android.calculator2;
import android.view.View;
import android.view.KeyEvent;
import android.widget.Button;
import android.widget.EditText;
import android.content.Context;
import android.content.res.Configuration;
import org.javia.arity.Symbols;
import org.javia.arity.SyntaxException;
import org.javia.arity.Util;
class Logic {
private CalculatorDisplay mDisplay;
private Symbols mSymbols = new Symbols();
private History mHistory;
private String mResult = "";
private Button mEqualButton;
private final String mEnterString;
private boolean mIsError = false;
private int mLineLength = 0;
private static final String INFINITY_UNICODE = "\u221e";
// the two strings below are the result of Double.toString() for Infinity & NaN
// they are not output to the user and don't require internationalization
private static final String INFINITY = "Infinity";
private static final String NAN = "NaN";
static final char MINUS = '\u2212';
private final String mErrorString;
Logic(Context context, History history, CalculatorDisplay display, Button equalButton) {
mErrorString = context.getResources().getString(R.string.error);
try {
// in calculator we use log() for base-10,
// unlike in arity-lib where log() is natural logarithm
mSymbols.define(mSymbols.compileWithName("log(x)=log10(x)"));
} catch (SyntaxException e) {
throw new Error("" + e); //never
}
mHistory = history;
mDisplay = display;
mDisplay.setLogic(this);
mEqualButton = equalButton;
mEnterString = context.getText(R.string.enter).toString();
clearWithHistory(false);
}
void setLineLength(int nDigits) {
mLineLength = nDigits;
}
boolean eatHorizontalMove(boolean toLeft) {
EditText editText = mDisplay.getEditText();
int cursorPos = editText.getSelectionStart();
return toLeft ? cursorPos == 0 : cursorPos >= editText.length();
}
private String getText() {
return mDisplay.getText().toString();
}
void insert(String delta) {
mDisplay.insert(delta);
}
private void setText(CharSequence text) {
mDisplay.setText(text, CalculatorDisplay.Scroll.UP);
}
private void clearWithHistory(boolean scroll) {
mDisplay.setText(mHistory.getText(),
scroll ? CalculatorDisplay.Scroll.UP : CalculatorDisplay.Scroll.NONE);
mResult = "";
mIsError = false;
}
private void clear(boolean scroll) {
mDisplay.setText("", scroll ? CalculatorDisplay.Scroll.UP : CalculatorDisplay.Scroll.NONE);
cleared();
}
void cleared() {
mResult = "";
mIsError = false;
updateHistory();
}
boolean acceptInsert(String delta) {
String text = getText();
return !mIsError &&
(!mResult.equals(text) ||
isOperator(delta) ||
mDisplay.getSelectionStart() != text.length());
}
void onDelete() {
if (getText().equals(mResult) || mIsError) {
clear(false);
} else {
mDisplay.dispatchKeyEvent(new KeyEvent(0, KeyEvent.KEYCODE_DEL));
mResult = "";
}
}
void onClear() {
clear(false);
}
void onEnter() {
String text = getText();
if (text.equals(mResult)) {
clearWithHistory(false); //clear after an Enter on result
} else {
mHistory.enter(text);
try {
mResult = evaluate(text);
} catch (SyntaxException e) {
mIsError = true;
mResult = mErrorString;
}
if (text.equals(mResult)) {
//no need to show result, it is exactly what the user entered
clearWithHistory(true);
} else {
setText(mResult);
//mEqualButton.setText(mEnterString);
}
}
}
void onUp() {
String text = getText();
if (!text.equals(mResult)) {
mHistory.update(text);
}
if (mHistory.moveToPrevious()) {
mDisplay.setText(mHistory.getText(), CalculatorDisplay.Scroll.DOWN);
}
}
void onDown() {
String text = getText();
if (!text.equals(mResult)) {
mHistory.update(text);
}
if (mHistory.moveToNext()) {
mDisplay.setText(mHistory.getText(), CalculatorDisplay.Scroll.UP);
}
}
void updateHistory() {
mHistory.update(getText());
}
private static final int ROUND_DIGITS = 1;
String evaluate(String input) throws SyntaxException {
if (input.trim().equals("")) {
return "";
}
// drop final infix operators (they can only result in error)
int size = input.length();
while (size > 0 && isOperator(input.charAt(size - 1))) {
input = input.substring(0, size - 1);
--size;
}
String result = Util.doubleToString(mSymbols.eval(input), mLineLength, ROUND_DIGITS);
if (result.equals(NAN)) { // treat NaN as Error
mIsError = true;
return mErrorString;
}
return result.replace('-', MINUS).replace(INFINITY, INFINITY_UNICODE);
}
static boolean isOperator(String text) {
return text.length() == 1 && isOperator(text.charAt(0));
}
static boolean isOperator(char c) {
//plus minus times div
return "+\u2212\u00d7\u00f7/*".indexOf(c) != -1;
}
}