From 848012615e1f5efc411aa853fd70e6677afa1ced Mon Sep 17 00:00:00 2001 From: serso Date: Wed, 14 Dec 2011 02:47:04 +0400 Subject: [PATCH] changes --- res/layout/calc_eight_digit_button.xml | 1 + res/layout/calc_five_digit_button.xml | 1 + res/layout/calc_four_digit_button.xml | 1 + res/layout/calc_nine_digit_button.xml | 1 + res/layout/calc_one_digit_button.xml | 1 + res/layout/calc_seven_digit_button.xml | 1 + res/layout/calc_six_digit_button.xml | 1 + res/layout/calc_three_digit_button.xml | 1 + res/layout/calc_title.xml | 30 +++++ res/layout/calc_two_digit_button.xml | 1 + res/values/default_values.xml | 2 + res/values/styles.xml | 14 +++ .../calculator/CalculatorActivity.java | 40 +++++-- .../calculator/CalculatorAdditionalTitle.java | 44 +++++++ .../android/calculator/CalculatorDisplay.java | 2 +- .../android/calculator/CalculatorEditor.java | 2 +- .../android/calculator/TextHighlighter.java | 48 ++++++-- .../jscl/FromJsclNumericTextProcessor.java | 108 +----------------- .../calculator/jscl/JsclOperation.java | 6 +- .../android/calculator/math/MathType.java | 9 ++ .../calculator/model/CalculatorEngine.java | 82 ++++--------- .../calculator/model/DummyTextProcessor.java | 7 +- .../model/FromJsclSimplifyTextProcessor.java | 10 +- .../calculator/model/NumberBuilder.java | 6 +- .../calculator/model/TextProcessor.java | 4 +- .../calculator/model/ToJsclTextProcessor.java | 2 +- .../view/widgets/DirectionDragButton.java | 19 ++- .../view/widgets/SimpleOnDragListener.java | 10 +- .../calculator/TextHighlighterTest.java | 5 + .../FromJsclNumericTextProcessorTest.java | 19 ++- .../model/CalculatorEngineTest.java | 8 +- .../FromJsclSimplifyTextProcessorTest.java | 5 + .../model/ToJsclTextProcessorTest.java | 18 +++ 33 files changed, 298 insertions(+), 211 deletions(-) create mode 100644 res/layout/calc_title.xml create mode 100644 src/main/java/org/solovyev/android/calculator/CalculatorAdditionalTitle.java diff --git a/res/layout/calc_eight_digit_button.xml b/res/layout/calc_eight_digit_button.xml index 650dff8f..ed3f46ad 100644 --- a/res/layout/calc_eight_digit_button.xml +++ b/res/layout/calc_eight_digit_button.xml @@ -10,6 +10,7 @@ xmlns:calc="http://schemas.android.com/apk/res/org.solovyev.android.calculator" a:id="@+id/eightDigitButton" a:text="8" calc:textUp="ln" + calc:textLeft="0b:" calc:textDown="lg" calc:directionTextScale="0.5" diff --git a/res/layout/calc_five_digit_button.xml b/res/layout/calc_five_digit_button.xml index a1250be7..c18062ec 100644 --- a/res/layout/calc_five_digit_button.xml +++ b/res/layout/calc_five_digit_button.xml @@ -10,6 +10,7 @@ a:id="@+id/fiveDigitButton" a:text="5" calc:textUp="t" + calc:textLeft="e" calc:textDown="j" style="?digitButtonStyle" a:onClick="digitButtonClickHandler"/> \ No newline at end of file diff --git a/res/layout/calc_four_digit_button.xml b/res/layout/calc_four_digit_button.xml index 9cca9b65..d7475560 100644 --- a/res/layout/calc_four_digit_button.xml +++ b/res/layout/calc_four_digit_button.xml @@ -10,6 +10,7 @@ a:id="@+id/fourDigitButton" a:text="4" calc:textUp="x" + calc:textLeft="d" calc:textDown="y" style="?digitButtonStyle" a:onClick="digitButtonClickHandler"/> \ No newline at end of file diff --git a/res/layout/calc_nine_digit_button.xml b/res/layout/calc_nine_digit_button.xml index fe28538f..327d5e6f 100644 --- a/res/layout/calc_nine_digit_button.xml +++ b/res/layout/calc_nine_digit_button.xml @@ -10,6 +10,7 @@ xmlns:calc="http://schemas.android.com/apk/res/org.solovyev.android.calculator" a:id="@+id/nineDigitButton" a:text="9" calc:textDown="e" + calc:textLeft="0o:" calc:textUp="π" calc:directionTextScale="0.5" style="?digitButtonStyle" diff --git a/res/layout/calc_one_digit_button.xml b/res/layout/calc_one_digit_button.xml index 4be170b3..f01a399c 100644 --- a/res/layout/calc_one_digit_button.xml +++ b/res/layout/calc_one_digit_button.xml @@ -11,6 +11,7 @@ a:id="@+id/oneDigitButton" a:text="1" calc:textUp="sin" + calc:textLeft="a" calc:textDown="asin" style="?digitButtonStyle" a:onClick="digitButtonClickHandler"/> \ No newline at end of file diff --git a/res/layout/calc_seven_digit_button.xml b/res/layout/calc_seven_digit_button.xml index ebbb8fcf..c467479b 100644 --- a/res/layout/calc_seven_digit_button.xml +++ b/res/layout/calc_seven_digit_button.xml @@ -10,6 +10,7 @@ xmlns:calc="http://schemas.android.com/apk/res/org.solovyev.android.calculator" a:id="@+id/sevenDigitButton" a:text="7" calc:textUp="i" + calc:textLeft="0x:" calc:textDown="!" calc:directionTextScale="0.5" diff --git a/res/layout/calc_six_digit_button.xml b/res/layout/calc_six_digit_button.xml index 170391d6..91b54339 100644 --- a/res/layout/calc_six_digit_button.xml +++ b/res/layout/calc_six_digit_button.xml @@ -11,6 +11,7 @@ calc:textUp="deg" a:id="@+id/sixDigitButton" a:text="6" + calc:textLeft="f" calc:textDown="rad" style="?digitButtonStyle" a:onClick="digitButtonClickHandler"/> \ No newline at end of file diff --git a/res/layout/calc_three_digit_button.xml b/res/layout/calc_three_digit_button.xml index 75883444..a7ecee06 100644 --- a/res/layout/calc_three_digit_button.xml +++ b/res/layout/calc_three_digit_button.xml @@ -11,6 +11,7 @@ a:id="@+id/threeDigitButton" a:text="3" calc:textUp="tan" + calc:textLeft="c" calc:textDown="atan" style="?digitButtonStyle" a:onClick="digitButtonClickHandler"/> \ No newline at end of file diff --git a/res/layout/calc_title.xml b/res/layout/calc_title.xml new file mode 100644 index 00000000..1837e073 --- /dev/null +++ b/res/layout/calc_title.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/calc_two_digit_button.xml b/res/layout/calc_two_digit_button.xml index f2897ad6..8c05fac1 100644 --- a/res/layout/calc_two_digit_button.xml +++ b/res/layout/calc_two_digit_button.xml @@ -11,6 +11,7 @@ a:id="@+id/twoDigitButton" a:text="2" calc:textUp="cos" + calc:textLeft="b" calc:textDown="acos" style="?digitButtonStyle" a:onClick="digitButtonClickHandler"/> \ No newline at end of file diff --git a/res/values/default_values.xml b/res/values/default_values.xml index fb28c9bc..215dfecf 100644 --- a/res/values/default_values.xml +++ b/res/values/default_values.xml @@ -8,8 +8,10 @@ org.solovyev.android.calculator.DragButtonCalibrationActivity_distance 15;350 + org.solovyev.android.calculator.DragButtonCalibrationActivity_angle 0;45 + org.solovyev.android.calculator.DragButtonCalibrationActivity_duration 40;2500 diff --git a/res/values/styles.xml b/res/values/styles.xml index 276197f4..4ede49f7 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -6,6 +6,20 @@ + + + + + diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java index 73491017..450cab28 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java @@ -66,6 +66,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh public void onCreate(@Nullable Bundle savedInstanceState) { Log.d(this.getClass().getName(), "org.solovyev.android.calculator.CalculatorActivity.onCreate()"); + final boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); setDefaultValues(preferences); @@ -74,6 +76,13 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh super.onCreate(savedInstanceState); setLayout(preferences); + if (customTitleSupported) { + getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.calc_title); + final CalculatorAdditionalTitle additionalAdditionalTitleText = (CalculatorAdditionalTitle)findViewById(R.id.additional_title_text); + additionalAdditionalTitleText.init(preferences); + preferences.registerOnSharedPreferenceChangeListener(additionalAdditionalTitleText); + } + ResourceCache.instance.initCaptions(ApplicationContext.getInstance(), R.string.class); firstTimeInit(preferences); @@ -137,6 +146,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh private class AngleUnitsChanger implements SimpleOnDragListener.DragProcessor { + private final DigitButtonDragProcessor processor = new DigitButtonDragProcessor(calculatorModel); + @Override public boolean processDragEvent(@NotNull DragDirection dragDirection, @NotNull DragButton dragButton, @@ -144,22 +155,26 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh @NotNull MotionEvent motionEvent) { boolean result = false; - if ( dragButton instanceof AngleUnitsButton ) { - final String directionText = ((AngleUnitsButton) dragButton).getText(dragDirection); - if ( directionText != null ) { - try { + if (dragButton instanceof AngleUnitsButton) { + if (dragDirection == DragDirection.up || dragDirection == DragDirection.down ) { + final String directionText = ((AngleUnitsButton) dragButton).getText(dragDirection); + if ( directionText != null ) { + try { - final AngleUnit angleUnits = AngleUnit.valueOf(directionText); + final AngleUnit angleUnits = AngleUnit.valueOf(directionText); - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CalculatorActivity.this); - final SharedPreferences.Editor editor = preferences.edit(); - editor.putString(CalculatorEngine.ANGLE_UNITS_P_KEY, angleUnits.name()); - editor.commit(); + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CalculatorActivity.this); + final SharedPreferences.Editor editor = preferences.edit(); + editor.putString(CalculatorEngine.ANGLE_UNITS_P_KEY, angleUnits.name()); + editor.commit(); - result = true; - } catch (IllegalArgumentException e) { - Log.d(this.getClass().getName(), "Unsupported angle units: " + directionText); + result = true; + } catch (IllegalArgumentException e) { + Log.d(this.getClass().getName(), "Unsupported angle units: " + directionText); + } } + } else if ( dragDirection == DragDirection.left ) { + result = processor.processDragEvent(dragDirection, dragButton, startPoint2d, motionEvent); } } @@ -533,6 +548,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh } calculatorModel = CalculatorModel.instance.init(this, preferences, CalculatorEngine.instance); + calculatorModel.evaluate(); } @Override diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorAdditionalTitle.java b/src/main/java/org/solovyev/android/calculator/CalculatorAdditionalTitle.java new file mode 100644 index 00000000..047c1597 --- /dev/null +++ b/src/main/java/org/solovyev/android/calculator/CalculatorAdditionalTitle.java @@ -0,0 +1,44 @@ +/* + * 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; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.AttributeSet; +import android.widget.TextView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.solovyev.android.calculator.model.CalculatorEngine; + +/** + * User: serso + * Date: 12/10/11 + * Time: 10:34 PM + */ +public class CalculatorAdditionalTitle extends TextView implements SharedPreferences.OnSharedPreferenceChangeListener { + + public CalculatorAdditionalTitle(Context context) { + super(context); + } + + public CalculatorAdditionalTitle(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CalculatorAdditionalTitle(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public void init(@NotNull SharedPreferences preferences) { + onSharedPreferenceChanged(preferences, null); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences preferences, @Nullable String key) { + setText(CalculatorEngine.instance.getNumeralBaseFromPrefs(preferences) + " / " + CalculatorEngine.instance.getAngleUnitsFromPrefs(preferences)); + } +} diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java index 240156ba..325a3114 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java @@ -35,7 +35,7 @@ public class CalculatorDisplay extends AutoResizeTextView { private JsclOperation jsclOperation = JsclOperation.numeric; @NotNull - private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, true, CalculatorEngine.instance.getEngine()); + private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, true, CalculatorEngine.instance.getEngine()); @Nullable private Generic genericResult; diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java b/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java index 63c2c515..56f1fa81 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java @@ -31,7 +31,7 @@ public class CalculatorEditor extends EditText implements SharedPreferences.OnSh private boolean highlightText = true; @NotNull - private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, false, CalculatorEngine.instance.getEngine()); + private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, false, CalculatorEngine.instance.getEngine()); public CalculatorEditor(Context context) { super(context); diff --git a/src/main/java/org/solovyev/android/calculator/TextHighlighter.java b/src/main/java/org/solovyev/android/calculator/TextHighlighter.java index 96c879cd..bdfb54f1 100644 --- a/src/main/java/org/solovyev/android/calculator/TextHighlighter.java +++ b/src/main/java/org/solovyev/android/calculator/TextHighlighter.java @@ -8,18 +8,27 @@ package org.solovyev.android.calculator; import jscl.MathContext; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.model.NumberBuilder; import org.solovyev.android.calculator.model.CalculatorParseException; import org.solovyev.android.calculator.model.TextProcessor; import org.solovyev.common.utils.MutableObject; +import java.util.HashMap; +import java.util.Map; + /** * User: serso * Date: 10/12/11 * Time: 9:47 PM */ -public class TextHighlighter implements TextProcessor { +public class TextHighlighter implements TextProcessor { + + private static final Map nbFontAttributes = new HashMap(); + static { + nbFontAttributes.put("color", "#008000"); + } @NotNull public final MathContext mathContext; @@ -99,6 +108,7 @@ public class TextHighlighter implements TextProcessor { numberBuilder.process(text1, mathType, localNumberOffset); numberOffset += localNumberOffset.getObject(); + final String match = mathType.getMatch(); switch (mathType.getMathType()) { case open_group_symbol: numberOfOpenGroupSymbols++; @@ -110,19 +120,26 @@ public class TextHighlighter implements TextProcessor { text1.append(text.charAt(i)); break; case operator: - text1.append(mathType.getMatch()); - if (mathType.getMatch().length() > 1) { - i += mathType.getMatch().length() - 1; + text1.append(match); + if (match.length() > 1) { + i += match.length() - 1; } break; case function: - i = processHighlightedText(text1, i, mathType.getMatch(), "i"); + i = processHighlightedText(text1, i, match, "i", null); break; case constant: - i = processHighlightedText(text1, i, mathType.getMatch(), "b"); + i = processHighlightedText(text1, i, match, "b", null); + break; + case numeral_base: + i = processHighlightedText(text1, i, match, "font", nbFontAttributes); break; default: - text1.append(text.charAt(i)); + if (mathType.getMathType() == MathType.text || match.length() <= 1) { + text1.append(text.charAt(i)); + } else { + i += match.length() - 1; + } } } @@ -150,10 +167,19 @@ public class TextHighlighter implements TextProcessor { return new Result(result, numberOffset); } - private int processHighlightedText(@NotNull StringBuilder result, int i, @NotNull String functionName, @NotNull String tag) { - result.append("<").append(tag).append(">").append(functionName).append(""); - if (functionName.length() > 1) { - return i + functionName.length() - 1; + private int processHighlightedText(@NotNull StringBuilder result, int i, @NotNull String match, @NotNull String tag, @Nullable Map tagAttributes) { + result.append("<").append(tag); + + if ( tagAttributes != null ) { + for (Map.Entry entry : tagAttributes.entrySet()) { + // attr1="attr1_value" attr2="attr2_value" + result.append(" ").append(entry.getKey()).append("=\"").append(entry.getValue()).append("\""); + } + } + + result.append(">").append(match).append(""); + if (match.length() > 1) { + return i + match.length() - 1; } else { return i; } 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 6ca419a6..be30865c 100644 --- a/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java @@ -6,121 +6,21 @@ package org.solovyev.android.calculator.jscl; -import jscl.text.msg.Messages; +import jscl.math.Generic; 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.CalculatorParseException; import org.solovyev.android.calculator.model.TextProcessor; -import org.solovyev.common.utils.StringUtils; /** * User: serso * Date: 10/6/11 * Time: 9:48 PM */ -class FromJsclNumericTextProcessor implements TextProcessor { +class FromJsclNumericTextProcessor implements TextProcessor { @NotNull @Override - public String process(@NotNull String result) throws CalculatorParseException { - try { - final Double doubleValue = Double.valueOf(result); - - if (doubleValue.isInfinite()) { - result = MathType.INFINITY; - } else { - result = CalculatorEngine.instance.format(doubleValue); - } - } catch (NumberFormatException e) { - result = result.replace(MathType.INFINITY_JSCL, MathType.INFINITY); - try { - result = createResultForComplexNumber(result.replace(MathType.IMAGINARY_NUMBER_JSCL, MathType.IMAGINARY_NUMBER)); - } catch (NumberFormatException e1) { - // throw original one - throw new CalculatorParseException(new jscl.text.ParseException(Messages.msg_8, 0, result, result)); - } - } - - return result; + public String process(@NotNull Generic numeric) throws CalculatorParseException { + return numeric.toString().replace("*", ""); } - - private String format(@NotNull String value) throws java.lang.NumberFormatException { - return CalculatorEngine.instance.format(Double.valueOf(value)); - } - - protected String createResultForComplexNumber(@NotNull final String s) { - final Complex complex = new Complex(); - - final StringBuilder result = new StringBuilder(); - - // may be it's just complex number - int signIndex = tryRealPart(s, complex, result, "+"); - if (signIndex < 0) { - signIndex = tryRealPart(s, complex, result, "-"); - } - - int multiplyIndex = s.indexOf("*"); - if (multiplyIndex >= 0) { - complex.setImaginary(format(s.substring(signIndex >= 0 ? signIndex + 1 : 0, multiplyIndex))); - result.append(complex.getImaginary()); - - } - - result.append(MathType.IMAGINARY_NUMBER); - - return result.toString(); - } - - private int tryRealPart(@NotNull String s, - @NotNull Complex complex, - @NotNull StringBuilder result, - @NotNull String sign) { - int index = s.lastIndexOf(sign); - if (index >= 0) { - final String substring = s.substring(0, index); - - if (!StringUtils.isEmpty(substring)) { - try { - complex.setReal(format(substring)); - result.append(complex.getReal()); - } catch (NumberFormatException e) { - // do nothing - } - } - - result.append(sign); - } - - return index; - } - - private class Complex { - - @Nullable - private String real; - - @Nullable - private String imaginary; - - @Nullable - public String getReal() { - return real; - } - - public void setReal(@Nullable String real) { - this.real = real; - } - - @Nullable - public String getImaginary() { - return imaginary; - } - - public void setImaginary(@Nullable String imaginary) { - this.imaginary = imaginary; - } - } - } diff --git a/src/main/java/org/solovyev/android/calculator/jscl/JsclOperation.java b/src/main/java/org/solovyev/android/calculator/jscl/JsclOperation.java index 3f0487a2..a521b709 100644 --- a/src/main/java/org/solovyev/android/calculator/jscl/JsclOperation.java +++ b/src/main/java/org/solovyev/android/calculator/jscl/JsclOperation.java @@ -60,14 +60,14 @@ public enum JsclOperation { }; @NotNull - private final TextProcessor fromProcessor; + private final TextProcessor fromProcessor; - JsclOperation(@NotNull TextProcessor fromProcessor) { + JsclOperation(@NotNull TextProcessor fromProcessor) { this.fromProcessor = fromProcessor; } @NotNull - public TextProcessor getFromProcessor() { + public TextProcessor getFromProcessor() { return fromProcessor; } 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 4d8dcd24..fe20a4f0 100644 --- a/src/main/java/org/solovyev/android/calculator/math/MathType.java +++ b/src/main/java/org/solovyev/android/calculator/math/MathType.java @@ -5,6 +5,7 @@ package org.solovyev.android.calculator.math; +import jscl.JsclMathEngine; import jscl.NumeralBase; import jscl.math.function.Constant; import org.jetbrains.annotations.NotNull; @@ -336,6 +337,14 @@ public enum MathType { for (MathType mathType : getMathTypesByPriority()) { final String s = CollectionsUtils.find(mathType.getTokens(), startsWithFinder); if (s != null) { + if ( s.length() == 1 ) { + if (JsclMathEngine.instance.getNumeralBase() == NumeralBase.hex) { + final Character ch = s.charAt(0); + if ( NumeralBase.hex.getAcceptableCharacters().contains(ch) ) { + return new Result(MathType.digit, s); + } + } + } return new Result(mathType, s); } } 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 454ea55c..0ae0510d 100644 --- a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java +++ b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java @@ -20,10 +20,7 @@ import org.solovyev.common.msg.MessageRegistry; import org.solovyev.common.utils.MutableObject; import org.solovyev.common.utils.StringUtils; -import java.math.BigDecimal; -import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; -import java.util.Locale; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -38,7 +35,6 @@ public enum CalculatorEngine { instance; public static final String GROUPING_SEPARATOR_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator"; - private static final String GROUPING_SEPARATOR_DEFAULT = " "; public static final String ROUND_RESULT_P_KEY = "org.solovyev.android.calculator.CalculatorModel_round_result"; public static final boolean ROUND_RESULT_DEFAULT = true; @@ -57,15 +53,11 @@ public enum CalculatorEngine { @NotNull private final Object lock = new Object(); - private boolean roundResult = true; - - private int precision = 5; - @NotNull private MathEngine engine = JsclMathEngine.instance; @NotNull - public final TextProcessor preprocessor = new ToJsclTextProcessor(); + public final TextProcessor preprocessor = new ToJsclTextProcessor(); @NotNull private final AndroidVarsRegistry varsRegister = new AndroidVarsRegistryImpl(engine.getConstantsRegistry()); @@ -78,46 +70,20 @@ public enum CalculatorEngine { private final AndroidMathRegistry postfixFunctionsRegistry = new AndroidPostfixFunctionsRegistry(engine.getPostfixFunctionsRegistry()); - @NotNull - private DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(Locale.getDefault()); - - { - decimalGroupSymbols.setDecimalSeparator('.'); - decimalGroupSymbols.setGroupingSeparator(GROUPING_SEPARATOR_DEFAULT.charAt(0)); - } - - private boolean useGroupingSeparator = true; - @NotNull private ThreadKiller threadKiller = new AndroidThreadKiller(); // calculation thread timeout in milliseconds, after timeout thread would be interrupted private int timeout = DEFAULT_TIMEOUT; - @NotNull - public String format(@NotNull Double value) { - return format(value, true); + CalculatorEngine() { + this.engine.setRoundResult(true); + this.engine.setUseGroupingSeparator(true); } @NotNull public String format(@NotNull Double value, boolean round) { - if (!value.isInfinite() && !value.isNaN()) { - final DecimalFormat df = new DecimalFormat(); - df.setDecimalFormatSymbols(decimalGroupSymbols); - df.setGroupingUsed(useGroupingSeparator); - if (round) { - if (isRoundResult()) { - df.setMaximumFractionDigits(instance.getPrecision()); - return df.format(new BigDecimal(value).setScale(instance.getPrecision(), BigDecimal.ROUND_HALF_UP).doubleValue()); - } else { - return String.valueOf(value); - } - } else { - return df.format(value); - } - } else { - return String.valueOf(value); - } + return getEngine().format(value, round); } public static class Result { @@ -267,24 +233,16 @@ public enum CalculatorEngine { final Generic genericResult = calculationResult.getObject(); - return new Result(operation.getFromProcessor().process(genericResult.toString()), operation, genericResult); + return new Result(operation.getFromProcessor().process(genericResult), operation, genericResult); } } - private int getPrecision() { - return precision; - } - public void setPrecision(int precision) { - this.precision = precision; - } - - private boolean isRoundResult() { - return roundResult; + this.getEngine().setPrecision(precision); } public void setRoundResult(boolean roundResult) { - this.roundResult = roundResult; + this.getEngine().setRoundResult(roundResult); } public void init(@Nullable Context context, @Nullable SharedPreferences preferences) { @@ -300,15 +258,15 @@ public enum CalculatorEngine { //noinspection ConstantConditions this.setPrecision(integerNumberMapper.parseValue(preferences.getString(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT))); this.setRoundResult(preferences.getBoolean(ROUND_RESULT_P_KEY, ROUND_RESULT_DEFAULT)); - this.setAngleUnits(AngleUnit.valueOf(preferences.getString(ANGLE_UNITS_P_KEY, ANGLE_UNITS_DEFAULT))); - this.setNumeralBase(NumeralBase.valueOf(preferences.getString(NUMERAL_BASES_P_KEY, NUMERAL_BASES_DEFAULT))); + this.setAngleUnits(getAngleUnitsFromPrefs(preferences)); + this.setNumeralBase(getNumeralBaseFromPrefs(preferences)); - final String groupingSeparator = preferences.getString(GROUPING_SEPARATOR_P_KEY, GROUPING_SEPARATOR_DEFAULT); + final String groupingSeparator = preferences.getString(GROUPING_SEPARATOR_P_KEY, JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); if (StringUtils.isEmpty(groupingSeparator)) { - this.useGroupingSeparator = false; + this.getEngine().setUseGroupingSeparator(false); } else { - this.useGroupingSeparator = true; - this.decimalGroupSymbols.setGroupingSeparator(groupingSeparator.charAt(0)); + this.getEngine().setUseGroupingSeparator(true); + this.getEngine().setGroupingSeparator(groupingSeparator.charAt(0)); } } @@ -316,10 +274,20 @@ public enum CalculatorEngine { } } + @NotNull + public NumeralBase getNumeralBaseFromPrefs(@NotNull SharedPreferences preferences) { + return NumeralBase.valueOf(preferences.getString(NUMERAL_BASES_P_KEY, NUMERAL_BASES_DEFAULT)); + } + + @NotNull + public AngleUnit getAngleUnitsFromPrefs(@NotNull SharedPreferences preferences) { + return AngleUnit.valueOf(preferences.getString(ANGLE_UNITS_P_KEY, ANGLE_UNITS_DEFAULT)); + } + //for tests only void setDecimalGroupSymbols(@NotNull DecimalFormatSymbols decimalGroupSymbols) { synchronized (lock) { - this.decimalGroupSymbols = decimalGroupSymbols; + this.getEngine().setDecimalGroupSymbols(decimalGroupSymbols); } } 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 d7859404..19cbc293 100644 --- a/src/main/java/org/solovyev/android/calculator/model/DummyTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/DummyTextProcessor.java @@ -6,6 +6,7 @@ package org.solovyev.android.calculator.model; +import jscl.math.Generic; import org.jetbrains.annotations.NotNull; /** @@ -13,13 +14,13 @@ import org.jetbrains.annotations.NotNull; * Date: 10/18/11 * Time: 10:39 PM */ -public enum DummyTextProcessor implements TextProcessor { +public enum DummyTextProcessor implements TextProcessor { instance; @NotNull @Override - public String process(@NotNull String s) throws CalculatorParseException { - return s; + public String process(@NotNull Generic s) throws CalculatorParseException { + return s.toString(); } } 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 2222324c..930c8364 100644 --- a/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java @@ -1,6 +1,7 @@ package org.solovyev.android.calculator.model; import jscl.MathContext; +import jscl.math.Generic; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.math.MathType; @@ -13,7 +14,7 @@ import java.util.List; * Date: 10/20/11 * Time: 2:59 PM */ -public class FromJsclSimplifyTextProcessor implements TextProcessor { +public class FromJsclSimplifyTextProcessor implements TextProcessor { @NotNull private final MathContext mathContext; @@ -24,7 +25,12 @@ public class FromJsclSimplifyTextProcessor implements TextProcessor { @NotNull @Override - public String process(@NotNull String s) throws CalculatorParseException { + public String process(@NotNull Generic from) throws CalculatorParseException { + final String s = from.toString(); + return process(s); + } + + public String process(@NotNull String s) { final StringBuilder sb = new StringBuilder(); final NumberBuilder numberBuilder = new NumberBuilder(true, mathContext.getNumeralBase()); diff --git a/src/main/java/org/solovyev/android/calculator/model/NumberBuilder.java b/src/main/java/org/solovyev/android/calculator/model/NumberBuilder.java index 96072790..7042622a 100644 --- a/src/main/java/org/solovyev/android/calculator/model/NumberBuilder.java +++ b/src/main/java/org/solovyev/android/calculator/model/NumberBuilder.java @@ -49,7 +49,7 @@ public class NumberBuilder { final MathType.Result possibleResult; if ((CollectionsUtils.contains(mathTypeResult.getMathType(), MathType.digit, MathType.numeral_base, MathType.dot, MathType.grouping_separator, MathType.power_10) || - isSignAfterE(mathTypeResult)) && numeralBaseCheck(mathTypeResult)) { + isSignAfterE(mathTypeResult)) && numeralBaseCheck(mathTypeResult) && numeralBaseInTheStart(mathTypeResult.getMathType())) { if (numberBuilder == null) { numberBuilder = new StringBuilder(); } @@ -68,6 +68,10 @@ public class NumberBuilder { return possibleResult == null ? mathTypeResult : possibleResult; } + private boolean numeralBaseInTheStart(@NotNull MathType mathType) { + return mathType != MathType.numeral_base || numberBuilder == null; + } + private boolean numeralBaseCheck( @NotNull MathType.Result mathType ) { if ( mathType.getMathType() == MathType.digit ) { final Character ch = mathType.getMatch().charAt(0); 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 5134d988..48b3b1a3 100644 --- a/src/main/java/org/solovyev/android/calculator/model/TextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/TextProcessor.java @@ -7,8 +7,8 @@ import org.jetbrains.annotations.NotNull; * Date: 9/26/11 * Time: 12:12 PM */ -public interface TextProcessor { +public interface TextProcessor { @NotNull - T process(@NotNull String s) throws CalculatorParseException; + TO process(@NotNull FROM from) 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 2769ee54..f434cbb1 100644 --- a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java @@ -15,7 +15,7 @@ import org.solovyev.common.utils.CollectionsUtils; import java.util.ArrayList; import java.util.List; -class ToJsclTextProcessor implements TextProcessor { +class ToJsclTextProcessor implements TextProcessor { @NotNull private static final Integer MAX_DEPTH = 20; 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 830f2b8a..21b1061d 100644 --- a/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java +++ b/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java @@ -120,7 +120,18 @@ public class DirectionDragButton extends DragButton { @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!"); + final Point2d result = new Point2d(); + + float width = paint.measureText(" "); + result.setX(width); + + float selfHeight = paint.ascent() + paint.descent(); + + basePaint.measureText(StringUtils.getNotEmpty(baseText, "|")); + + result.setY(h / 2 - selfHeight / 2); + + return result; } }/*, right(DragDirection.right) { @@ -163,9 +174,9 @@ public class DirectionDragButton extends DragButton { } @Nullable - public static GuiDragDirection valueOf ( @NotNull DragDirection dragDirection ) { + public static GuiDragDirection valueOf(@NotNull DragDirection dragDirection) { for (GuiDragDirection guiDragDirection : values()) { - if ( guiDragDirection.dragDirection == dragDirection ) { + if (guiDragDirection.dragDirection == dragDirection) { return guiDragDirection; } } @@ -204,7 +215,7 @@ public class DirectionDragButton extends DragButton { default: // try drag direction text for (GuiDragDirection guiDragDirection : GuiDragDirection.values()) { - if ( guiDragDirection.getAttributeId() == attr ) { + if (guiDragDirection.getAttributeId() == attr) { this.directionTextDataMap.put(guiDragDirection, new DirectionTextData(guiDragDirection, attrValue)); break; } diff --git a/src/main/java/org/solovyev/android/view/widgets/SimpleOnDragListener.java b/src/main/java/org/solovyev/android/view/widgets/SimpleOnDragListener.java index 5d8c0eee..1e4938c5 100644 --- a/src/main/java/org/solovyev/android/view/widgets/SimpleOnDragListener.java +++ b/src/main/java/org/solovyev/android/view/widgets/SimpleOnDragListener.java @@ -62,6 +62,7 @@ public class SimpleOnDragListener implements OnDragListener, DragPreferencesChan DragDirection direction = null; for (Map.Entry directionEntry : distancePreferences.getDirectionPreferences().entrySet()) { + Log.d(String.valueOf(dragButton.getId()), "Drag direction: " + directionEntry.getKey()); Log.d(String.valueOf(dragButton.getId()), "Trying direction interval: " + directionEntry.getValue().getInterval()); if (isInInterval(directionEntry.getValue().getInterval(), distance)) { @@ -180,7 +181,7 @@ public class SimpleOnDragListener implements OnDragListener, DragPreferencesChan transformInterval(preferenceType, dragDirection, intervalPref); - Log.d(SimpleOnDragListener.class.getName(), "Preference loaded. Id: " + preferenceId + ", value: " + intervalPref.toString()); + Log.d(SimpleOnDragListener.class.getName(), "Preference loaded for " + dragDirection +". Id: " + preferenceId + ", value: " + intervalPref.toString()); final DragPreference directionPreference = new DragPreference(dragDirection, intervalPref); @@ -207,9 +208,12 @@ public class SimpleOnDragListener implements OnDragListener, DragPreferencesChan if (dragDirection == DragDirection.up) { interval.setLeftBorder(180f - rightBorder); interval.setRightBorder(180f - leftBorder); - } else if (dragDirection == DragDirection.left || dragDirection == DragDirection.right) { + } else if (dragDirection == DragDirection.left ) { interval.setLeftBorder(90f - rightBorder / 2); - interval.setRightBorder(90f + leftBorder / 2); + interval.setRightBorder(90f + rightBorder / 2); + } else if ( dragDirection == DragDirection.right ) { + interval.setLeftBorder(180f + 90f - rightBorder / 2); + interval.setRightBorder(180f + 90f + rightBorder / 2); } } diff --git a/src/test/java/org/solovyev/android/calculator/TextHighlighterTest.java b/src/test/java/org/solovyev/android/calculator/TextHighlighterTest.java index b1d609ee..a9435605 100644 --- a/src/test/java/org/solovyev/android/calculator/TextHighlighterTest.java +++ b/src/test/java/org/solovyev/android/calculator/TextHighlighterTest.java @@ -48,6 +48,11 @@ public class TextHighlighterTest { textHighlighter = new TextHighlighter(0, false, JsclMathEngine.instance); Assert.assertEquals("0.1E3", textHighlighter.process("0.1E3").toString()); Assert.assertEquals("1E3", textHighlighter.process("1E3").toString()); + Assert.assertEquals("20x:", textHighlighter.process("20x:").toString()); + Assert.assertEquals("20x", textHighlighter.process("20x").toString()); + Assert.assertEquals("22x", textHighlighter.process("22x").toString()); + Assert.assertEquals("20t", textHighlighter.process("20t").toString()); + Assert.assertEquals("20k", textHighlighter.process("20k").toString()); Assert.assertEquals("1 000 000E3", textHighlighter.process("1000000E3").toString()); Assert.assertEquals("-1 000 000E3", textHighlighter.process("-1000000E3").toString()); Assert.assertEquals("-1 000 000E-3", textHighlighter.process("-1000000E-3").toString()); diff --git a/src/test/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessorTest.java b/src/test/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessorTest.java index 61840a50..c2bbf2d7 100644 --- a/src/test/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessorTest.java +++ b/src/test/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessorTest.java @@ -6,8 +6,12 @@ package org.solovyev.android.calculator.jscl; +import jscl.math.Expression; +import jscl.math.Generic; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; +import org.solovyev.android.calculator.model.CalculatorEngine; /** * User: serso @@ -16,13 +20,20 @@ import org.junit.Test; */ public class FromJsclNumericTextProcessorTest { + @BeforeClass + public static void setUp() throws Exception { + CalculatorEngine.instance.init(null, null); + } + @Test public void testCreateResultForComplexNumber() throws Exception { final FromJsclNumericTextProcessor cm = new FromJsclNumericTextProcessor(); - Assert.assertEquals("1.22133+23 123i", cm.createResultForComplexNumber("1.22133232+23123*i")); - Assert.assertEquals("1.22133+1.2i", cm.createResultForComplexNumber("1.22133232+1.2*i")); - Assert.assertEquals("1.22i", cm.createResultForComplexNumber("1.22*i")); - Assert.assertEquals("i", cm.createResultForComplexNumber("i")); + Assert.assertEquals("1.22133+23 123i", cm.process(Expression.valueOf("1.22133232+23123*i").numeric())); + Assert.assertEquals("1.22133+1.2i", cm.process(Expression.valueOf("1.22133232+1.2*i").numeric())); + Assert.assertEquals("1.22i", cm.process(Expression.valueOf("1.22*i").numeric())); + Assert.assertEquals("i", cm.process(Expression.valueOf("i").numeric())); + Generic numeric = Expression.valueOf("e^(π*i)+1").numeric(); + junit.framework.Assert.assertEquals("0i", cm.process(numeric)); } } 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 bb294452..92d8009f 100644 --- a/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java +++ b/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java @@ -132,8 +132,8 @@ public class CalculatorEngineTest { junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "(2.0+2.0)!").getResult()); junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "4.0!").getResult()); junit.framework.Assert.assertEquals("720", cm.evaluate(JsclOperation.numeric, "3!!").getResult()); - junit.framework.Assert.assertEquals("36.0", Expression.valueOf("3!^2").numeric().toString()); - junit.framework.Assert.assertEquals("3.0", Expression.valueOf("cubic(27)").numeric().toString()); + junit.framework.Assert.assertEquals("36", Expression.valueOf("3!^2").numeric().toString()); + junit.framework.Assert.assertEquals("3", Expression.valueOf("cubic(27)").numeric().toString()); try { junit.framework.Assert.assertEquals("√(-1)!", cm.evaluate(JsclOperation.numeric, "i!").getResult()); fail(); @@ -369,8 +369,12 @@ public class CalculatorEngineTest { } catch (CalculatorEvalException e) { // ok } + + cm.getEngine().setNumeralBase(NumeralBase.hex); + Assert.assertEquals("637b", cm.evaluate(JsclOperation.numeric, "56ce+cad").getResult()); } finally { cm.setNumeralBase(defaultNumeralBase); } } + } diff --git a/src/test/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessorTest.java b/src/test/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessorTest.java index a0f05808..b0066679 100644 --- a/src/test/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessorTest.java +++ b/src/test/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessorTest.java @@ -62,6 +62,11 @@ public class FromJsclSimplifyTextProcessorTest { Assert.assertEquals("tlog(3)", tp.process("t*log(3)")); Assert.assertEquals("t√(3)", tp.process("t*√(3)")); + Assert.assertEquals("20x", tp.process("20*x")); + Assert.assertEquals("20x", tp.process("20x")); + Assert.assertEquals("2×0x3", tp.process("2*0x3")); + Assert.assertEquals("2×0x:3", tp.process("2*0x:3")); + Assert.assertEquals("0x:3 000 000", tp.process("0x:3 000 000.00000000000001")); } } 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 92c472ba..3f023dac 100644 --- a/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java +++ b/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java @@ -6,6 +6,8 @@ package org.solovyev.android.calculator.model; +import jscl.JsclMathEngine; +import jscl.NumeralBase; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -120,4 +122,20 @@ public class ToJsclTextProcessorTest { @Test public void testPostfixFunction() throws Exception { } + + @Test + public void testNumeralBases() throws Exception { + final ToJsclTextProcessor processor = new ToJsclTextProcessor(); + + final NumeralBase defaultNumeralBase = JsclMathEngine.instance.getNumeralBase(); + try{ + JsclMathEngine.instance.setNumeralBase(NumeralBase.bin); + Assert.assertEquals("101", JsclMathEngine.instance.evaluate("10+11")); + + JsclMathEngine.instance.setNumeralBase(NumeralBase.hex); + Assert.assertEquals("56ce+cad", processor.process("56ce+cad").getExpression()); + } finally { + JsclMathEngine.instance.setNumeralBase(defaultNumeralBase); + } + } }