diff --git a/AndroidManifest.xml b/AndroidManifest.xml index bae734fe..32630cd4 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,7 +17,7 @@ - + s diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 5cc9a057..5fd57fd4 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -3,6 +3,7 @@ + diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java index 229dc526..c7b9c407 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java @@ -139,7 +139,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh boolean result = false; if ( dragButton instanceof AngleUnitsButton ) { - final String directionText = ((AngleUnitsButton) dragButton).getDirectionText(dragDirection); + final String directionText = ((AngleUnitsButton) dragButton).getText(dragDirection); if ( directionText != null ) { try { @@ -508,7 +508,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh if (CalculatorEngine.GROUPING_SEPARATOR_P_KEY.equals(key) || CalculatorEngine.ROUND_RESULT_P_KEY.equals(key) || CalculatorEngine.RESULT_PRECISION_P_KEY.equals(key) || - CalculatorEngine.ANGLE_UNITS_P_KEY.equals(key)) { + CalculatorEngine.ANGLE_UNITS_P_KEY.equals(key) || + CalculatorEngine.NUMERAL_BASES_P_KEY.equals(key)) { CalculatorEngine.instance.reset(this, preferences); this.calculatorModel.evaluate(); } diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java index 88c285f1..240156ba 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java @@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.model.CalculatorEngine; -import org.solovyev.android.calculator.model.ParseException; +import org.solovyev.android.calculator.model.CalculatorParseException; import org.solovyev.android.calculator.model.TextProcessor; import org.solovyev.android.view.AutoResizeTextView; @@ -97,7 +97,7 @@ public class CalculatorDisplay extends AutoResizeTextView { try { TextHighlighter.Result result = textHighlighter.process(text); text = result.toString(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { Log.e(this.getClass().getName(), e.getMessage(), e); } diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java b/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java index aad53065..73efc3bd 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java @@ -14,9 +14,8 @@ import android.view.ContextMenu; import android.widget.EditText; import org.jetbrains.annotations.NotNull; import org.solovyev.android.calculator.model.CalculatorEngine; -import org.solovyev.android.calculator.model.ParseException; +import org.solovyev.android.calculator.model.CalculatorParseException; import org.solovyev.android.calculator.model.TextProcessor; -import org.solovyev.common.math.calculators.Calculator; /** * User: serso @@ -81,7 +80,7 @@ public class CalculatorEditor extends EditText { selectionStart += result.getOffset(); selectionEnd += result.getOffset(); text = result.toString(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { Log.e(this.getClass().getName(), e.getMessage(), e); } diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java index e592c2ba..522d7f16 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java @@ -25,11 +25,13 @@ import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.model.CalculatorEngine; -import org.solovyev.android.calculator.model.ParseException; +import org.solovyev.android.calculator.model.CalculatorEvalException; +import org.solovyev.android.calculator.model.CalculatorParseException; import org.solovyev.android.calculator.model.Var; import org.solovyev.android.view.CursorControl; import org.solovyev.android.view.HistoryControl; import org.solovyev.common.BooleanMapper; +import org.solovyev.common.msg.Message; import org.solovyev.common.utils.CollectionsUtils; import org.solovyev.common.utils.MutableObject; import org.solovyev.common.utils.StringUtils; @@ -235,7 +237,9 @@ public enum CalculatorModel implements CursorControl, HistoryControl { @NotNull @Override - public Result process(@NotNull String text) throws ParseException { + public Result process(@NotNull String text) throws CalculatorParseException { final String result; int maxNumberOfOpenGroupSymbols = 0; diff --git a/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java b/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java index a03206b5..6ca419a6 100644 --- a/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.model.CalculatorEngine; -import org.solovyev.android.calculator.model.ParseException; +import org.solovyev.android.calculator.model.CalculatorParseException; import org.solovyev.android.calculator.model.TextProcessor; import org.solovyev.common.utils.StringUtils; @@ -24,7 +24,7 @@ class FromJsclNumericTextProcessor implements TextProcessor { @NotNull @Override - public String process(@NotNull String result) throws ParseException { + public String process(@NotNull String result) throws CalculatorParseException { try { final Double doubleValue = Double.valueOf(result); @@ -39,7 +39,7 @@ class FromJsclNumericTextProcessor implements TextProcessor { result = createResultForComplexNumber(result.replace(MathType.IMAGINARY_NUMBER_JSCL, MathType.IMAGINARY_NUMBER)); } catch (NumberFormatException e1) { // throw original one - throw new ParseException(new jscl.text.ParseException(Messages.msg_8, 0, result, result)); + throw new CalculatorParseException(new jscl.text.ParseException(Messages.msg_8, 0, result, result)); } } diff --git a/src/main/java/org/solovyev/android/calculator/math/MathType.java b/src/main/java/org/solovyev/android/calculator/math/MathType.java index 056e0003..4d8dcd24 100644 --- a/src/main/java/org/solovyev/android/calculator/math/MathType.java +++ b/src/main/java/org/solovyev/android/calculator/math/MathType.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.StartsWithFinder; import org.solovyev.android.calculator.model.CalculatorEngine; -import org.solovyev.android.calculator.model.ParseException; +import org.solovyev.android.calculator.model.CalculatorParseException; import org.solovyev.common.utils.CollectionsUtils; import org.solovyev.common.utils.Finder; @@ -48,7 +48,7 @@ public enum MathType { grouping_separator(250, false, false, "'", " "){ @Override - public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws ParseException { + public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws CalculatorParseException { return i; } }, @@ -262,7 +262,7 @@ public enum MathType { return needMultiplicationSignBefore && mathTypeBefore.isNeedMultiplicationSignAfter(); } - public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws ParseException { + public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws CalculatorParseException { final String substitute = getSubstituteToJscl(match); result.append(substitute == null ? match : substitute); return returnI(i, match); @@ -378,7 +378,7 @@ public enum MathType { this.match = match; } - public int processToJscl(@NotNull StringBuilder result, int i) throws ParseException { + public int processToJscl(@NotNull StringBuilder result, int i) throws CalculatorParseException { return mathType.processToJscl(result, i, match); } diff --git a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java index ae689bbb..454ea55c 100644 --- a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java +++ b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java @@ -7,10 +7,7 @@ package org.solovyev.android.calculator.model; import android.content.Context; import android.content.SharedPreferences; -import jscl.AngleUnit; -import jscl.JsclMathEngine; -import jscl.MathEngine; -import jscl.NumeralBase; +import jscl.*; import jscl.math.Generic; import jscl.math.function.Function; import jscl.math.operator.Operator; @@ -157,13 +154,13 @@ public enum CalculatorEngine { } public Result evaluate(@NotNull JsclOperation operation, - @NotNull String expression) throws ParseException { + @NotNull String expression) throws CalculatorParseException, CalculatorEvalException { return evaluate(operation, expression, null); } public Result evaluate(@NotNull JsclOperation operation, @NotNull String expression, - @Nullable MessageRegistry mr) throws ParseException { + @Nullable MessageRegistry mr) throws CalculatorParseException, CalculatorEvalException { synchronized (lock) { final StringBuilder sb = new StringBuilder(); @@ -189,9 +186,9 @@ public enum CalculatorEngine { final String jsclExpression = sb.toString(); final JsclOperation finalOperation = operation; - final String result; final MutableObject calculationResult = new MutableObject(null); - final MutableObject exception = new MutableObject(null); + final MutableObject parseException = new MutableObject(null); + final MutableObject evalException = new MutableObject(null); final MutableObject calculationThread = new MutableObject(null); final CountDownLatch latch = new CountDownLatch(1); @@ -204,16 +201,23 @@ public enum CalculatorEngine { //Log.d(CalculatorEngine.class.getName(), "Calculation thread started work: " + thread.getName()); //System.out.println(jsclExpression); calculationThread.setObject(thread); - calculationResult.setObject(finalOperation.evaluateGeneric(jsclExpression)); + final Generic genericResult = finalOperation.evaluateGeneric(jsclExpression); + + // NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!) + genericResult.toString(); + + calculationResult.setObject(genericResult); + } catch (AbstractJsclArithmeticException e) { + evalException.setObject(new CalculatorEvalException(e, jsclExpression)); } catch (ArithmeticException e) { //System.out.println(e.getMessage()); - exception.setObject(new ParseException(Messages.msg_1, jsclExpression, e.getMessage())); + parseException.setObject(new CalculatorParseException(Messages.msg_1, jsclExpression, e.getMessage())); } catch (StackOverflowError e) { //System.out.println(StringUtils.fromStackTrace(e.getStackTrace())); - exception.setObject(new ParseException(Messages.msg_2, jsclExpression)); + parseException.setObject(new CalculatorParseException(Messages.msg_2, jsclExpression)); } catch (jscl.text.ParseException e) { //System.out.println(e.getMessage()); - exception.setObject(new ParseException(e)); + parseException.setObject(new CalculatorParseException(e)); } catch (ParseInterruptedException e) { //System.out.println(e.getMessage()); // do nothing - we ourselves interrupt the calculations @@ -230,7 +234,8 @@ public enum CalculatorEngine { latch.await(timeout, TimeUnit.MILLISECONDS); //Log.d(CalculatorEngine.class.getName(), "Main thread got up: " + Thread.currentThread().getName()); - final ParseException evalErrorLocal = exception.getObject(); + final CalculatorParseException parseExceptionObject = parseException.getObject(); + final CalculatorEvalException evalExceptionObject = evalException.getObject(); final Object calculationResultLocal = calculationResult.getObject(); final Thread calculationThreadLocal = calculationThread.getObject(); @@ -240,19 +245,24 @@ public enum CalculatorEngine { //calculationThreadLocal.stop(); } - if (evalErrorLocal != null) { + if (parseExceptionObject != null || evalExceptionObject != null) { if (finalOperation == JsclOperation.numeric && preparedExpression.isExistsUndefinedVar()) { return evaluate(JsclOperation.simplify, expression, mr); } - throw evalErrorLocal; + + if (parseExceptionObject != null) { + throw parseExceptionObject; + } else { + throw evalExceptionObject; + } } if (calculationResultLocal == null) { - throw new ParseException(Messages.msg_3, jsclExpression); + throw new CalculatorParseException(Messages.msg_3, jsclExpression); } } catch (InterruptedException e) { - throw new ParseException(Messages.msg_4, jsclExpression); + throw new CalculatorParseException(Messages.msg_4, jsclExpression); } final Generic genericResult = calculationResult.getObject(); diff --git a/src/main/java/org/solovyev/android/calculator/model/CalculatorEvalException.java b/src/main/java/org/solovyev/android/calculator/model/CalculatorEvalException.java new file mode 100644 index 00000000..485cac09 --- /dev/null +++ b/src/main/java/org/solovyev/android/calculator/model/CalculatorEvalException.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.calculator.model; + +import org.jetbrains.annotations.NotNull; +import org.solovyev.common.exceptions.SersoException; +import org.solovyev.common.msg.Message; +import org.solovyev.common.msg.MessageType; + +import java.util.List; +import java.util.Locale; + +/** + * User: serso + * Date: 12/8/11 + * Time: 1:27 AM + */ +public class CalculatorEvalException extends SersoException implements Message { + + @NotNull + private final Message message; + + @NotNull + private final String expression; + + public CalculatorEvalException(@NotNull Message message, String expression) { + this.message = message; + this.expression = expression; + } + + + @NotNull + public String getExpression() { + return expression; + } + + @NotNull + @Override + public String getMessageCode() { + return this.message.getMessageCode(); + } + + @NotNull + @Override + public List getParameters() { + return this.message.getParameters(); + } + + @NotNull + @Override + public MessageType getMessageType() { + return this.message.getMessageType(); + } + + @Override + @NotNull + public String getLocalizedMessage() { + return this.message.getLocalizedMessage(Locale.getDefault()); + } + + @NotNull + @Override + public String getLocalizedMessage(@NotNull Locale locale) { + return this.message.getLocalizedMessage(locale); + } +} + diff --git a/src/main/java/org/solovyev/android/calculator/model/ParseException.java b/src/main/java/org/solovyev/android/calculator/model/CalculatorParseException.java similarity index 80% rename from src/main/java/org/solovyev/android/calculator/model/ParseException.java rename to src/main/java/org/solovyev/android/calculator/model/CalculatorParseException.java index 340fa9da..176e1492 100644 --- a/src/main/java/org/solovyev/android/calculator/model/ParseException.java +++ b/src/main/java/org/solovyev/android/calculator/model/CalculatorParseException.java @@ -21,7 +21,7 @@ import java.util.Locale; * Date: 10/6/11 * Time: 9:25 PM */ -public class ParseException extends SersoException implements Message { +public class CalculatorParseException extends SersoException implements Message { @NotNull private final Message message; @@ -32,19 +32,19 @@ public class ParseException extends SersoException implements Message { @Nullable private final Integer position; - public ParseException(@NotNull jscl.text.ParseException jsclParseException) { + public CalculatorParseException(@NotNull jscl.text.ParseException jsclParseException) { this.message = jsclParseException; this.expression = jsclParseException.getExpression(); this.position = jsclParseException.getPosition(); } - public ParseException(@NotNull String messageId, @Nullable Integer position, @NotNull String expression, Object... parameters) { + public CalculatorParseException(@NotNull String messageId, @Nullable Integer position, @NotNull String expression, Object... parameters) { this.message = new AndroidMessage(messageId, MessageType.error, parameters); this.expression = expression; this.position = position; } - public ParseException(@NotNull String messageId, @NotNull String expression, Object... parameters) { + public CalculatorParseException(@NotNull String messageId, @NotNull String expression, Object... parameters) { this(messageId, null, expression, parameters); } diff --git a/src/main/java/org/solovyev/android/calculator/model/DummyTextProcessor.java b/src/main/java/org/solovyev/android/calculator/model/DummyTextProcessor.java index 02974bf2..d7859404 100644 --- a/src/main/java/org/solovyev/android/calculator/model/DummyTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/DummyTextProcessor.java @@ -19,7 +19,7 @@ public enum DummyTextProcessor implements TextProcessor { @NotNull @Override - public String process(@NotNull String s) throws ParseException { + public String process(@NotNull String s) throws CalculatorParseException { return s; } } diff --git a/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java b/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java index 07c54dd8..2222324c 100644 --- a/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java @@ -1,7 +1,6 @@ package org.solovyev.android.calculator.model; import jscl.MathContext; -import jscl.MathEngine; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.math.MathType; @@ -25,7 +24,7 @@ public class FromJsclSimplifyTextProcessor implements TextProcessor { @NotNull @Override - public String process(@NotNull String s) throws ParseException { + public String process(@NotNull String s) throws CalculatorParseException { final StringBuilder sb = new StringBuilder(); final NumberBuilder numberBuilder = new NumberBuilder(true, mathContext.getNumeralBase()); diff --git a/src/main/java/org/solovyev/android/calculator/model/TextProcessor.java b/src/main/java/org/solovyev/android/calculator/model/TextProcessor.java index d89a69b2..5134d988 100644 --- a/src/main/java/org/solovyev/android/calculator/model/TextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/TextProcessor.java @@ -10,5 +10,5 @@ import org.jetbrains.annotations.NotNull; public interface TextProcessor { @NotNull - T process(@NotNull String s) throws ParseException; + T process(@NotNull String s) throws CalculatorParseException; } diff --git a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java index 5ad51609..2769ee54 100644 --- a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java @@ -22,16 +22,16 @@ class ToJsclTextProcessor implements TextProcessor { @Override @NotNull - public PreparedExpression process(@NotNull String s) throws ParseException { + public PreparedExpression process(@NotNull String s) throws CalculatorParseException { return processWithDepth(s, 0, new ArrayList()); } - private static PreparedExpression processWithDepth(@NotNull String s, int depth, @NotNull List undefinedVars) throws ParseException { + private static PreparedExpression processWithDepth(@NotNull String s, int depth, @NotNull List undefinedVars) throws CalculatorParseException { return replaceVariables(processExpression(s).toString(), depth, undefinedVars); } @NotNull - private static StringBuilder processExpression(@NotNull String s) throws ParseException { + private static StringBuilder processExpression(@NotNull String s) throws CalculatorParseException { final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); final StringBuilder result = new StringBuilder(); @@ -57,7 +57,7 @@ class ToJsclTextProcessor implements TextProcessor { if (mathTypeBefore != null && (mathTypeBefore.getMathType() == MathType.function || mathTypeBefore.getMathType() == MathType.operator) && CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) { - throw new ParseException(Messages.msg_5, i, s, mathTypeBefore.getMatch()); + throw new CalculatorParseException(Messages.msg_5, i, s, mathTypeBefore.getMatch()); } i = mathTypeResult.processToJscl(result, i); @@ -66,9 +66,9 @@ class ToJsclTextProcessor implements TextProcessor { } @NotNull - private static PreparedExpression replaceVariables(@NotNull final String s, int depth, @NotNull List undefinedVars) throws ParseException { + private static PreparedExpression replaceVariables(@NotNull final String s, int depth, @NotNull List undefinedVars) throws CalculatorParseException { if (depth >= MAX_DEPTH) { - throw new ParseException(Messages.msg_6, s); + throw new CalculatorParseException(Messages.msg_6, s); } else { depth++; } diff --git a/src/main/java/org/solovyev/android/calculator/plot/MyXYSeries.java b/src/main/java/org/solovyev/android/calculator/plot/MyXYSeries.java index e9d3f2df..42ba9e29 100644 --- a/src/main/java/org/solovyev/android/calculator/plot/MyXYSeries.java +++ b/src/main/java/org/solovyev/android/calculator/plot/MyXYSeries.java @@ -136,7 +136,7 @@ public class MyXYSeries extends XYSeries { * @param x the value for the X axis * @param y the value for the Y axis */ - public synchronized void add(double x, double y) { + public void add(double x, double y) { boolean added = false; for (int i = 0; i < mX.size(); i++ ) { if ( mX.get(i) > x ) { @@ -174,7 +174,7 @@ public class MyXYSeries extends XYSeries { * * @param index the index in the series of the value to remove */ - public synchronized void remove(int index) { + public void remove(int index) { double removedX = mX.remove(index); double removedY = mY.remove(index); if (removedX == mMinX || removedX == mMaxX || removedY == mMinY || removedY == mMaxY) { @@ -185,7 +185,7 @@ public class MyXYSeries extends XYSeries { /** * Removes all the existing values from the series. */ - public synchronized void clear() { + public void clear() { mX.clear(); mY.clear(); initRange(); @@ -197,7 +197,7 @@ public class MyXYSeries extends XYSeries { * @param index the index * @return the X value */ - public synchronized double getX(int index) { + public double getX(int index) { return mX.get(index); } @@ -207,7 +207,7 @@ public class MyXYSeries extends XYSeries { * @param index the index * @return the Y value */ - public synchronized double getY(int index) { + public double getY(int index) { return mY.get(index); } @@ -216,7 +216,7 @@ public class MyXYSeries extends XYSeries { * * @return the series item count */ - public synchronized int getItemCount() { + public int getItemCount() { return mX == null ? 0 : mX.size(); } diff --git a/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java b/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java index b3b9e2f8..565432c3 100644 --- a/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java +++ b/src/main/java/org/solovyev/android/calculator/plot/PlotUtils.java @@ -39,7 +39,7 @@ public final class PlotUtils { @NotNull MyXYSeries realSeries, @NotNull MyXYSeries imagSeries, boolean addExtra, - int numberOfSteps) { + int numberOfSteps) throws ArithmeticException { boolean imagExists = false; diff --git a/src/main/java/org/solovyev/android/view/widgets/AngleUnitsButton.java b/src/main/java/org/solovyev/android/view/widgets/AngleUnitsButton.java index e8fdc727..1ece9285 100644 --- a/src/main/java/org/solovyev/android/view/widgets/AngleUnitsButton.java +++ b/src/main/java/org/solovyev/android/view/widgets/AngleUnitsButton.java @@ -12,7 +12,6 @@ import android.graphics.Paint; import android.text.TextPaint; import android.util.AttributeSet; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.model.CalculatorEngine; @@ -27,21 +26,18 @@ public class AngleUnitsButton extends DirectionDragButton { super(context, attrs); } - @Nullable @Override - protected TextPaint initUpDownTextPaint(@Nullable Paint paint, @NotNull DragDirection direction) { - final TextPaint result = super.initUpDownTextPaint(paint, direction); + protected void initDirectionTextPaint(@NotNull Paint basePaint, + @NotNull DirectionTextData directionTextData, + @NotNull Resources resources) { + super.initDirectionTextPaint(basePaint, directionTextData, resources); - if (result != null) { - final Resources resources = getResources(); - if ( CalculatorEngine.instance.getEngine().getAngleUnits().name().equals(getDirectionText(direction)) ) { - result.setColor(resources.getColor(R.color.selected_angle_unit_text_color)); - } else { - result.setColor(resources.getColor(R.color.default_text_color)); - result.setAlpha(getDefaultDirectionTextAlpha()); - } + final TextPaint directionTextPaint = directionTextData.getPaint(); + if (CalculatorEngine.instance.getEngine().getAngleUnits().name().equals(directionTextData.getText())) { + directionTextPaint.setColor(resources.getColor(R.color.selected_angle_unit_text_color)); + } else { + directionTextPaint.setColor(resources.getColor(R.color.default_text_color)); + directionTextPaint.setAlpha(getDefaultDirectionTextAlpha()); } - - return result; } } diff --git a/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java b/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java index 31eeca1b..830f2b8a 100644 --- a/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java +++ b/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java @@ -18,6 +18,9 @@ import org.solovyev.android.calculator.R; import org.solovyev.common.utils.Point2d; import org.solovyev.common.utils.StringUtils; +import java.util.EnumMap; +import java.util.Map; + /** * User: serso * Date: 7/17/11 @@ -31,7 +34,10 @@ public class DirectionDragButton extends DragButton { @Nullable private String textMiddle; - private static class DirectionTextData { + protected static class DirectionTextData { + + @NotNull + private final GuiDragDirection guiDragDirection; @NotNull private String text; @@ -42,10 +48,16 @@ public class DirectionDragButton extends DragButton { @NotNull private TextPaint paint; - private DirectionTextData(@NotNull String text) { + private DirectionTextData(@NotNull GuiDragDirection guiDragDirection, @NotNull String text) { + this.guiDragDirection = guiDragDirection; this.text = text; } + @NotNull + public GuiDragDirection getGuiDragDirection() { + return guiDragDirection; + } + @NotNull public String getText() { return text; @@ -74,36 +86,106 @@ public class DirectionDragButton extends DragButton { } } - @Nullable + protected static enum GuiDragDirection { + up(DragDirection.up) { + @Override + public int getAttributeId() { + return R.styleable.DragButton_textUp; + } + + @NotNull + @Override + public Point2d getTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, CharSequence baseText, int w, int h) { + return getUpDownTextPosition(paint, basePaint, text, baseText, 1, w, h); + } + }, + down(DragDirection.down) { + @Override + public int getAttributeId() { + return R.styleable.DragButton_textDown; + } + + @NotNull + @Override + public Point2d getTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, CharSequence baseText, int w, int h) { + return getUpDownTextPosition(paint, basePaint, text, baseText, -1, w, h); + } + }, + left(DragDirection.left) { + @Override + public int getAttributeId() { + return R.styleable.DragButton_textLeft; + } + + @NotNull + @Override + public Point2d getTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, CharSequence baseText, int w, int h) { + throw new UnsupportedOperationException("Not implemented yet!"); + } + }/*, + right(DragDirection.right) { + @Override + public int getAttributeId() { + return 0; + } + }*/; + + @NotNull + private final DragDirection dragDirection; + + GuiDragDirection(@NotNull DragDirection dragDirection) { + this.dragDirection = dragDirection; + } + + public abstract int getAttributeId(); + + @NotNull + public abstract Point2d getTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, CharSequence baseText, int w, int h); + + @NotNull + private static Point2d getUpDownTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, CharSequence baseText, float direction, int w, int h) { + final Point2d result = new Point2d(); + + float width = paint.measureText(text.toString() + " "); + result.setX(w - width); + + float selfHeight = paint.ascent() + paint.descent(); + + basePaint.measureText(StringUtils.getNotEmpty(baseText, "|")); + + if (direction < 0) { + result.setY(h / 2 + h / 3 - selfHeight / 2); + } else { + result.setY(h / 2 - h / 3 - selfHeight / 2); + } + + return result; + } + + @Nullable + public static GuiDragDirection valueOf ( @NotNull DragDirection dragDirection ) { + for (GuiDragDirection guiDragDirection : values()) { + if ( guiDragDirection.dragDirection == dragDirection ) { + return guiDragDirection; + } + } + return null; + } + } + + @NotNull + private final Map directionTextDataMap = new EnumMap(GuiDragDirection.class); + + @NotNull private Float directionTextScale = DEFAULT_DIRECTION_TEXT_SCALE; + private boolean initialized = false; + public DirectionDragButton(Context context, @NotNull AttributeSet attrs) { super(context, attrs, false); init(context, attrs); } - @Nullable - public String getDirectionText(@NotNull DragDirection direction) { - final String result; - - switch (direction) { - case up: - result = this.getTextUp(); - break; - - case down: - result = this.getTextDown(); - break; - - default: - result = null; - break; - } - - return result; - } - - private void init(@NotNull Context context, @NotNull AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, org.solovyev.android.calculator.R.styleable.DragButton); @@ -111,16 +193,24 @@ public class DirectionDragButton extends DragButton { final int N = a.getIndexCount(); for (int i = 0; i < N; i++) { int attr = a.getIndex(i); - switch (attr) { - case R.styleable.DragButton_textUp: - this.textUp = a.getString(attr); - break; - case R.styleable.DragButton_textDown: - this.textDown = a.getString(attr); - break; - case R.styleable.DragButton_directionTextScale: - this.directionTextScale = Float.valueOf(a.getString(attr)); - break; + + final String attrValue = a.getString(attr); + + if (!StringUtils.isEmpty(attrValue)) { + switch (attr) { + case R.styleable.DragButton_directionTextScale: + this.directionTextScale = Float.valueOf(attrValue); + break; + default: + // try drag direction text + for (GuiDragDirection guiDragDirection : GuiDragDirection.values()) { + if ( guiDragDirection.getAttributeId() == attr ) { + this.directionTextDataMap.put(guiDragDirection, new DirectionTextData(guiDragDirection, attrValue)); + break; + } + } + break; + } } } @@ -128,95 +218,55 @@ public class DirectionDragButton extends DragButton { this.textMiddle = String.valueOf(getText()); super.init(context); + initialized = true; } @Override protected void measureText() { super.measureText(); - final Paint basePaint = getPaint(); + if (initialized) { + final Paint basePaint = getPaint(); + final Resources resources = getResources(); - if (textUp != null) { - initUpDownTextPaint(basePaint, DragDirection.up); - textUpPosition = getTextPosition(upTextPaint, basePaint, textUp, getText(), 1, getWidth(), getHeight(), getDirectionTextScale()); - } + for (DirectionTextData directionTextData : directionTextDataMap.values()) { + initDirectionTextPaint(basePaint, directionTextData, resources); - if (textDown != null) { - initUpDownTextPaint(basePaint, DragDirection.down); - textDownPosition = getTextPosition(downTextPaint, basePaint, textDown, getText(), -1, getWidth(), getHeight(), getDirectionTextScale()); - } + final GuiDragDirection guiDragDirection = directionTextData.getGuiDragDirection(); + final String directionText = directionTextData.getText(); + final Paint directionPaint = directionTextData.getPaint(); - /*if (textDownPosition != null && textUpPosition != null) { - if (textDownPosition.getX() > textUpPosition.getX()) { - textDownPosition.setX(textUpPosition.getX()); - } else { - textUpPosition.setX(textDownPosition.getX()); + directionTextData.setPosition(guiDragDirection.getTextPosition(directionPaint, basePaint, directionText, getText(), getWidth(), getHeight())); } - }*/ - - } - - public static Point2d getTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, CharSequence baseText, float direction, int w, int h, float scale) { - final Point2d result = new Point2d(); - - float width = paint.measureText(text.toString() + " "); - result.setX(w - width); - - float selfHeight = paint.ascent() + paint.descent(); - - basePaint.measureText(StringUtils.getNotEmpty(baseText, "|")); - - if (direction < 0) { - result.setY(h / 2 + h / 3 - selfHeight / 2); - } else { - result.setY(h / 2 - h / 3 - selfHeight / 2); } - - return result; } + @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); - - if (textUp != null && textUpPosition != null) { - initUpDownTextPaint(null, DragDirection.up); - canvas.drawText(textUp, 0, textUp.length(), textUpPosition.getX(), textUpPosition.getY(), upTextPaint); - } - - if (textDown != null && textDownPosition != null) { - initUpDownTextPaint(null, DragDirection.down); - canvas.drawText(textDown, 0, textDown.length(), textDownPosition.getX(), textDownPosition.getY(), downTextPaint); - } - } - - @Nullable - protected TextPaint initUpDownTextPaint(@Nullable Paint paint, @NotNull DragDirection direction) { - if (paint == null) { - paint = getPaint(); - } - + final TextPaint paint = getPaint(); final Resources resources = getResources(); - if (direction == DragDirection.up) { - upTextPaint = getUpDownTextPaint(paint, resources, getDirectionTextScale()); - return upTextPaint; - } else if (direction == DragDirection.down) { - downTextPaint = getUpDownTextPaint(paint, resources, getDirectionTextScale()); - return downTextPaint; - } - return null; + for (DirectionTextData directionTextData : directionTextDataMap.values()) { + initDirectionTextPaint(paint, directionTextData, resources); + final String text = directionTextData.getText(); + final Point2d position = directionTextData.getPosition(); + canvas.drawText(text, 0, text.length(), position.getX(), position.getY(), directionTextData.getPaint()); + } } - @NotNull - private static TextPaint getUpDownTextPaint(@NotNull Paint basePaint, @NotNull Resources resources, @NotNull Float directionTextScale) { - final TextPaint result = new TextPaint(basePaint); - result.setColor(resources.getColor(R.color.button_text_color)); - result.setAlpha(getDefaultDirectionTextAlpha()); - result.setTextSize(basePaint.getTextSize() * directionTextScale); + protected void initDirectionTextPaint(@NotNull Paint basePaint, + @NotNull DirectionTextData directionTextData, + @NotNull Resources resources) { + final TextPaint directionTextPaint = new TextPaint(basePaint); - return result; + directionTextPaint.setColor(resources.getColor(R.color.button_text_color)); + directionTextPaint.setAlpha(getDefaultDirectionTextAlpha()); + directionTextPaint.setTextSize(basePaint.getTextSize() * getDirectionTextScale()); + + directionTextData.setPaint(directionTextPaint); } protected static int getDefaultDirectionTextAlpha() { @@ -225,12 +275,12 @@ public class DirectionDragButton extends DragButton { @Nullable public String getTextUp() { - return textUp; + return getText(GuiDragDirection.up); } @Nullable public String getTextDown() { - return textDown; + return getText(GuiDragDirection.down); } @Nullable @@ -240,22 +290,20 @@ public class DirectionDragButton extends DragButton { @Nullable public String getText(@NotNull DragDirection direction) { - final String result; - - if (direction == DragDirection.up) { - result = getTextUp(); - } else if (direction == DragDirection.down) { - result = getTextDown(); - } else { - result = null; - } - - return result; + final GuiDragDirection guiDragDirection = GuiDragDirection.valueOf(direction); + return guiDragDirection == null ? null : getText(guiDragDirection); } + @Nullable + private String getText(@NotNull GuiDragDirection direction) { + DirectionTextData directionTextData = this.directionTextDataMap.get(direction); + return directionTextData == null ? null : directionTextData.getText(); + } + + @NotNull public Float getDirectionTextScale() { - return directionTextScale == null ? DEFAULT_DIRECTION_TEXT_SCALE : directionTextScale; + return directionTextScale; } } diff --git a/src/main/java/org/solovyev/android/view/widgets/VibratorContainer.java b/src/main/java/org/solovyev/android/view/widgets/VibratorContainer.java index d85684ea..f7a3c177 100644 --- a/src/main/java/org/solovyev/android/view/widgets/VibratorContainer.java +++ b/src/main/java/org/solovyev/android/view/widgets/VibratorContainer.java @@ -20,6 +20,7 @@ import org.solovyev.common.NumberMapper; public class VibratorContainer implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String HAPTIC_FEEDBACK_P_KEY = "org.solovyev.android.calculator.CalculatorModel_haptic_feedback"; + public static final boolean HAPTIC_FEEDBACK_DEFAULT = false; public static final String HAPTIC_FEEDBACK_DURATION_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_haptic_feedback_duration_key"; private final static NumberMapper mapper = new NumberMapper(Long.class); @@ -50,7 +51,7 @@ public class VibratorContainer implements SharedPreferences.OnSharedPreferenceCh @Override public void onSharedPreferenceChanged(SharedPreferences preferences, @Nullable String key) { - if (preferences.getBoolean(HAPTIC_FEEDBACK_P_KEY, false)) { + if (preferences.getBoolean(HAPTIC_FEEDBACK_P_KEY, VibratorContainer.HAPTIC_FEEDBACK_DEFAULT)) { //noinspection ConstantConditions this.time = getScaledValue(mapper.parseValue(preferences.getString(HAPTIC_FEEDBACK_DURATION_P_KEY, mapper.formatValue(getScaledValue(defaultVibrationTime))))); } else { diff --git a/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java b/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java index f6367813..5ffe47c2 100644 --- a/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java +++ b/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java @@ -6,6 +6,7 @@ package org.solovyev.android.calculator.model; import jscl.AngleUnit; +import jscl.NumeralBase; import jscl.math.Expression; import jscl.math.Generic; import jscl.math.function.Constant; @@ -41,7 +42,7 @@ public class CalculatorEngineTest { try { cm.evaluate(JsclOperation.numeric, "3^10^10^10"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { if (e.getMessageCode().equals(Messages.msg_3)) { } else { @@ -53,7 +54,7 @@ public class CalculatorEngineTest { try { cm.evaluate(JsclOperation.numeric, "9999999!"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { if (e.getMessageCode().equals(Messages.msg_3)) { } else { @@ -136,7 +137,7 @@ public class CalculatorEngineTest { try { junit.framework.Assert.assertEquals("√(-1)!", cm.evaluate(JsclOperation.numeric, "i!").getResult()); fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } junit.framework.Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "(π/π)!").getResult()); @@ -144,7 +145,7 @@ public class CalculatorEngineTest { try { junit.framework.Assert.assertEquals("i", cm.evaluate(JsclOperation.numeric, "(-1)i!").getResult()); fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } junit.framework.Assert.assertEquals("24i", cm.evaluate(JsclOperation.numeric, "4!i").getResult()); @@ -213,7 +214,7 @@ public class CalculatorEngineTest { } @Test - public void testI() throws ParseException { + public void testI() throws CalculatorParseException, CalculatorEvalException { final CalculatorEngine cm = CalculatorEngine.instance; Assert.assertEquals("-i", cm.evaluate(JsclOperation.numeric, "i^3").getResult()); @@ -243,13 +244,13 @@ public class CalculatorEngineTest { try { cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos(cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos())))))))))))))))))))))))))))))))))))))"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } Assert.assertEquals("0.34+1.382i", cm.evaluate(JsclOperation.numeric, "ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(100)))))))))))))))").getResult()); try { cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos())))))))))))))))))))))))))))))))))))"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } final AngleUnit defaultAngleUnit = cm.getEngine().getAngleUnits(); @@ -266,7 +267,7 @@ public class CalculatorEngineTest { try { cm.evaluate(JsclOperation.numeric, "sin"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } } @@ -334,7 +335,7 @@ public class CalculatorEngineTest { try { Assert.assertEquals("0.017", cm.evaluate(JsclOperation.numeric, "°")); fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } @@ -345,7 +346,7 @@ public class CalculatorEngineTest { try { Assert.assertEquals("∂(cos(t), t, t,1°)", cm.evaluate(JsclOperation.numeric, "∂(cos(t),t,t,1°)").getResult()); fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } Assert.assertEquals("∂(cos(t), t, t,1°)", cm.evaluate(JsclOperation.simplify, "∂(cos(t),t,t,1°)").getResult()); @@ -353,4 +354,23 @@ public class CalculatorEngineTest { cm.getEngine().setAngleUnits(defaultAngleUnit); } } + + @Test + public void testNumeralSystems() throws Exception { + final CalculatorEngine cm = CalculatorEngine.instance; + + final NumeralBase defaultNumeralBase = cm.getEngine().getNumeralBase(); + try{ + cm.getEngine().setNumeralBase(NumeralBase.bin); + Assert.assertEquals("101", cm.evaluate(JsclOperation.numeric, "10+11").getResult()); + try { + cm.evaluate(JsclOperation.numeric, "10/11"); + fail(); + } catch (CalculatorParseException e) { + // ok + } + } finally { + cm.setNumeralBase(defaultNumeralBase); + } + } } diff --git a/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java b/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java index bcd76949..92c472ba 100644 --- a/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java +++ b/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java @@ -23,7 +23,7 @@ public class ToJsclTextProcessorTest { } @Test - public void testSpecialCases() throws ParseException { + public void testSpecialCases() throws CalculatorParseException { final ToJsclTextProcessor preprocessor = new ToJsclTextProcessor(); Assert.assertEquals( "3^E10", preprocessor.process("3^E10").toString()); } @@ -62,30 +62,30 @@ public class ToJsclTextProcessorTest { try { preprocessor.process("ln()"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } try { preprocessor.process("ln()ln()"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } try { preprocessor.process("eln()eln()ln()ln()ln()e"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } try { preprocessor.process("ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln()))))))))))))))"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } try { preprocessor.process("cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos(cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos())))))))))))))))))))))))))))))))))))))"); Assert.fail(); - } catch (ParseException e) { + } catch (CalculatorParseException e) { } }