14b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen/* 24b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * Copyright (C) 2014 The Android Open Source Project 34b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * 44b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * Licensed under the Apache License, Version 2.0 (the "License"); 54b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * you may not use this file except in compliance with the License. 64b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * You may obtain a copy of the License at 74b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * 84b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * http://www.apache.org/licenses/LICENSE-2.0 94b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * 104b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * Unless required by applicable law or agreed to in writing, software 114b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * distributed under the License is distributed on an "AS IS" BASIS, 124b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * See the License for the specific language governing permissions and 144b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen * limitations under the License. 154b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen */ 164b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 174b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenpackage com.android.calculator2; 184b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 194b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.content.Context; 204b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.text.SpannableStringBuilder; 214b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenimport android.text.TextUtils; 224b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 234b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassenpublic class CalculatorExpressionBuilder extends SpannableStringBuilder { 244b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 254b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private final CalculatorExpressionTokenizer mTokenizer; 264b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen private boolean mIsEdited; 274b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 282be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen public CalculatorExpressionBuilder( 292be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen CharSequence text, CalculatorExpressionTokenizer tokenizer, boolean isEdited) { 304b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen super(text); 31741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen 322be4fdbfcd5f16bc12066d1ccac181bca3dfaa7aJustin Klaassen mTokenizer = tokenizer; 33741471e3e99760acd44f8536534ac6121af9b03fJustin Klaassen mIsEdited = isEdited; 344b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 354b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 364b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen @Override 374b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart, 384b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen int tbend) { 394b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (start != length() || end != length()) { 404b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mIsEdited = true; 414b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen return super.replace(start, end, tb, tbstart, tbend); 424b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 434b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 444b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen String appendExpr = 454b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mTokenizer.getNormalizedExpression(tb.subSequence(tbstart, tbend).toString()); 464b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (appendExpr.length() == 1) { 474b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final String expr = mTokenizer.getNormalizedExpression(toString()); 484b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen switch (appendExpr.charAt(0)) { 494b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case '.': 504b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // don't allow two decimals in the same number 514b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen final int index = expr.lastIndexOf('.'); 524b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (index != -1 && TextUtils.isDigitsOnly(expr.substring(index + 1, start))) { 534b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen appendExpr = ""; 544b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 554b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 564b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case '+': 574b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case '*': 584b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case '/': 594b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // don't allow leading operator 604b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (start == 0) { 614b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen appendExpr = ""; 624b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 634b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 644b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 654b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // don't allow multiple successive operators 664b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen while (start > 0 && "+-*/".indexOf(expr.charAt(start - 1)) != -1) { 674b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen --start; 684b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 694b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // fall through 704b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen case '-': 714b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // don't allow -- or +- 724b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (start > 0 && "+-".indexOf(expr.charAt(start - 1)) != -1) { 734b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen --start; 744b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 754b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 764b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // mark as edited since operators can always be appended 774b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mIsEdited = true; 784b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 794b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen default: 804b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen break; 814b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 824b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 834b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 844b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen // since this is the first edit replace the entire string 854b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen if (!mIsEdited && appendExpr.length() > 0) { 864b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen start = 0; 874b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen mIsEdited = true; 884b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 894b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen 904b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen appendExpr = mTokenizer.getLocalizedExpression(appendExpr); 914b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen return super.replace(start, end, appendExpr, 0, appendExpr.length()); 924b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen } 934b3af0578b1a44038856bc56244aea8aaeac22d1Justin Klaassen} 94