| /* |
| * 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; |
| } |
| } |