1 /* 2 * Copyright (C) 2014 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.content.Context; 20 import android.text.SpannableStringBuilder; 21 import android.text.TextUtils; 22 23 public class CalculatorExpressionBuilder extends SpannableStringBuilder { 24 25 private final CalculatorExpressionTokenizer mTokenizer; 26 private boolean mIsEdited; 27 28 public CalculatorExpressionBuilder( 29 CharSequence text, CalculatorExpressionTokenizer tokenizer, boolean isEdited) { 30 super(text); 31 32 mTokenizer = tokenizer; 33 mIsEdited = isEdited; 34 } 35 36 @Override 37 public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart, 38 int tbend) { 39 if (start != length() || end != length()) { 40 mIsEdited = true; 41 return super.replace(start, end, tb, tbstart, tbend); 42 } 43 44 String appendExpr = 45 mTokenizer.getNormalizedExpression(tb.subSequence(tbstart, tbend).toString()); 46 if (appendExpr.length() == 1) { 47 final String expr = mTokenizer.getNormalizedExpression(toString()); 48 switch (appendExpr.charAt(0)) { 49 case '.': 50 // don't allow two decimals in the same number 51 final int index = expr.lastIndexOf('.'); 52 if (index != -1 && TextUtils.isDigitsOnly(expr.substring(index + 1, start))) { 53 appendExpr = ""; 54 } 55 break; 56 case '+': 57 case '*': 58 case '/': 59 // don't allow leading operator 60 if (start == 0) { 61 appendExpr = ""; 62 break; 63 } 64 65 // don't allow multiple successive operators 66 while (start > 0 && "+-*/".indexOf(expr.charAt(start - 1)) != -1) { 67 --start; 68 } 69 // fall through 70 case '-': 71 // don't allow -- or +- 72 if (start > 0 && "+-".indexOf(expr.charAt(start - 1)) != -1) { 73 --start; 74 } 75 76 // mark as edited since operators can always be appended 77 mIsEdited = true; 78 break; 79 default: 80 break; 81 } 82 } 83 84 // since this is the first edit replace the entire string 85 if (!mIsEdited && appendExpr.length() > 0) { 86 start = 0; 87 mIsEdited = true; 88 } 89 90 appendExpr = mTokenizer.getLocalizedExpression(appendExpr); 91 return super.replace(start, end, appendExpr, 0, appendExpr.length()); 92 } 93 } 94