/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.numix.calculator; import android.text.Editable; import android.text.SpannableStringBuilder; public class CalculatorEditable extends SpannableStringBuilder { private static final char[] ORIGINALS = { '-', '*', '/' }; private static final char[] REPLACEMENTS = { '\u2212', '\u00d7', '\u00f7' }; private boolean isInsideReplace = false; private Logic mLogic; private CalculatorEditable(CharSequence source, Logic logic) { super(source); mLogic = logic; } @Override public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart, int tbend) { if(isInsideReplace) { return super.replace(start, end, tb, tbstart, tbend); } else { isInsideReplace = true; try { String delta = tb.subSequence(tbstart, tbend).toString(); return internalReplace(start, end, delta); } finally { isInsideReplace = false; } } } private SpannableStringBuilder internalReplace(int start, int end, String delta) { if(!mLogic.acceptInsert(delta)) { mLogic.cleared(); start = 0; end = length(); } for(int i = ORIGINALS.length - 1; i >= 0; --i) { delta = delta.replace(ORIGINALS[i], REPLACEMENTS[i]); } int length = delta.length(); if(length == 1) { char text = delta.charAt(0); // don't allow two dots in the same number if(text == '.') { int p = start - 1; while(p >= 0 && Character.isDigit(charAt(p))) { --p; } if(p >= 0 && charAt(p) == '.') { return super.replace(start, end, ""); } } char prevChar = start > 0 ? charAt(start - 1) : '\0'; // don't allow 2 successive minuses if(text == Logic.MINUS && prevChar == Logic.MINUS) { return super.replace(start, end, ""); } // TODO move to advanced display // don't allow multiple successive operators if(Logic.isOperator(text)) { while(Logic.isOperator(prevChar) && (text != Logic.MINUS || prevChar == '+')) { --start; prevChar = start > 0 ? charAt(start - 1) : '\0'; } } } return super.replace(start, end, delta); } public static class Factory extends Editable.Factory { private Logic mLogic; public Factory(Logic logic) { mLogic = logic; } public Editable newEditable(CharSequence source) { return new CalculatorEditable(source, mLogic); } } }