Home | History | Annotate | Download | only in calculator2
      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 
     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 
     56     void setLineLength(int nDigits) {
     57         mLineLength = nDigits;
     58     }
     59 
     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 
     66     private String getText() {
     67         return mDisplay.getText().toString();
     68     }
     69 
     70     void insert(String delta) {
     71         mDisplay.insert(delta);
     72     }
     73 
     74     private void setText(CharSequence text) {
     75         mDisplay.setText(text, CalculatorDisplay.Scroll.UP);
     76     }
     77 
     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 
     85     private void clear(boolean scroll) {
     86         mDisplay.setText("", scroll ? CalculatorDisplay.Scroll.UP : CalculatorDisplay.Scroll.NONE);
     87         cleared();
     88     }
     89 
     90     void cleared() {
     91         mResult = "";
     92         mIsError = false;
     93         updateHistory();
     94     }
     95 
     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 
    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 
    113     void onClear() {
    114         clear(false);
    115     }
    116 
    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 
    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 
    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 
    159     void updateHistory() {
    160         mHistory.update(getText());
    161     }
    162 
    163     private static final int ROUND_DIGITS = 1;
    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 
    184     static boolean isOperator(String text) {
    185         return text.length() == 1 && isOperator(text.charAt(0));
    186     }
    187 
    188     static boolean isOperator(char c) {
    189         //plus minus times div
    190         return "+\u2212\u00d7\u00f7/*".indexOf(c) != -1;
    191     }
    192 }
    193