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
17package com.android.calculator2;
18
19import android.text.SpannableStringBuilder;
20import android.text.Editable;
21
22class CalculatorEditable extends SpannableStringBuilder {
23    private static final char[] ORIGINALS    = {'-',      '*',      '/'};
24    private static final char[] REPLACEMENTS = {'\u2212', '\u00d7', '\u00f7'};
25    private boolean isInsideReplace = false;
26    private Logic mLogic;
27
28    private CalculatorEditable(CharSequence source, Logic logic) {
29        super(source);
30        mLogic = logic;
31    }
32
33    @Override
34    public SpannableStringBuilder
35    replace(int start, int end, CharSequence tb, int tbstart, int tbend) {
36        if (isInsideReplace) {
37            return super.replace(start, end, tb, tbstart, tbend);
38        } else {
39            isInsideReplace = true;
40            try {
41                String delta = tb.subSequence(tbstart, tbend).toString();
42                return internalReplace(start, end, delta);
43            } finally {
44                isInsideReplace = false;
45            }
46        }
47    }
48
49    private SpannableStringBuilder internalReplace(int start, int end, String delta) {
50        if (!mLogic.acceptInsert(delta)) {
51            mLogic.cleared();
52            start = 0;
53            end = length();
54        }
55
56        for (int i = ORIGINALS.length - 1; i >= 0; --i) {
57            delta = delta.replace(ORIGINALS[i], REPLACEMENTS[i]);
58        }
59
60        int length = delta.length();
61        if (length == 1) {
62            char text = delta.charAt(0);
63
64            //don't allow two dots in the same number
65            if (text == '.') {
66                int p = start - 1;
67                while (p >= 0 && Character.isDigit(charAt(p))) {
68                    --p;
69                }
70                if (p >= 0 && charAt(p) == '.') {
71                    return super.replace(start, end, "");
72                }
73            }
74
75            char prevChar = start > 0 ? charAt(start-1) : '\0';
76
77            //don't allow 2 successive minuses
78            if (text == Logic.MINUS && prevChar == Logic.MINUS) {
79                return super.replace(start, end, "");
80            }
81
82            //don't allow multiple successive operators
83            if (Logic.isOperator(text)) {
84                while (Logic.isOperator(prevChar) &&
85                       (text != Logic.MINUS || prevChar == '+')) {
86                    --start;
87                    prevChar = start > 0 ? charAt(start-1) : '\0';
88                }
89            }
90
91            //don't allow leading operator + * /
92            if (start == 0 && Logic.isOperator(text) && text != Logic.MINUS) {
93                return super.replace(start, end, "");
94            }
95        }
96        return super.replace(start, end, delta);
97    }
98
99    public static class Factory extends Editable.Factory {
100        private Logic mLogic;
101
102        public Factory(Logic logic) {
103            mLogic = logic;
104        }
105
106        public Editable newEditable(CharSequence source) {
107            return new CalculatorEditable(source, mLogic);
108        }
109    }
110}
111