changes
This commit is contained in:
parent
d888d2dd47
commit
a49524be9f
@ -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"
|
||||
|
||||
|
@ -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"/>
|
@ -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"/>
|
@ -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"
|
||||
|
@ -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"/>
|
@ -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"
|
||||
|
||||
|
@ -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"/>
|
@ -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"/>
|
30
res/layout/calc_title.xml
Normal file
30
res/layout/calc_title.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
~ 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
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
a:orientation="horizontal"
|
||||
a:gravity="center_vertical"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="fill_parent">
|
||||
|
||||
<TextView
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_gravity="left"
|
||||
style="@style/WindowTitle"
|
||||
a:text="@string/c_app_name"/>
|
||||
|
||||
<org.solovyev.android.calculator.CalculatorAdditionalTitle
|
||||
a:id="@+id/additional_title_text"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
style="@style/WindowTitle"
|
||||
a:gravity="center_vertical|right"
|
||||
a:layout_gravity="right"/>
|
||||
|
||||
</LinearLayout>
|
@ -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"/>
|
@ -8,8 +8,10 @@
|
||||
<resources>
|
||||
<string name="p_drag_distance_key">org.solovyev.android.calculator.DragButtonCalibrationActivity_distance</string>
|
||||
<string name="p_drag_distance">15;350</string>
|
||||
|
||||
<string name="p_drag_angle_key">org.solovyev.android.calculator.DragButtonCalibrationActivity_angle</string>
|
||||
<string name="p_drag_angle">0;45</string>
|
||||
|
||||
<string name="p_drag_duration_key">org.solovyev.android.calculator.DragButtonCalibrationActivity_duration</string>
|
||||
<string name="p_drag_duration">40;2500</string>
|
||||
|
||||
|
@ -6,6 +6,20 @@
|
||||
|
||||
<resources>
|
||||
|
||||
<style name="WindowTitle">
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:textAppearance">@style/TextAppearance_WindowTitle</item>
|
||||
<item name="android:shadowColor">#BB000000</item>
|
||||
<item name="android:shadowRadius">2.75</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance_WindowTitle">
|
||||
<item name="android:textColor">#fff</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="default_text_size">
|
||||
<item name="android:textSize">20dp</item>
|
||||
</style>
|
||||
|
@ -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,
|
||||
@ -145,6 +156,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
|
||||
boolean result = false;
|
||||
|
||||
if (dragButton instanceof AngleUnitsButton) {
|
||||
if (dragDirection == DragDirection.up || dragDirection == DragDirection.down ) {
|
||||
final String directionText = ((AngleUnitsButton) dragButton).getText(dragDirection);
|
||||
if ( directionText != null ) {
|
||||
try {
|
||||
@ -161,6 +173,9 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
|
||||
Log.d(this.getClass().getName(), "Unsupported angle units: " + directionText);
|
||||
}
|
||||
}
|
||||
} else if ( dragDirection == DragDirection.left ) {
|
||||
result = processor.processDragEvent(dragDirection, dragButton, startPoint2d, motionEvent);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -533,6 +548,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
|
||||
}
|
||||
|
||||
calculatorModel = CalculatorModel.instance.init(this, preferences, CalculatorEngine.instance);
|
||||
calculatorModel.evaluate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ public class CalculatorDisplay extends AutoResizeTextView {
|
||||
private JsclOperation jsclOperation = JsclOperation.numeric;
|
||||
|
||||
@NotNull
|
||||
private final static TextProcessor<TextHighlighter.Result> textHighlighter = new TextHighlighter(Color.WHITE, true, CalculatorEngine.instance.getEngine());
|
||||
private final static TextProcessor<TextHighlighter.Result, String> textHighlighter = new TextHighlighter(Color.WHITE, true, CalculatorEngine.instance.getEngine());
|
||||
|
||||
@Nullable
|
||||
private Generic genericResult;
|
||||
|
@ -31,7 +31,7 @@ public class CalculatorEditor extends EditText implements SharedPreferences.OnSh
|
||||
private boolean highlightText = true;
|
||||
|
||||
@NotNull
|
||||
private final static TextProcessor<TextHighlighter.Result> textHighlighter = new TextHighlighter(Color.WHITE, false, CalculatorEngine.instance.getEngine());
|
||||
private final static TextProcessor<TextHighlighter.Result, String> textHighlighter = new TextHighlighter(Color.WHITE, false, CalculatorEngine.instance.getEngine());
|
||||
|
||||
public CalculatorEditor(Context context) {
|
||||
super(context);
|
||||
|
@ -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<TextHighlighter.Result> {
|
||||
public class TextHighlighter implements TextProcessor<TextHighlighter.Result, String> {
|
||||
|
||||
private static final Map<String, String> nbFontAttributes = new HashMap<String, String>();
|
||||
static {
|
||||
nbFontAttributes.put("color", "#008000");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final MathContext mathContext;
|
||||
@ -99,6 +108,7 @@ public class TextHighlighter implements TextProcessor<TextHighlighter.Result> {
|
||||
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<TextHighlighter.Result> {
|
||||
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:
|
||||
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<TextHighlighter.Result> {
|
||||
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("</").append(tag).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<String, String> tagAttributes) {
|
||||
result.append("<").append(tag);
|
||||
|
||||
if ( tagAttributes != null ) {
|
||||
for (Map.Entry<String, String> entry : tagAttributes.entrySet()) {
|
||||
// attr1="attr1_value" attr2="attr2_value"
|
||||
result.append(" ").append(entry.getKey()).append("=\"").append(entry.getValue()).append("\"");
|
||||
}
|
||||
}
|
||||
|
||||
result.append(">").append(match).append("</").append(tag).append(">");
|
||||
if (match.length() > 1) {
|
||||
return i + match.length() - 1;
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
|
@ -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<String> {
|
||||
class FromJsclNumericTextProcessor implements TextProcessor<String, Generic> {
|
||||
|
||||
@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));
|
||||
public String process(@NotNull Generic numeric) throws CalculatorParseException {
|
||||
return numeric.toString().replace("*", "");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -60,14 +60,14 @@ public enum JsclOperation {
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private final TextProcessor<String> fromProcessor;
|
||||
private final TextProcessor<String, Generic> fromProcessor;
|
||||
|
||||
JsclOperation(@NotNull TextProcessor<String> fromProcessor) {
|
||||
JsclOperation(@NotNull TextProcessor<String, Generic> fromProcessor) {
|
||||
this.fromProcessor = fromProcessor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TextProcessor<String> getFromProcessor() {
|
||||
public TextProcessor<String, Generic> getFromProcessor() {
|
||||
return fromProcessor;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<PreparedExpression> preprocessor = new ToJsclTextProcessor();
|
||||
public final TextProcessor<PreparedExpression, String> preprocessor = new ToJsclTextProcessor();
|
||||
|
||||
@NotNull
|
||||
private final AndroidVarsRegistry varsRegister = new AndroidVarsRegistryImpl(engine.getConstantsRegistry());
|
||||
@ -78,46 +70,20 @@ public enum CalculatorEngine {
|
||||
|
||||
private final AndroidMathRegistry<Operator> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<String> {
|
||||
public enum DummyTextProcessor implements TextProcessor<String, Generic> {
|
||||
|
||||
instance;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String process(@NotNull String s) throws CalculatorParseException {
|
||||
return s;
|
||||
public String process(@NotNull Generic s) throws CalculatorParseException {
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
|
@ -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<String> {
|
||||
public class FromJsclSimplifyTextProcessor implements TextProcessor<String, Generic> {
|
||||
|
||||
@NotNull
|
||||
private final MathContext mathContext;
|
||||
@ -24,7 +25,12 @@ public class FromJsclSimplifyTextProcessor implements TextProcessor<String> {
|
||||
|
||||
@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());
|
||||
|
@ -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);
|
||||
|
@ -7,8 +7,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Date: 9/26/11
|
||||
* Time: 12:12 PM
|
||||
*/
|
||||
public interface TextProcessor<T extends CharSequence> {
|
||||
public interface TextProcessor<TO extends CharSequence, FROM> {
|
||||
|
||||
@NotNull
|
||||
T process(@NotNull String s) throws CalculatorParseException;
|
||||
TO process(@NotNull FROM from) throws CalculatorParseException;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import org.solovyev.common.utils.CollectionsUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
|
||||
class ToJsclTextProcessor implements TextProcessor<PreparedExpression, String> {
|
||||
|
||||
@NotNull
|
||||
private static final Integer MAX_DEPTH = 20;
|
||||
|
@ -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) {
|
||||
|
@ -62,6 +62,7 @@ public class SimpleOnDragListener implements OnDragListener, DragPreferencesChan
|
||||
DragDirection direction = null;
|
||||
for (Map.Entry<DragDirection, DragPreference> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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("2<font color=\"#008000\">0x:</font>", 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());
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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"));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user