• 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.KeyEvent;
20 import android.widget.Button;
21 import android.widget.EditText;
22 import android.content.Context;
23 
24 import org.javia.arity.Symbols;
25 import org.javia.arity.SyntaxException;
26 import org.javia.arity.Util;
27 
28 class Logic {
29     private CalculatorDisplay mDisplay;
30     private Symbols mSymbols = new Symbols();
31     private History mHistory;
32     private String  mResult = "";
33     private boolean mIsError = false;
34     private int mLineLength = 0;
35 
36     private static final String INFINITY_UNICODE = "\u221e";
37 
38     // the two strings below are the result of Double.toString() for Infinity & NaN
39     // they are not output to the user and don't require internationalization
40     private static final String INFINITY = "Infinity";
41     private static final String NAN      = "NaN";
42 
43     static final char MINUS = '\u2212';
44 
45     private final String mErrorString;
46 
Logic(Context context, History history, CalculatorDisplay display, Button equalButton)47     Logic(Context context, History history, CalculatorDisplay display, Button equalButton) {
48         mErrorString = context.getResources().getString(R.string.error);
49         mHistory = history;
50         mDisplay = display;
51         mDisplay.setLogic(this);
52 
53         clearWithHistory(false);
54     }
55 
setLineLength(int nDigits)56     void setLineLength(int nDigits) {
57         mLineLength = nDigits;
58     }
59 
eatHorizontalMove(boolean toLeft)60     boolean eatHorizontalMove(boolean toLeft) {
61         EditText editText = mDisplay.getEditText();
62         int cursorPos = editText.getSelectionStart();
63         return toLeft ? cursorPos == 0 : cursorPos >= editText.length();
64     }
65 
getText()66     private String getText() {
67         return mDisplay.getText().toString();
68     }
69 
insert(String delta)70     void insert(String delta) {
71         mDisplay.insert(delta);
72     }
73 
setText(CharSequence text)74     private void setText(CharSequence text) {
75         mDisplay.setText(text, CalculatorDisplay.Scroll.UP);
76     }
77 
clearWithHistory(boolean scroll)78     private void clearWithHistory(boolean scroll) {
79         mDisplay.setText(mHistory.getText(),
80                          scroll ? CalculatorDisplay.Scroll.UP : CalculatorDisplay.Scroll.NONE);
81         mResult = "";
82         mIsError = false;
83     }
84 
clear(boolean scroll)85     private void clear(boolean scroll) {
86         mDisplay.setText("", scroll ? CalculatorDisplay.Scroll.UP : CalculatorDisplay.Scroll.NONE);
87         cleared();
88     }
89 
cleared()90     void cleared() {
91         mResult = "";
92         mIsError = false;
93         updateHistory();
94     }
95 
acceptInsert(String delta)96     boolean acceptInsert(String delta) {
97         String text = getText();
98         return !mIsError &&
99             (!mResult.equals(text) ||
100              isOperator(delta) ||
101              mDisplay.getSelectionStart() != text.length());
102     }
103 
onDelete()104     void onDelete() {
105         if (getText().equals(mResult) || mIsError) {
106             clear(false);
107         } else {
108             mDisplay.dispatchKeyEvent(new KeyEvent(0, KeyEvent.KEYCODE_DEL));
109             mResult = "";
110         }
111     }
112 
onClear()113     void onClear() {
114         clear(false);
115     }
116 
onEnter()117     void onEnter() {
118         String text = getText();
119         if (text.equals(mResult)) {
120             clearWithHistory(false); //clear after an Enter on result
121         } else {
122             mHistory.enter(text);
123             try {
124                 mResult = evaluate(text);
125             } catch (SyntaxException e) {
126                 mIsError = true;
127                 mResult = mErrorString;
128             }
129             if (text.equals(mResult)) {
130                 //no need to show result, it is exactly what the user entered
131                 clearWithHistory(true);
132             } else {
133                 setText(mResult);
134                 //mEqualButton.setText(mEnterString);
135             }
136         }
137     }
138 
onUp()139     void onUp() {
140         String text = getText();
141         if (!text.equals(mResult)) {
142             mHistory.update(text);
143         }
144         if (mHistory.moveToPrevious()) {
145             mDisplay.setText(mHistory.getText(), CalculatorDisplay.Scroll.DOWN);
146         }
147     }
148 
onDown()149     void onDown() {
150         String text = getText();
151         if (!text.equals(mResult)) {
152             mHistory.update(text);
153         }
154         if (mHistory.moveToNext()) {
155             mDisplay.setText(mHistory.getText(), CalculatorDisplay.Scroll.UP);
156         }
157     }
158 
updateHistory()159     void updateHistory() {
160         mHistory.update(getText());
161     }
162 
163     private static final int ROUND_DIGITS = 1;
evaluate(String input)164     String evaluate(String input) throws SyntaxException {
165         if (input.trim().equals("")) {
166             return "";
167         }
168 
169         // drop final infix operators (they can only result in error)
170         int size = input.length();
171         while (size > 0 && isOperator(input.charAt(size - 1))) {
172             input = input.substring(0, size - 1);
173             --size;
174         }
175 
176         String result = Util.doubleToString(mSymbols.eval(input), mLineLength, ROUND_DIGITS);
177         if (result.equals(NAN)) { // treat NaN as Error
178             mIsError = true;
179             return mErrorString;
180         }
181         return result.replace('-', MINUS).replace(INFINITY, INFINITY_UNICODE);
182     }
183 
isOperator(String text)184     static boolean isOperator(String text) {
185         return text.length() == 1 && isOperator(text.charAt(0));
186     }
187 
isOperator(char c)188     static boolean isOperator(char c) {
189         //plus minus times div
190         return "+\u2212\u00d7\u00f7/*".indexOf(c) != -1;
191     }
192 }
193