001: /*
002: * Javu WingS - Lightweight Java Component Set
003: * Copyright (c) 2005-2007 Krzysztof A. Sadlocha
004: * e-mail: ksadlocha@programics.com
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020:
021: package calc;
022:
023: import java.text.DecimalFormat;
024: import java.text.DecimalFormatSymbols;
025: import java.text.NumberFormat;
026: import java.util.Locale;
027: import java.util.Vector;
028:
029: /**
030: * Logic of the calc WingsCalc
031: * it does not interact with any component of WingS
032: * and is out of the scope of this tutorial
033: */
034: public class CalcLogic {
035: public static final int FUNC_EQUAL = 0;
036: public static final int FUNC_PERCENT = 1;
037: public static final int FUNC_PLUS = 2;
038: public static final int FUNC_MINUS = 3;
039: public static final int FUNC_MULTIPLY = 4;
040: public static final int FUNC_DIVIDE = 5;
041: public static final int FUNC_SQRT = 6;
042: public static final int FUNC_RECIPROCAL = 7;
043: public static final int FUNC_LAST_MATH = 7;
044:
045: public static final int FUNC_PERIOD = 10;
046: public static final int FUNC_SIGN = 11;
047: public static final int FUNC_BACKSPACE = 12;
048: public static final int FUNC_C = 13;
049: public static final int FUNC_CE = 14;
050:
051: public static final int FUNC_0 = 20;
052: public static final int FUNC_1 = FUNC_0 + 1;
053: public static final int FUNC_2 = FUNC_0 + 2;
054: public static final int FUNC_3 = FUNC_0 + 3;
055: public static final int FUNC_4 = FUNC_0 + 4;
056: public static final int FUNC_5 = FUNC_0 + 5;
057: public static final int FUNC_6 = FUNC_0 + 6;
058: public static final int FUNC_7 = FUNC_0 + 7;
059: public static final int FUNC_8 = FUNC_0 + 8;
060: public static final int FUNC_9 = FUNC_0 + 9;
061:
062: public static final int FUNC_COUNT = FUNC_9 + 1;
063:
064: public static final int[] precedence = { 0, // FUNC_EQUAL
065: 0, // FUNC_PERCENT
066: 5, // FUNC_ADD
067: 5, // FUNC_SUBTRACT
068: 6, // FUNC_MULTIPLY
069: 6 // FUNC_DIVIDE
070: };
071:
072: static class Operation {
073: double number;
074: int operation;
075: }
076:
077: private Vector stack = new Vector();
078: private Operation lastOperation;
079: private boolean wasPercent;
080: private boolean firstDigit;
081: private boolean wasPeriod;
082: private String displayText;
083:
084: public CalcLogic() {
085: reset();
086: }
087:
088: public void reset() {
089: resetDisplay();
090: stack.setSize(0);
091: lastOperation = null;
092: wasPercent = false;
093: }
094:
095: public void operation(int func) {
096: double value;
097: try {
098: value = Double.valueOf(displayText).doubleValue();
099: } catch (NumberFormatException e) {
100: return;
101: }
102:
103: if (func == FUNC_SQRT || func == FUNC_RECIPROCAL) {
104: if (func == FUNC_SQRT)
105: value = Math.sqrt(value);
106: else
107: value = 1 / value;
108: displayText = formatValue(value);
109: return;
110: }
111:
112: if (func == FUNC_PERCENT) {
113: wasPercent = true;
114: }
115:
116: Operation o = new Operation();
117: o.number = value;
118: o.operation = func;
119:
120: if (stack.size() > 0)
121: lastOperation = (Operation) stack.firstElement();
122:
123: if (o.operation == FUNC_EQUAL && stack.size() == 0
124: && lastOperation != null)
125: stack.addElement(lastOperation);
126:
127: while (stack.size() > 0) {
128: Operation o2 = (Operation) stack.lastElement();
129:
130: if (precedence[o.operation] > precedence[o2.operation]) {
131: break;
132: }
133: stack.setSize(stack.size() - 1);
134:
135: double result;
136: if (o2.operation == FUNC_PLUS) {
137: if (!wasPercent)
138: result = o2.number + o.number;
139: else
140: result = o2.number * (1 + o.number / 100);
141: } else if (o2.operation == FUNC_MINUS) {
142: if (!wasPercent)
143: result = o2.number - o.number;
144: else
145: result = o2.number * (1 - o.number / 100);
146: } else if (o2.operation == FUNC_MULTIPLY) {
147: if (!wasPercent)
148: result = o2.number * o.number;
149: else
150: result = o2.number * o.number / 100;
151: } else //if(o2.operation==FUNC_DIVIDE)
152: {
153: if (!wasPercent)
154: result = o2.number / o.number;
155: else
156: result = o2.number * 100 / o.number;
157: }
158:
159: wasPercent = false;
160: o.number = result;
161: }
162:
163: if (o.operation != FUNC_EQUAL && o.operation != FUNC_PERCENT)
164: stack.addElement(o);
165:
166: displayText = formatValue(o.number);
167: }
168:
169: private String formatValue(double value) {
170: NumberFormat f = NumberFormat.getInstance(Locale.US);
171: String p = (value >= (10000000000.0)) ? "0.000000000E0"
172: : (value >= (1000000000)) ? "0.0"
173: : (value >= (100000000)) ? "0.0#"
174: : (value >= (10000000)) ? "0.0##"
175: : (value >= (1000000)) ? "0.0###"
176: : (value >= (100000)) ? "0.0####"
177: : (value >= (10000)) ? "0.0#####"
178: : (value >= (1000)) ? "0.0######"
179: : (value >= (100)) ? "0.0#######"
180: : (value >= (10)) ? "0.0########"
181: : "0.0#########";
182: f = new DecimalFormat(p, new DecimalFormatSymbols(Locale.US));
183: String r = f.format(value);
184: if (r.endsWith(".0"))
185: r = r.substring(0, r.length() - 1);
186: return r;
187: }
188:
189: private void resetDisplay() {
190: firstDigit = true;
191: wasPeriod = false;
192: displayText = "0.";
193: }
194:
195: public String getDisplayText() {
196: return displayText;
197: }
198:
199: public void buttonAction(int func) {
200: if (isError()) {
201: if (func == FUNC_CE) {
202: String text = displayText.substring(0, displayText
203: .indexOf('E'));
204: reset();
205: displayText = text;
206: } else if (func == FUNC_C) {
207: reset();
208: }
209: } else if (func >= FUNC_0) {
210: int digit = func - FUNC_0;
211: if (firstDigit) {
212: displayText = digit + ".";
213: } else if (wasPeriod) {
214: displayText = displayText + digit;
215: } else {
216: displayText = displayText.substring(0, displayText
217: .length() - 1)
218: + digit + ".";
219: }
220: firstDigit = false;
221: } else if (func == FUNC_PERIOD) {
222: wasPeriod = true;
223: if (firstDigit) {
224: displayText = "0.";
225: firstDigit = false;
226: }
227: } else if (func == FUNC_SIGN) {
228: if (displayText.startsWith("-"))
229: displayText = displayText.substring(1);
230: else
231: displayText = "-" + displayText;
232: } else if (func == FUNC_CE) {
233: resetDisplay();
234: } else if (func == FUNC_C) {
235: reset();
236: } else if (func == FUNC_BACKSPACE) {
237: if (wasPeriod && displayText.endsWith(".")) {
238: //reset period flag
239: wasPeriod = false;
240: } else if (wasPeriod) {
241: // just eat last digit
242: displayText = displayText.substring(0, displayText
243: .length() - 1);
244: } else if (displayText.length() > 2) {
245: if (displayText.length() == 3
246: && displayText.startsWith("-")) {
247: //reset minus sign
248: displayText = displayText.substring(1);
249: } else {
250: // eat digit before the period
251: displayText = displayText.substring(0, displayText
252: .length() - 2)
253: + ".";
254: }
255: } else {
256: // and finally set last digit to zero
257: displayText = "0.";
258: }
259: } else if (func <= FUNC_LAST_MATH) {
260: operation(func);
261: firstDigit = true;
262: wasPeriod = false;
263: }
264: }
265:
266: private boolean isError() {
267: return displayText.indexOf('E') != -1
268: || displayText.indexOf('N') != -1
269: || displayText.indexOf('I') != -1;
270: }
271:
272: public boolean isEnabled(int func) {
273: if (func == FUNC_PERCENT && wasPercent)
274: return false;
275: if (func == FUNC_PERIOD && wasPeriod)
276: return false;
277: if (isError() && func != FUNC_C && func != FUNC_CE)
278: return false;
279: if (!firstDigit && displayText.length() >= 11 && func >= FUNC_0)
280: return false;
281: if (func == FUNC_EQUAL && stack.size() == 0
282: && lastOperation == null)
283: return false;
284: return true;
285: }
286:
287: }
|