• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.calculator2;
18 
19 import android.view.View;
20 import android.view.KeyEvent;
21 import android.widget.Button;
22 import android.widget.EditText;
23 import android.content.Context;
24 import android.content.res.Configuration;
25 
26 import org.javia.arity.Symbols;
27 import org.javia.arity.SyntaxException;
28 import org.javia.arity.Util;
29 
30 class Logic {
31     private CalculatorDisplay mDisplay;
32     private Symbols mSymbols = new Symbols();
33     private History mHistory;
34     private String  mResult = "";
35     private Button mEqualButton;
36     private final String mEnterString;
37     private boolean mIsError = false;
38     private int mLineLength = 0;
39 
40     private static final String INFINITY_UNICODE = "\u221e";
41 
42     // the two strings below are the result of Double.toString() for Infinity & NaN
43     // they are not output to the user and don't require internationalization
44     private static final String INFINITY = "Infinity";
45     private static final String NAN      = "NaN";
46 
47     static final char MINUS = '\u2212';
48 
49     private final String mErrorString;
50 
Logic(Context context, History history, CalculatorDisplay display, Button equalButton)51     Logic(Context context, History history, CalculatorDisplay display, Button equalButton) {
52         mErrorString = context.getResources().getString(R.string.error);
53         try {
54             // in calculator we use log() for base-10,
55             // unlike in arity-lib where log() is natural logarithm
56             mSymbols.define(mSymbols.compileWithName("log(x)=log10(x)"));
57         } catch (SyntaxException e) {
58             throw new Error("" + e); //never
59         }
60         mHistory = history;
61         mDisplay = display;
62         mDisplay.setLogic(this);
63         mEqualButton = equalButton;
64         mEnterString = context.getText(R.string.enter).toString();
65 
66         clearWithHistory(false);
67     }
68 
setLineLength(int nDigits)69     void setLineLength(int nDigits) {
70         mLineLength = nDigits;
71     }
72 
eatHorizontalMove(boolean toLeft)73     boolean eatHorizontalMove(boolean toLeft) {
74         EditText editText = mDisplay.getEditText();
75         int cursorPos = editText.getSelectionStart();
76         return toLeft ? cursorPos == 0 : cursorPos >= editText.length();
77     }
78 
getText()79     private String getText() {
80         return mDisplay.getText().toString();
81     }
82 
insert(String delta)83     void insert(String delta) {
84         mDisplay.insert(delta);
85     }
86 
setText(CharSequence text)87     private void setText(CharSequence text) {
88         mDisplay.setText(text, CalculatorDisplay.Scroll.UP);
89     }
90 
clearWithHistory(boolean scroll)91     private void clearWithHistory(boolean scroll) {
92         mDisplay.setText(mHistory.getText(),
93                          scroll ? CalculatorDisplay.Scroll.UP : CalculatorDisplay.Scroll.NONE);
94         mResult = "";
95         mIsError = false;
96     }
97 
clear(boolean scroll)98     private void clear(boolean scroll) {
99         mDisplay.setText("", scroll ? CalculatorDisplay.Scroll.UP : CalculatorDisplay.Scroll.NONE);
100         cleared();
101     }
102 
cleared()103     void cleared() {
104         mResult = "";
105         mIsError = false;
106         updateHistory();
107     }
108 
acceptInsert(String delta)109     boolean acceptInsert(String delta) {
110         String text = getText();
111         return !mIsError &&
112             (!mResult.equals(text) ||
113              isOperator(delta) ||
114              mDisplay.getSelectionStart() != text.length());
115     }
116 
onDelete()117     void onDelete() {
118         if (getText().equals(mResult) || mIsError) {
119             clear(false);
120         } else {
121             mDisplay.dispatchKeyEvent(new KeyEvent(0, KeyEvent.KEYCODE_DEL));
122             mResult = "";
123         }
124     }
125 
onClear()126     void onClear() {
127         clear(false);
128     }
129 
onEnter()130     void onEnter() {
131         String text = getText();
132         if (text.equals(mResult)) {
133             clearWithHistory(false); //clear after an Enter on result
134         } else {
135             mHistory.enter(text);
136             try {
137                 mResult = evaluate(text);
138             } catch (SyntaxException e) {
139                 mIsError = true;
140                 mResult = mErrorString;
141             }
142             if (text.equals(mResult)) {
143                 //no need to show result, it is exactly what the user entered
144                 clearWithHistory(true);
145             } else {
146                 setText(mResult);
147                 //mEqualButton.setText(mEnterString);
148             }
149         }
150     }
151 
onUp()152     void onUp() {
153         String text = getText();
154         if (!text.equals(mResult)) {
155             mHistory.update(text);
156         }
157         if (mHistory.moveToPrevious()) {
158             mDisplay.setText(mHistory.getText(), CalculatorDisplay.Scroll.DOWN);
159         }
160     }
161 
onDown()162     void onDown() {
163         String text = getText();
164         if (!text.equals(mResult)) {
165             mHistory.update(text);
166         }
167         if (mHistory.moveToNext()) {
168             mDisplay.setText(mHistory.getText(), CalculatorDisplay.Scroll.UP);
169         }
170     }
171 
updateHistory()172     void updateHistory() {
173         mHistory.update(getText());
174     }
175 
176     private static final int ROUND_DIGITS = 1;
evaluate(String input)177     String evaluate(String input) throws SyntaxException {
178         if (input.trim().equals("")) {
179             return "";
180         }
181 
182         // drop final infix operators (they can only result in error)
183         int size = input.length();
184         while (size > 0 && isOperator(input.charAt(size - 1))) {
185             input = input.substring(0, size - 1);
186             --size;
187         }
188 
189         String result = Util.doubleToString(mSymbols.eval(input), mLineLength, ROUND_DIGITS);
190         if (result.equals(NAN)) { // treat NaN as Error
191             mIsError = true;
192             return mErrorString;
193         }
194         return result.replace('-', MINUS).replace(INFINITY, INFINITY_UNICODE);
195     }
196 
isOperator(String text)197     static boolean isOperator(String text) {
198         return text.length() == 1 && isOperator(text.charAt(0));
199     }
200 
isOperator(char c)201     static boolean isOperator(char c) {
202         //plus minus times div
203         return "+\u2212\u00d7\u00f7/*".indexOf(c) != -1;
204     }
205 }
206