refactor + russian language support
This commit is contained in:
parent
6b120465b5
commit
647eb27004
BIN
res/drawable/paste.png
Normal file
BIN
res/drawable/paste.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
@ -100,8 +100,8 @@
|
|||||||
style="@style/control_button_style"
|
style="@style/control_button_style"
|
||||||
a:onClick="numericButtonClickHandler"/>
|
a:onClick="numericButtonClickHandler"/>
|
||||||
|
|
||||||
<org.solovyev.android.view.widgets.DirectionDragButton a:id="@+id/pasteButton"
|
<ImageButton a:id="@+id/pasteButton"
|
||||||
a:text="@string/c_paste"
|
a:src="@drawable/paste"
|
||||||
style="@style/control_button_style"
|
style="@style/control_button_style"
|
||||||
a:onClick="pasteButtonClickHandler"/>
|
a:onClick="pasteButtonClickHandler"/>
|
||||||
|
|
||||||
@ -185,7 +185,8 @@
|
|||||||
|
|
||||||
<org.solovyev.android.view.widgets.DirectionDragButton
|
<org.solovyev.android.view.widgets.DirectionDragButton
|
||||||
a:id="@+id/varsButton"
|
a:id="@+id/varsButton"
|
||||||
a:text="@string/c_vars"
|
a:text="π,e,…"
|
||||||
|
a:textStyle="italic"
|
||||||
a:onClick="varsButtonClickHandler"
|
a:onClick="varsButtonClickHandler"
|
||||||
style="@style/control_button_style"/>
|
style="@style/control_button_style"/>
|
||||||
|
|
||||||
|
@ -130,8 +130,8 @@
|
|||||||
style="@style/digit_button_style"
|
style="@style/digit_button_style"
|
||||||
a:onClick="digitButtonClickHandler"/>
|
a:onClick="digitButtonClickHandler"/>
|
||||||
|
|
||||||
<org.solovyev.android.view.widgets.DirectionDragButton a:id="@+id/pasteButton"
|
<ImageButton a:id="@+id/pasteButton"
|
||||||
a:text="@string/c_paste"
|
a:src="@drawable/paste"
|
||||||
style="@style/control_button_style"
|
style="@style/control_button_style"
|
||||||
a:onClick="pasteButtonClickHandler"/>
|
a:onClick="pasteButtonClickHandler"/>
|
||||||
|
|
||||||
@ -198,7 +198,8 @@
|
|||||||
|
|
||||||
<org.solovyev.android.view.widgets.DirectionDragButton
|
<org.solovyev.android.view.widgets.DirectionDragButton
|
||||||
a:id="@+id/varsButton"
|
a:id="@+id/varsButton"
|
||||||
a:text="@string/c_vars"
|
a:text="π,e,…"
|
||||||
|
a:textStyle="italic"
|
||||||
a:onClick="varsButtonClickHandler"
|
a:onClick="varsButtonClickHandler"
|
||||||
style="@style/control_button_style"/>
|
style="@style/control_button_style"/>
|
||||||
|
|
||||||
|
@ -1,4 +1,58 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="c_app_name">Калькулятор</string>
|
<string name="c_app_name">Калькулятор</string>
|
||||||
|
<string name="c_app_settings">Калькулятор</string>
|
||||||
|
<string name="c_syntax_error">Ошибка</string>
|
||||||
|
<string name="c_result_copied">Результат скопирован в буфер!</string>
|
||||||
|
<string name="c_settings">Настройки</string>
|
||||||
|
<string name="c_help">Помощь</string>
|
||||||
|
<string name="c_about">О программе</string>
|
||||||
|
<string name="c_vars_and_constants">Переменные и константы</string>
|
||||||
|
|
||||||
|
<!--PREFERENCE ACTIVITY-->
|
||||||
|
<string name="c_prefs_main_category">Основные настройки</string>
|
||||||
|
<string name="c_prefs_drag_button_category">Настройки кнопок</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="c_down">Вниз</string>
|
||||||
|
<string name="c_up">Вверх</string>
|
||||||
|
<string name="c_restart">Перезапуск</string>
|
||||||
|
|
||||||
|
<!--ABOUT ACTIVITY-->
|
||||||
|
<string name="c_copyright">Copyright (c) 2009-2011.\nПрограмма создана serso aka se.solovyev.\n
|
||||||
|
За подробной информацией, пожалуйста,\nобращайтесь на почту\n<a href="mailto:se.solovyev@gmail.com">se.solovyev@gmail.com</a>
|
||||||
|
\nили посетите\n<a href="http://se.solovyev.org">http://se.solovyev.org</a>
|
||||||
|
</string>
|
||||||
|
|
||||||
|
<string name="c_undo">назад</string>
|
||||||
|
<string name="c_redo">вперёд</string>
|
||||||
|
<string name="c_paste">вставить</string>
|
||||||
|
<string name="c_vars">переменные</string>
|
||||||
|
|
||||||
|
<string name="c_calc_color_display_title">Подсветка выражений</string>
|
||||||
|
<string name="p_calc_result_precision_title">Точность результата</string>
|
||||||
|
<string name="c_exit">Выход</string>
|
||||||
|
<string name="c_add">Добавить</string>
|
||||||
|
<string name="c_cancel">Отмена</string>
|
||||||
|
<string name="c_save">Сохранить</string>
|
||||||
|
<string name="c_remove">Удалить</string>
|
||||||
|
<string name="c_yes">Да</string>
|
||||||
|
<string name="c_no">Нет</string>
|
||||||
|
<string name="c_var_removal_confirmation">Подтверждение удаления</string>
|
||||||
|
<string name="c_var_removal_confirmation_question">Вы действительно хотите удалить переменную \'%s\'?</string>
|
||||||
|
<string name="c_var_name">Имя</string>
|
||||||
|
<string name="c_var_value">Значение</string>
|
||||||
|
<string name="c_var_description">Описание</string>
|
||||||
|
<string name="c_var_create_var">Создать переменную</string>
|
||||||
|
<string name="c_var_edit_var">Редактировать переменную</string>
|
||||||
|
|
||||||
|
<string name="c_value.is.not.a.number">Значение - не число!</string>
|
||||||
|
<string name="c_var.name.clashes">Имя переменной не может быть зарезервированным системным именем!</string>
|
||||||
|
<string name="c_var.already.exists">Переменная с таким именем уже существует!</string>
|
||||||
|
<string name="c_name.is.empty">Имя не может быть пустым!</string>
|
||||||
|
<string name="c_sys.var.cannot.be.changed">Системная переменная не может быть изменена!</string>
|
||||||
|
|
||||||
|
<string name="c_pi_description">Отношение длины окружности к диаметру</string>
|
||||||
|
<string name="c_e_description">Вещесвтенное число, такое что производная функции f(x) = e^x в точке x = 0 равно 1</string>
|
||||||
|
<string name="c_i_description">Мнимая единица, определённая как i^2 = −1</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<string name="c_undo">undo</string>
|
<string name="c_undo">undo</string>
|
||||||
<string name="c_redo">redo</string>
|
<string name="c_redo">redo</string>
|
||||||
<string name="c_clear">clear</string>
|
<string name="c_clear">clr</string>
|
||||||
<string name="c_paste">paste</string>
|
<string name="c_paste">paste</string>
|
||||||
<string name="c_vars">vars</string>
|
<string name="c_vars">vars</string>
|
||||||
|
|
||||||
@ -47,4 +47,14 @@
|
|||||||
<string name="c_var_description">Description</string>
|
<string name="c_var_description">Description</string>
|
||||||
<string name="c_var_create_var">Create variable</string>
|
<string name="c_var_create_var">Create variable</string>
|
||||||
<string name="c_var_edit_var">Edit variable</string>
|
<string name="c_var_edit_var">Edit variable</string>
|
||||||
|
|
||||||
|
<string name="c_value.is.not.a.number">Value is not a number!</string>
|
||||||
|
<string name="c_var.name.clashes">Variable name clashes with function name!</string>
|
||||||
|
<string name="c_var.already.exists">Variable with same name already exists!</string>
|
||||||
|
<string name="c_name.is.empty">Name is empty!</string>
|
||||||
|
<string name="c_sys.var.cannot.be.changed">System variable cannot be changed!</string>
|
||||||
|
|
||||||
|
<string name="c_pi_description">Ratio of any circle\'s circumference to its diameter</string>
|
||||||
|
<string name="c_e_description">Unique real number such that the value of the derivative (slope of the tangent line) of the function f(x) = e^x at the point x = 0 is equal to 1</string>
|
||||||
|
<string name="c_i_description">Imaginary unit, defined such that i^2 = −1</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:range="http://schemas.android.com/apk/res/org.solovyev.android.calculator">
|
xmlns:range="http://schemas.android.com/apk/res/org.solovyev.android.calculator">
|
||||||
<PreferenceCategory a:title="@string/c_prefs_drag_button_category">
|
<PreferenceCategory a:title="@string/c_prefs_main_category">
|
||||||
|
|
||||||
<org.solovyev.android.view.prefs.NumberPickerDialogPreference
|
<org.solovyev.android.view.prefs.NumberPickerDialogPreference
|
||||||
a:key="@string/p_calc_result_precision_key"
|
a:key="@string/p_calc_result_precision_key"
|
||||||
|
@ -18,6 +18,7 @@ import android.widget.TextView;
|
|||||||
import bsh.EvalError;
|
import bsh.EvalError;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.android.calculator.model.CalculatorModel;
|
||||||
import org.solovyev.android.view.FontSizeAdjuster;
|
import org.solovyev.android.view.FontSizeAdjuster;
|
||||||
import org.solovyev.android.view.widgets.*;
|
import org.solovyev.android.view.widgets.*;
|
||||||
import org.solovyev.common.BooleanMapper;
|
import org.solovyev.common.BooleanMapper;
|
||||||
@ -41,9 +42,6 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
|
|||||||
@NotNull
|
@NotNull
|
||||||
private CalculatorView calculatorView;
|
private CalculatorView calculatorView;
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private CalculatorModel calculatorModel;
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private BroadcastReceiver insertTextReceiver;
|
private BroadcastReceiver insertTextReceiver;
|
||||||
|
|
||||||
@ -125,16 +123,13 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
|
|||||||
private synchronized void firstTimeInit() {
|
private synchronized void firstTimeInit() {
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
try {
|
try {
|
||||||
if (!CalculatorModel.isLoaded()) {
|
CalculatorModel.instance.init(this);
|
||||||
CalculatorModel.init(this);
|
|
||||||
}
|
|
||||||
this.calculatorModel = CalculatorModel.getInstance();
|
|
||||||
} catch (EvalError evalError) {
|
} catch (EvalError evalError) {
|
||||||
// todo serso: create serso runtime exception
|
// todo serso: create serso runtime exception
|
||||||
throw new RuntimeException("Could not initialize interpreter!");
|
throw new RuntimeException("Could not initialize interpreter!");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.calculatorView = new CalculatorView(this, this.calculatorModel);
|
this.calculatorView = new CalculatorView(this, CalculatorModel.instance);
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
@ -279,7 +274,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
|
|||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String s) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String s) {
|
||||||
dpclRegister.announce().onDragPreferencesChange(SimpleOnDragListener.getPreferences(CalculatorActivity.this));
|
dpclRegister.announce().onDragPreferencesChange(SimpleOnDragListener.getPreferences(CalculatorActivity.this));
|
||||||
|
|
||||||
this.calculatorModel.load(this);
|
CalculatorModel.instance.reset(this);
|
||||||
|
|
||||||
final Boolean colorExpressionsInBracketsDefault = new BooleanMapper().parseValue(this.getString(R.string.p_calc_color_display));
|
final Boolean colorExpressionsInBracketsDefault = new BooleanMapper().parseValue(this.getString(R.string.p_calc_color_display));
|
||||||
assert colorExpressionsInBracketsDefault != null;
|
assert colorExpressionsInBracketsDefault != null;
|
||||||
|
@ -12,7 +12,7 @@ import android.util.AttributeSet;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.solovyev.android.calculator.math.MathEntityType;
|
import org.solovyev.android.calculator.math.MathType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User: serso
|
* User: serso
|
||||||
@ -62,9 +62,9 @@ public class CalculatorEditor extends EditText {
|
|||||||
final StringBuilder text1 = new StringBuilder();
|
final StringBuilder text1 = new StringBuilder();
|
||||||
|
|
||||||
for (int i = 0; i < text.length(); i++) {
|
for (int i = 0; i < text.length(); i++) {
|
||||||
final MathEntityType.Result mathType = MathEntityType.getType(text, i);
|
final MathType.Result mathType = MathType.getType(text, i);
|
||||||
|
|
||||||
switch (mathType.getMathEntityType()) {
|
switch (mathType.getMathType()) {
|
||||||
case open_group_symbol:
|
case open_group_symbol:
|
||||||
numberOfOpenGroupSymbols++;
|
numberOfOpenGroupSymbols++;
|
||||||
maxNumberOfOpenGroupSymbols = Math.max(maxNumberOfOpenGroupSymbols, numberOfOpenGroupSymbols);
|
maxNumberOfOpenGroupSymbols = Math.max(maxNumberOfOpenGroupSymbols, numberOfOpenGroupSymbols);
|
||||||
@ -75,10 +75,10 @@ public class CalculatorEditor extends EditText {
|
|||||||
text1.append(text.charAt(i));
|
text1.append(text.charAt(i));
|
||||||
break;
|
break;
|
||||||
case function:
|
case function:
|
||||||
i = processHighlightedText(text1, i, mathType.getS(), "i");
|
i = processHighlightedText(text1, i, mathType.getMatch(), "i");
|
||||||
break;
|
break;
|
||||||
case constant:
|
case constant:
|
||||||
i = processHighlightedText(text1, i, mathType.getS(), "b");
|
i = processHighlightedText(text1, i, mathType.getMatch(), "b");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
text1.append(text.charAt(i));
|
text1.append(text.charAt(i));
|
||||||
@ -113,15 +113,15 @@ public class CalculatorEditor extends EditText {
|
|||||||
for (; i < s.length(); i++) {
|
for (; i < s.length(); i++) {
|
||||||
char ch = s.charAt(i);
|
char ch = s.charAt(i);
|
||||||
|
|
||||||
if (MathEntityType.openGroupSymbols.contains(ch)) {
|
if (MathType.openGroupSymbols.contains(ch)) {
|
||||||
result.append(ch);
|
result.append(ch);
|
||||||
result.append("</font>");
|
result.append("</font>");
|
||||||
i = processBracketGroup(result, s, i + 1, numberOfOpenings + 1, maxNumberOfGroups);
|
i = processBracketGroup(result, s, i + 1, numberOfOpenings + 1, maxNumberOfGroups);
|
||||||
result.append("<font color=\"").append(getColor(maxNumberOfGroups, numberOfOpenings)).append("\">");
|
result.append("<font color=\"").append(getColor(maxNumberOfGroups, numberOfOpenings)).append("\">");
|
||||||
if (i < s.length() && MathEntityType.closeGroupSymbols.contains(s.charAt(i))) {
|
if (i < s.length() && MathType.closeGroupSymbols.contains(s.charAt(i))) {
|
||||||
result.append(s.charAt(i));
|
result.append(s.charAt(i));
|
||||||
}
|
}
|
||||||
} else if (MathEntityType.closeGroupSymbols.contains(ch)) {
|
} else if (MathType.closeGroupSymbols.contains(ch)) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
result.append(ch);
|
result.append(ch);
|
||||||
|
@ -1,212 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
|
||||||
* For more information, please, contact se.solovyev@gmail.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.solovyev.android.calculator;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import bsh.EvalError;
|
|
||||||
import bsh.Interpreter;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.solovyev.common.NumberMapper;
|
|
||||||
import org.solovyev.common.exceptions.SersoException;
|
|
||||||
import org.solovyev.common.utils.MathUtils;
|
|
||||||
import org.solovyev.util.math.Complex;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User: serso
|
|
||||||
* Date: 9/12/11
|
|
||||||
* Time: 11:38 PM
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class CalculatorModel {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private Interpreter interpreter;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final Object interpreterMonitor = new Object();
|
|
||||||
|
|
||||||
private int numberOfFractionDigits = 5;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public final Preprocessor preprocessor = new ToJsclPreprocessor();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final VarsRegister varsRegister = new VarsRegister();
|
|
||||||
|
|
||||||
private static CalculatorModel instance;
|
|
||||||
|
|
||||||
public CalculatorModel(@Nullable Context context) {
|
|
||||||
load(context);
|
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
synchronized (interpreterMonitor) {
|
|
||||||
try {
|
|
||||||
interpreter = new Interpreter();
|
|
||||||
interpreter.eval(ToJsclPreprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
|
|
||||||
|
|
||||||
/*for (Var var : varsRegister.getVars()) {
|
|
||||||
if (!var.isSystem()) {
|
|
||||||
exec(var.getName() + "=" + var.getValue() + ";");
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
} catch (EvalError evalError) {
|
|
||||||
throw new RuntimeException(evalError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String evaluate(@NotNull JsclOperation operation, @NotNull String expression) throws EvalError, ParseException {
|
|
||||||
|
|
||||||
final StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.append(preprocessor.process(expression));
|
|
||||||
|
|
||||||
//Log.d(CalculatorModel.class.getName(), "Preprocessed expression: " + preprocessedExpression);
|
|
||||||
|
|
||||||
final Object evaluationObject;
|
|
||||||
synchronized (interpreterMonitor) {
|
|
||||||
evaluationObject = interpreter.eval(ToJsclPreprocessor.wrap(operation, sb.toString()));
|
|
||||||
}
|
|
||||||
String result = String.valueOf(evaluationObject).trim();
|
|
||||||
|
|
||||||
try {
|
|
||||||
result = String.valueOf(round(result));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
if (result.contains("sqrt(-1)")) {
|
|
||||||
try {
|
|
||||||
result = createResultForComplexNumber(result.replace("sqrt(-1)", "i"));
|
|
||||||
} catch (NumberFormatException e1) {
|
|
||||||
// throw original one
|
|
||||||
throw new ParseException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new ParseException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String createResultForComplexNumber(@NotNull final String s) {
|
|
||||||
final Complex complex = new Complex();
|
|
||||||
|
|
||||||
String result = "";
|
|
||||||
// may be it's just complex number
|
|
||||||
int plusIndex = s.lastIndexOf("+");
|
|
||||||
if (plusIndex >= 0) {
|
|
||||||
complex.setReal(round(s.substring(0, plusIndex)));
|
|
||||||
result += complex.getReal();
|
|
||||||
result += "+";
|
|
||||||
} else {
|
|
||||||
plusIndex = s.lastIndexOf("-");
|
|
||||||
if (plusIndex >= 0) {
|
|
||||||
complex.setReal(round(s.substring(0, plusIndex)));
|
|
||||||
result += complex.getReal();
|
|
||||||
result += "-";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int multiplyIndex = s.indexOf("*");
|
|
||||||
if (multiplyIndex >= 0) {
|
|
||||||
complex.setImaginary(round(s.substring(plusIndex >= 0 ? plusIndex + 1 : 0, multiplyIndex)));
|
|
||||||
result += complex.getImaginary();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
result += "i";
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Double round(@NotNull String result) {
|
|
||||||
final Double dResult = Double.valueOf(result);
|
|
||||||
return MathUtils.round(dResult, numberOfFractionDigits);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void load(@Nullable Context context) {
|
|
||||||
if (context != null) {
|
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
|
||||||
|
|
||||||
final NumberMapper<Integer> integerNumberMapper = new NumberMapper<Integer>(Integer.class);
|
|
||||||
this.setNumberOfFractionDigits(integerNumberMapper.parseValue(preferences.getString(context.getString(R.string.p_calc_result_precision_key), context.getString(R.string.p_calc_result_precision))));
|
|
||||||
}
|
|
||||||
|
|
||||||
varsRegister.load(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ParseException extends SersoException {
|
|
||||||
public ParseException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumberOfFractionDigits() {
|
|
||||||
return numberOfFractionDigits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNumberOfFractionDigits(int numberOfFractionDigits) {
|
|
||||||
this.numberOfFractionDigits = numberOfFractionDigits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void init(@Nullable Context context) throws EvalError {
|
|
||||||
if (!isLoaded()) {
|
|
||||||
instance = new CalculatorModel(context);
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("Calculator model already instantiated!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CalculatorModel getInstance() {
|
|
||||||
if (!isLoaded()) {
|
|
||||||
throw new RuntimeException("CalculatorModel must be instantiated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLoaded() {
|
|
||||||
return instance != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void exec(String str) throws EvalError {
|
|
||||||
interpreter.eval(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String eval(String str) throws EvalError {
|
|
||||||
return interpreter.eval(commands(str)).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public VarsRegister getVarsRegister() {
|
|
||||||
return varsRegister;
|
|
||||||
}
|
|
||||||
|
|
||||||
String commands(String str) {
|
|
||||||
return commands(str, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
String commands(String str, boolean found) {
|
|
||||||
for (int i = 0; i < cmds.length; i++) {
|
|
||||||
int n = str.length() - cmds[i].length() - 1;
|
|
||||||
if (n >= 0 && (" " + cmds[i].toLowerCase()).equals(str.substring(n)))
|
|
||||||
return commands(str.substring(0, n), true) + "." + cmds[i] + "()";
|
|
||||||
}
|
|
||||||
str = str.replaceAll("\n", "");
|
|
||||||
return found ? "jscl.math.Expression.valueOf(\"" + str + "\")" : str;
|
|
||||||
}
|
|
||||||
|
|
||||||
static final String cmds[] = new String[]{"expand", "factorize", "elementary", "simplify", "numeric", "toMathML", "toJava"};
|
|
||||||
}
|
|
@ -16,7 +16,10 @@ import android.view.*;
|
|||||||
import android.widget.*;
|
import android.widget.*;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.calculator.math.MathEntityType;
|
import org.solovyev.android.calculator.math.MathType;
|
||||||
|
import org.solovyev.android.calculator.model.CalculatorModel;
|
||||||
|
import org.solovyev.android.calculator.model.Var;
|
||||||
|
import org.solovyev.android.calculator.model.VarsRegister;
|
||||||
import org.solovyev.common.utils.StringUtils;
|
import org.solovyev.common.utils.StringUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -36,7 +39,7 @@ public class CalculatorVarsActivity extends ListActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
adapter = new VarsArrayAdapter(this, R.layout.var, R.id.var_text, new ArrayList<Var>(CalculatorModel.getInstance().getVarsRegister().getVars()));
|
adapter = new VarsArrayAdapter(this, R.layout.var, R.id.var_text, new ArrayList<Var>(CalculatorModel.instance.getVarsRegister().getVars()));
|
||||||
setListAdapter(adapter);
|
setListAdapter(adapter);
|
||||||
|
|
||||||
final ListView lv = getListView();
|
final ListView lv = getListView();
|
||||||
@ -111,7 +114,7 @@ public class CalculatorVarsActivity extends ListActivity {
|
|||||||
|
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, "System variable cannot be changed!", Toast.LENGTH_LONG).show();
|
Toast.makeText(this, getString(R.string.c_sys_var_cannot_be_changed), Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +138,7 @@ public class CalculatorVarsActivity extends ListActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||||
final String error;
|
final Integer error;
|
||||||
|
|
||||||
final EditText editName = (EditText) editView.findViewById(R.id.var_edit_name);
|
final EditText editName = (EditText) editView.findViewById(R.id.var_edit_name);
|
||||||
String name = editName.getText().toString();
|
String name = editName.getText().toString();
|
||||||
@ -147,13 +150,13 @@ public class CalculatorVarsActivity extends ListActivity {
|
|||||||
String description = editDescription.getText().toString();
|
String description = editDescription.getText().toString();
|
||||||
|
|
||||||
|
|
||||||
final VarsRegister varsRegister = CalculatorModel.getInstance().getVarsRegister();
|
final VarsRegister varsRegister = CalculatorModel.instance.getVarsRegister();
|
||||||
if (!StringUtils.isEmpty(name)) {
|
if (!StringUtils.isEmpty(name)) {
|
||||||
final Var varFromRegister = varsRegister.getVar(name);
|
final Var varFromRegister = varsRegister.getVar(name);
|
||||||
if (varFromRegister == null || varFromRegister == editedInstance) {
|
if (varFromRegister == null || varFromRegister == editedInstance) {
|
||||||
final MathEntityType.Result mathType = MathEntityType.getType(name, 0);
|
final MathType.Result mathType = MathType.getType(name, 0);
|
||||||
|
|
||||||
if (mathType.getMathEntityType() == MathEntityType.text || mathType.getMathEntityType() == MathEntityType.constant) {
|
if (mathType.getMathType() == MathType.text || mathType.getMathType() == MathType.constant) {
|
||||||
boolean correctDouble = true;
|
boolean correctDouble = true;
|
||||||
try {
|
try {
|
||||||
Double.valueOf(value);
|
Double.valueOf(value);
|
||||||
@ -167,20 +170,20 @@ public class CalculatorVarsActivity extends ListActivity {
|
|||||||
varBuilder.setDescription(description);
|
varBuilder.setDescription(description);
|
||||||
error = null;
|
error = null;
|
||||||
} else {
|
} else {
|
||||||
error = "Value is not a number!";
|
error = R.string.c_value_is_not_a_number;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error = "Variable name clashes with function name!";
|
error = R.string.c_var_name_clashes;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error = "Variable with same name already exist!";
|
error = R.string.c_var_already_exists;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error = "Name is empty!";
|
error = R.string.c_name_is_empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
Toast.makeText(CalculatorVarsActivity.this, error, Toast.LENGTH_LONG).show();
|
Toast.makeText(CalculatorVarsActivity.this, getString(error), Toast.LENGTH_LONG).show();
|
||||||
createEditVariableDialog(editedInstance, name, value, description);
|
createEditVariableDialog(editedInstance, name, value, description);
|
||||||
} else {
|
} else {
|
||||||
if ( editedInstance == null ) {
|
if ( editedInstance == null ) {
|
||||||
@ -290,7 +293,7 @@ public class CalculatorVarsActivity extends ListActivity {
|
|||||||
builder.create().show();
|
builder.create().show();
|
||||||
} else {
|
} else {
|
||||||
adapter.remove(var);
|
adapter.remove(var);
|
||||||
final VarsRegister varsRegister = CalculatorModel.getInstance().getVarsRegister();
|
final VarsRegister varsRegister = CalculatorModel.instance.getVarsRegister();
|
||||||
varsRegister.remove(var);
|
varsRegister.remove(var);
|
||||||
varsRegister.save(CalculatorVarsActivity.this);
|
varsRegister.save(CalculatorVarsActivity.this);
|
||||||
CalculatorVarsActivity.this.adapter.notifyDataSetChanged();
|
CalculatorVarsActivity.this.adapter.notifyDataSetChanged();
|
||||||
|
@ -19,7 +19,9 @@ import android.widget.Toast;
|
|||||||
import bsh.EvalError;
|
import bsh.EvalError;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.calculator.math.MathEntityType;
|
import org.solovyev.android.calculator.math.MathType;
|
||||||
|
import org.solovyev.android.calculator.model.CalculatorModel;
|
||||||
|
import org.solovyev.android.calculator.model.ParseException;
|
||||||
import org.solovyev.android.view.CursorControl;
|
import org.solovyev.android.view.CursorControl;
|
||||||
import org.solovyev.android.view.HistoryControl;
|
import org.solovyev.android.view.HistoryControl;
|
||||||
import org.solovyev.common.utils.MutableObject;
|
import org.solovyev.common.utils.MutableObject;
|
||||||
@ -36,7 +38,7 @@ import org.solovyev.common.utils.history.SimpleHistoryHelper;
|
|||||||
public class CalculatorView implements CursorControl, HistoryControl<CalculatorHistoryState> {
|
public class CalculatorView implements CursorControl, HistoryControl<CalculatorHistoryState> {
|
||||||
|
|
||||||
// millis to wait before evaluation after user edit action
|
// millis to wait before evaluation after user edit action
|
||||||
public static final int EVAL_DELAY_MILLIS = 500;
|
public static final int EVAL_DELAY_MILLIS = 700;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final CalculatorEditor editor;
|
private final CalculatorEditor editor;
|
||||||
@ -44,9 +46,6 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
|||||||
@NotNull
|
@NotNull
|
||||||
private final CalculatorDisplay display;
|
private final CalculatorDisplay display;
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final Activity activity;
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final CalculatorModel calculatorModel;
|
private final CalculatorModel calculatorModel;
|
||||||
|
|
||||||
@ -54,7 +53,6 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
|||||||
private final HistoryHelper<CalculatorHistoryState> history;
|
private final HistoryHelper<CalculatorHistoryState> history;
|
||||||
|
|
||||||
public CalculatorView(@NotNull final Activity activity, @NotNull CalculatorModel calculator) {
|
public CalculatorView(@NotNull final Activity activity, @NotNull CalculatorModel calculator) {
|
||||||
this.activity = activity;
|
|
||||||
this.calculatorModel = calculator;
|
this.calculatorModel = calculator;
|
||||||
|
|
||||||
final InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
final InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
@ -159,7 +157,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
|||||||
localDisplay.setText(calculatorModel.evaluate(JsclOperation.numeric, expression));
|
localDisplay.setText(calculatorModel.evaluate(JsclOperation.numeric, expression));
|
||||||
} catch (EvalError e) {
|
} catch (EvalError e) {
|
||||||
handleEvaluationException(expression, localDisplay, e);
|
handleEvaluationException(expression, localDisplay, e);
|
||||||
} catch (CalculatorModel.ParseException e) {
|
} catch (ParseException e) {
|
||||||
handleEvaluationException(expression, localDisplay, e);
|
handleEvaluationException(expression, localDisplay, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,11 +190,11 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
|
|||||||
@Override
|
@Override
|
||||||
public void doOperation(@NotNull EditText editor) {
|
public void doOperation(@NotNull EditText editor) {
|
||||||
|
|
||||||
final MathEntityType.Result mathType = MathEntityType.getType(text, 0);
|
final MathType.Result mathType = MathType.getType(text, 0);
|
||||||
|
|
||||||
int cursorPositionOffset = 0;
|
int cursorPositionOffset = 0;
|
||||||
final StringBuilder textToBeInserted = new StringBuilder(text);
|
final StringBuilder textToBeInserted = new StringBuilder(text);
|
||||||
switch (mathType.getMathEntityType()) {
|
switch (mathType.getMathType()) {
|
||||||
case function:
|
case function:
|
||||||
textToBeInserted.append("()");
|
textToBeInserted.append("()");
|
||||||
cursorPositionOffset = -1;
|
cursorPositionOffset = -1;
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
package org.solovyev.android.calculator;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User: serso
|
|
||||||
* Date: 9/26/11
|
|
||||||
* Time: 12:12 PM
|
|
||||||
*/
|
|
||||||
public interface Preprocessor {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
String process(@NotNull String s);
|
|
||||||
}
|
|
@ -14,6 +14,11 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class Functions {
|
public class Functions {
|
||||||
|
|
||||||
|
// not intended for instantiation
|
||||||
|
private Functions() {
|
||||||
|
throw new AssertionError("Not allowed!");
|
||||||
|
}
|
||||||
|
|
||||||
public final static String SIN = "sin";
|
public final static String SIN = "sin";
|
||||||
public final static String SINH = "sinh";
|
public final static String SINH = "sinh";
|
||||||
public final static String ASIN = "asin";
|
public final static String ASIN = "asin";
|
||||||
@ -45,8 +50,4 @@ public class Functions {
|
|||||||
public final static Character DEGREE = '°';
|
public final static Character DEGREE = '°';
|
||||||
|
|
||||||
public static final List<Character> allPostfix = Arrays.asList(FACT, DEGREE);
|
public static final List<Character> allPostfix = Arrays.asList(FACT, DEGREE);
|
||||||
|
|
||||||
private Functions() {
|
|
||||||
throw new AssertionError("Not allowed!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
package org.solovyev.android.calculator.math;
|
package org.solovyev.android.calculator.math;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.solovyev.android.calculator.CalculatorModel;
|
|
||||||
import org.solovyev.android.calculator.CharacterAtPositionFinder;
|
import org.solovyev.android.calculator.CharacterAtPositionFinder;
|
||||||
import org.solovyev.android.calculator.StartsWithFinder;
|
import org.solovyev.android.calculator.StartsWithFinder;
|
||||||
|
import org.solovyev.android.calculator.model.CalculatorModel;
|
||||||
import org.solovyev.common.utils.Finder;
|
import org.solovyev.common.utils.Finder;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -16,7 +16,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import static org.solovyev.common.utils.CollectionsUtils.get;
|
import static org.solovyev.common.utils.CollectionsUtils.get;
|
||||||
|
|
||||||
public enum MathEntityType {
|
public enum MathType {
|
||||||
|
|
||||||
digit,
|
digit,
|
||||||
constant,
|
constant,
|
||||||
@ -30,7 +30,12 @@ public enum MathEntityType {
|
|||||||
close_group_symbol,
|
close_group_symbol,
|
||||||
text;
|
text;
|
||||||
|
|
||||||
public static final List<String> constants = Arrays.asList("e", "π", "i");
|
public static final String IMAGINARY_NUMBER = "i";
|
||||||
|
public static final String IMAGINARY_NUMBER_DEF = "sqrt(-1)";
|
||||||
|
public static final String PI = "π";
|
||||||
|
public static final String E = "e";
|
||||||
|
|
||||||
|
public static final List<String> constants = Arrays.asList(E, PI, IMAGINARY_NUMBER);
|
||||||
|
|
||||||
public static final List<String> digits = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
|
public static final List<String> digits = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
|
||||||
|
|
||||||
@ -57,11 +62,6 @@ public enum MathEntityType {
|
|||||||
* @param i index which points to start of substring
|
* @param i index which points to start of substring
|
||||||
* @return math entity type of substring starting from ith index of specified text
|
* @return math entity type of substring starting from ith index of specified text
|
||||||
*/
|
*/
|
||||||
@NotNull
|
|
||||||
public static MathEntityType getMathEntityType(@NotNull String text, int i) {
|
|
||||||
return getType(text, i).getMathEntityType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Result getType(@NotNull String text, int i) {
|
public static Result getType(@NotNull String text, int i) {
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
@ -69,7 +69,7 @@ public enum MathEntityType {
|
|||||||
} else if (i >= text.length() && i != 0) {
|
} else if (i >= text.length() && i != 0) {
|
||||||
throw new IllegalArgumentException("I must be less than size of text.");
|
throw new IllegalArgumentException("I must be less than size of text.");
|
||||||
} else if (i == 0 && text.length() == 0) {
|
} else if (i == 0 && text.length() == 0) {
|
||||||
return new Result(MathEntityType.text, text);
|
return new Result(MathType.text, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
final StartsWithFinder stringStartWithFinder = new StartsWithFinder(text, i);
|
final StartsWithFinder stringStartWithFinder = new StartsWithFinder(text, i);
|
||||||
@ -77,7 +77,7 @@ public enum MathEntityType {
|
|||||||
|
|
||||||
String foundString = get(digits, stringStartWithFinder);
|
String foundString = get(digits, stringStartWithFinder);
|
||||||
if (foundString != null) {
|
if (foundString != null) {
|
||||||
return new Result(MathEntityType.digit, foundString);
|
return new Result(MathType.digit, foundString);
|
||||||
}
|
}
|
||||||
|
|
||||||
Character foundCharacter = get(dots, characterStartWithFinder);
|
Character foundCharacter = get(dots, characterStartWithFinder);
|
||||||
@ -102,7 +102,7 @@ public enum MathEntityType {
|
|||||||
|
|
||||||
foundString = get(groupSymbols, stringStartWithFinder);
|
foundString = get(groupSymbols, stringStartWithFinder);
|
||||||
if (foundString != null) {
|
if (foundString != null) {
|
||||||
return new Result(MathEntityType.group_symbols, foundString);
|
return new Result(MathType.group_symbols, foundString);
|
||||||
}
|
}
|
||||||
|
|
||||||
foundCharacter = get(openGroupSymbols, characterStartWithFinder);
|
foundCharacter = get(openGroupSymbols, characterStartWithFinder);
|
||||||
@ -117,39 +117,39 @@ public enum MathEntityType {
|
|||||||
|
|
||||||
foundString = get(prefixFunctions, stringStartWithFinder);
|
foundString = get(prefixFunctions, stringStartWithFinder);
|
||||||
if (foundString != null) {
|
if (foundString != null) {
|
||||||
return new Result(MathEntityType.function, foundString);
|
return new Result(MathType.function, foundString);
|
||||||
}
|
}
|
||||||
|
|
||||||
foundString = get(CalculatorModel.getInstance().getVarsRegister().getVarNames(), stringStartWithFinder);
|
foundString = get(CalculatorModel.instance.getVarsRegister().getVarNames(), stringStartWithFinder);
|
||||||
if (foundString != null) {
|
if (foundString != null) {
|
||||||
return new Result(MathEntityType.constant, foundString);
|
return new Result(MathType.constant, foundString);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Result(MathEntityType.text, text.substring(i));
|
return new Result(MathType.text, text.substring(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Result {
|
public static class Result {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final MathEntityType mathEntityType;
|
private final MathType mathType;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final String s;
|
private final String match;
|
||||||
|
|
||||||
private Result(@NotNull MathEntityType mathEntityType, @NotNull String s){
|
private Result(@NotNull MathType mathType, @NotNull String match){
|
||||||
this.mathEntityType = mathEntityType;
|
this.mathType = mathType;
|
||||||
|
|
||||||
this.s = s;
|
this.match = match;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getS() {
|
public String getMatch() {
|
||||||
return s;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public MathEntityType getMathEntityType() {
|
public MathType getMathType() {
|
||||||
return mathEntityType;
|
return mathType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||||
|
* For more information, please, contact se.solovyev@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.solovyev.android.calculator.model;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import bsh.EvalError;
|
||||||
|
import bsh.Interpreter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.android.calculator.JsclOperation;
|
||||||
|
import org.solovyev.common.NumberMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 9/12/11
|
||||||
|
* Time: 11:38 PM
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum CalculatorModel {
|
||||||
|
|
||||||
|
instance;
|
||||||
|
|
||||||
|
private static final String RESULT_PRECISION_P_KEY = "org.solovyev.android.calculator.CalculatorModel_result_precision";
|
||||||
|
private static final String RESULT_PRECISION_DEFAULT = "5";
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Interpreter interpreter;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final Object lock = new Object();
|
||||||
|
|
||||||
|
private int numberOfFractionDigits = 5;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public final TextProcessor preprocessor = new ToJsclTextProcessor();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public final TextProcessor postprocessor = new FromJsclTextProcessor();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final VarsRegisterImpl varsRegister = new VarsRegisterImpl();
|
||||||
|
|
||||||
|
public String evaluate(@NotNull JsclOperation operation, @NotNull String expression) throws EvalError, ParseException {
|
||||||
|
synchronized (lock) {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.append(preprocessor.process(expression));
|
||||||
|
|
||||||
|
//Log.d(CalculatorModel.class.getName(), "Preprocessed expression: " + preprocessedExpression);
|
||||||
|
|
||||||
|
final Object evaluationObject = interpreter.eval(ToJsclTextProcessor.wrap(operation, sb.toString()));
|
||||||
|
|
||||||
|
return postprocessor.process(String.valueOf(evaluationObject).trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfFractionDigits() {
|
||||||
|
return numberOfFractionDigits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumberOfFractionDigits(int numberOfFractionDigits) {
|
||||||
|
this.numberOfFractionDigits = numberOfFractionDigits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(@Nullable Context context) throws EvalError {
|
||||||
|
synchronized (lock) {
|
||||||
|
reset(context);
|
||||||
|
resetInterpreter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(@Nullable Context context) {
|
||||||
|
synchronized (lock) {
|
||||||
|
if (context != null) {
|
||||||
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
final NumberMapper<Integer> integerNumberMapper = new NumberMapper<Integer>(Integer.class);
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
this.setNumberOfFractionDigits(integerNumberMapper.parseValue(preferences.getString(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
varsRegister.init(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetInterpreter() {
|
||||||
|
synchronized (lock) {
|
||||||
|
try {
|
||||||
|
interpreter = new Interpreter();
|
||||||
|
interpreter.eval(ToJsclTextProcessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
|
||||||
|
} catch (EvalError evalError) {
|
||||||
|
throw new RuntimeException(evalError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public VarsRegister getVarsRegister() {
|
||||||
|
return varsRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* private String commands(String str) {
|
||||||
|
return commands(str, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void exec(String str) throws EvalError {
|
||||||
|
interpreter.eval(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String eval(String str) throws EvalError {
|
||||||
|
return interpreter.eval(commands(str)).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String commands(String str, boolean found) {
|
||||||
|
for (int i = 0; i < cmds.length; i++) {
|
||||||
|
int n = str.length() - cmds[i].length() - 1;
|
||||||
|
if (n >= 0 && (" " + cmds[i].toLowerCase()).equals(str.substring(n)))
|
||||||
|
return commands(str.substring(0, n), true) + "." + cmds[i] + "()";
|
||||||
|
}
|
||||||
|
str = str.replaceAll("\n", "");
|
||||||
|
return found ? "jscl.math.Expression.valueOf(\"" + str + "\")" : str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String cmds[] = new String[]{"expand", "factorize", "elementary", "simplify", "numeric", "toMathML", "toJava"};*/
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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.android.calculator.math.MathType;
|
||||||
|
import org.solovyev.common.utils.MathUtils;
|
||||||
|
import org.solovyev.util.math.Complex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 10/6/11
|
||||||
|
* Time: 9:48 PM
|
||||||
|
*/
|
||||||
|
class FromJsclTextProcessor implements TextProcessor {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String process(@NotNull String s) throws ParseException {
|
||||||
|
String result = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = String.valueOf(round(s));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
if (result.contains(MathType.IMAGINARY_NUMBER_DEF)) {
|
||||||
|
try {
|
||||||
|
result = createResultForComplexNumber(result.replace(MathType.IMAGINARY_NUMBER_DEF, MathType.IMAGINARY_NUMBER));
|
||||||
|
} catch (NumberFormatException e1) {
|
||||||
|
// throw original one
|
||||||
|
throw new ParseException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new ParseException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String createResultForComplexNumber(@NotNull final String s) {
|
||||||
|
final Complex complex = new Complex();
|
||||||
|
|
||||||
|
String result = "";
|
||||||
|
// may be it's just complex number
|
||||||
|
int plusIndex = s.lastIndexOf("+");
|
||||||
|
if (plusIndex >= 0) {
|
||||||
|
complex.setReal(round(s.substring(0, plusIndex)));
|
||||||
|
result += complex.getReal();
|
||||||
|
result += "+";
|
||||||
|
} else {
|
||||||
|
plusIndex = s.lastIndexOf("-");
|
||||||
|
if (plusIndex >= 0) {
|
||||||
|
complex.setReal(round(s.substring(0, plusIndex)));
|
||||||
|
result += complex.getReal();
|
||||||
|
result += "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int multiplyIndex = s.indexOf("*");
|
||||||
|
if (multiplyIndex >= 0) {
|
||||||
|
complex.setImaginary(round(s.substring(plusIndex >= 0 ? plusIndex + 1 : 0, multiplyIndex)));
|
||||||
|
result += complex.getImaginary();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
result += MathType.IMAGINARY_NUMBER;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Double round(@NotNull String result) {
|
||||||
|
final Double dResult = Double.valueOf(result);
|
||||||
|
return MathUtils.round(dResult, CalculatorModel.instance.getNumberOfFractionDigits());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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.solovyev.common.exceptions.SersoException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 10/6/11
|
||||||
|
* Time: 9:25 PM
|
||||||
|
*/
|
||||||
|
public class ParseException extends SersoException {
|
||||||
|
public ParseException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.solovyev.android.calculator.model;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 9/26/11
|
||||||
|
* Time: 12:12 PM
|
||||||
|
*/
|
||||||
|
public interface TextProcessor {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
String process(@NotNull String s) throws ParseException;
|
||||||
|
}
|
@ -4,17 +4,19 @@
|
|||||||
* or visit http://se.solovyev.org
|
* or visit http://se.solovyev.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator.model;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.android.calculator.JsclOperation;
|
||||||
|
import org.solovyev.android.calculator.StartsWithFinder;
|
||||||
import org.solovyev.android.calculator.math.Functions;
|
import org.solovyev.android.calculator.math.Functions;
|
||||||
import org.solovyev.android.calculator.math.MathEntityType;
|
import org.solovyev.android.calculator.math.MathType;
|
||||||
import org.solovyev.common.utils.CollectionsUtils;
|
import org.solovyev.common.utils.CollectionsUtils;
|
||||||
import org.solovyev.common.utils.FilterType;
|
import org.solovyev.common.utils.FilterType;
|
||||||
import org.solovyev.common.utils.Finder;
|
import org.solovyev.common.utils.Finder;
|
||||||
|
|
||||||
public class ToJsclPreprocessor implements Preprocessor {
|
class ToJsclTextProcessor implements TextProcessor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
@ -23,26 +25,26 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
MathEntityType.Result mathTypeResult = null;
|
MathType.Result mathTypeResult = null;
|
||||||
for (int i = 0; i < s.length(); i++) {
|
for (int i = 0; i < s.length(); i++) {
|
||||||
char ch = s.charAt(i);
|
char ch = s.charAt(i);
|
||||||
startsWithFinder.setI(i);
|
startsWithFinder.setI(i);
|
||||||
|
|
||||||
mathTypeResult = checkMultiplicationSignBeforeFunction(sb, s, i, mathTypeResult);
|
mathTypeResult = checkMultiplicationSignBeforeFunction(sb, s, i, mathTypeResult);
|
||||||
|
|
||||||
final MathEntityType mathType = mathTypeResult.getMathEntityType();
|
final MathType mathType = mathTypeResult.getMathType();
|
||||||
if (mathType == MathEntityType.open_group_symbol) {
|
if (mathType == MathType.open_group_symbol) {
|
||||||
sb.append('(');
|
sb.append('(');
|
||||||
} else if (mathType == MathEntityType.close_group_symbol) {
|
} else if (mathType == MathType.close_group_symbol) {
|
||||||
sb.append(')');
|
sb.append(')');
|
||||||
} else if (ch == '×' || ch == '∙') {
|
} else if (ch == '×' || ch == '∙') {
|
||||||
sb.append("*");
|
sb.append("*");
|
||||||
} else if ( mathType == MathEntityType.function ){
|
} else if ( mathType == MathType.function ){
|
||||||
sb.append(toJsclFunction(mathTypeResult.getS()));
|
sb.append(toJsclFunction(mathTypeResult.getMatch()));
|
||||||
i += mathTypeResult.getS().length() - 1;
|
i += mathTypeResult.getMatch().length() - 1;
|
||||||
} else if ( mathType == MathEntityType.constant ) {
|
} else if ( mathType == MathType.constant ) {
|
||||||
sb.append(mathTypeResult.getS());
|
sb.append(mathTypeResult.getMatch());
|
||||||
i += mathTypeResult.getS().length() - 1;
|
i += mathTypeResult.getMatch().length() - 1;
|
||||||
} else {
|
} else {
|
||||||
sb.append(ch);
|
sb.append(ch);
|
||||||
}
|
}
|
||||||
@ -59,11 +61,11 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
startsWithFinder.setI(i);
|
startsWithFinder.setI(i);
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
String functionName = CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder);
|
String functionName = CollectionsUtils.get(MathType.prefixFunctions, startsWithFinder);
|
||||||
if (functionName == null) {
|
if (functionName == null) {
|
||||||
String varName = CollectionsUtils.get(CalculatorModel.getInstance().getVarsRegister().getVarNames(), startsWithFinder);
|
String varName = CollectionsUtils.get(CalculatorModel.instance.getVarsRegister().getVarNames(), startsWithFinder);
|
||||||
if (varName != null) {
|
if (varName != null) {
|
||||||
final Var var = CalculatorModel.getInstance().getVarsRegister().getVar(varName);
|
final Var var = CalculatorModel.instance.getVarsRegister().getVar(varName);
|
||||||
if (var != null) {
|
if (var != null) {
|
||||||
result.append(var.getValue());
|
result.append(var.getValue());
|
||||||
offset = varName.length();
|
offset = varName.length();
|
||||||
@ -86,10 +88,10 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void replaceVariables(StringBuilder sb, String s, int i, @NotNull StartsWithFinder startsWithFinder) {
|
private void replaceVariables(StringBuilder sb, String s, int i, @NotNull StartsWithFinder startsWithFinder) {
|
||||||
for (Var var : CalculatorModel.getInstance().getVarsRegister().getVars()) {
|
for (Var var : CalculatorModel.instance.getVarsRegister().getVars()) {
|
||||||
if (!var.isSystem()) {
|
if (!var.isSystem()) {
|
||||||
if (s.startsWith(var.getName(), i)) {
|
if (s.startsWith(var.getName(), i)) {
|
||||||
if (CollectionsUtils.get(MathEntityType.prefixFunctions, startsWithFinder) == null) {
|
if (CollectionsUtils.get(MathType.prefixFunctions, startsWithFinder) == null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,13 +105,13 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
int result = position;
|
int result = position;
|
||||||
for (; result >= 0; result--) {
|
for (; result >= 0; result--) {
|
||||||
|
|
||||||
final MathEntityType mathEntityType = MathEntityType.getMathEntityType(s, result);
|
final MathType mathType = MathType.getType(s, result).getMathType();
|
||||||
|
|
||||||
if (CollectionsUtils.contains(mathEntityType, MathEntityType.digit, MathEntityType.dot)) {
|
if (CollectionsUtils.contains(mathType, MathType.digit, MathType.dot)) {
|
||||||
// continue
|
// continue
|
||||||
} else if (mathEntityType == MathEntityType.close_group_symbol) {
|
} else if (mathType == MathType.close_group_symbol) {
|
||||||
numberOfOpenGroups++;
|
numberOfOpenGroups++;
|
||||||
} else if (mathEntityType == MathEntityType.open_group_symbol) {
|
} else if (mathType == MathType.open_group_symbol) {
|
||||||
numberOfOpenGroups--;
|
numberOfOpenGroups--;
|
||||||
} else {
|
} else {
|
||||||
if (stop(s, numberOfOpenGroups, result)) break;
|
if (stop(s, numberOfOpenGroups, result)) break;
|
||||||
@ -124,9 +126,9 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
final EndsWithFinder endsWithFinder = new EndsWithFinder(s);
|
final EndsWithFinder endsWithFinder = new EndsWithFinder(s);
|
||||||
endsWithFinder.setI(i + 1);
|
endsWithFinder.setI(i + 1);
|
||||||
if (!CollectionsUtils.contains(MathEntityType.prefixFunctions, FilterType.included, endsWithFinder)) {
|
if (!CollectionsUtils.contains(MathType.prefixFunctions, FilterType.included, endsWithFinder)) {
|
||||||
MathEntityType type = MathEntityType.getMathEntityType(s, i);
|
MathType type = MathType.getType(s, i).getMathType();
|
||||||
if (type != MathEntityType.constant) {
|
if (type != MathType.constant) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,31 +177,31 @@ public class ToJsclPreprocessor implements Preprocessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static MathEntityType.Result checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb,
|
private static MathType.Result checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb,
|
||||||
@NotNull String s,
|
@NotNull String s,
|
||||||
int i,
|
int i,
|
||||||
@Nullable MathEntityType.Result mathTypeBeforeResult) {
|
@Nullable MathType.Result mathTypeBeforeResult) {
|
||||||
MathEntityType.Result result = MathEntityType.getType(s, i);
|
MathType.Result result = MathType.getType(s, i);
|
||||||
|
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
|
|
||||||
final MathEntityType mathType = result.getMathEntityType();
|
final MathType mathType = result.getMathType();
|
||||||
assert mathTypeBeforeResult != null;
|
assert mathTypeBeforeResult != null;
|
||||||
final MathEntityType mathTypeBefore = mathTypeBeforeResult.getMathEntityType();
|
final MathType mathTypeBefore = mathTypeBeforeResult.getMathType();
|
||||||
|
|
||||||
if (mathTypeBefore == MathEntityType.constant || (mathTypeBefore != MathEntityType.binary_operation &&
|
if (mathTypeBefore == MathType.constant || (mathTypeBefore != MathType.binary_operation &&
|
||||||
mathTypeBefore != MathEntityType.unary_operation &&
|
mathTypeBefore != MathType.unary_operation &&
|
||||||
mathTypeBefore != MathEntityType.function &&
|
mathTypeBefore != MathType.function &&
|
||||||
mathTypeBefore != MathEntityType.open_group_symbol)) {
|
mathTypeBefore != MathType.open_group_symbol)) {
|
||||||
|
|
||||||
if (mathType == MathEntityType.constant) {
|
if (mathType == MathType.constant) {
|
||||||
sb.append("*");
|
sb.append("*");
|
||||||
} else if (mathType == MathEntityType.open_group_symbol && mathTypeBefore != null) {
|
} else if (mathType == MathType.open_group_symbol && mathTypeBefore != null) {
|
||||||
sb.append("*");
|
sb.append("*");
|
||||||
} else if (mathType == MathEntityType.digit && ((mathTypeBefore != MathEntityType.digit && mathTypeBefore != MathEntityType.dot) || mathTypeBefore == MathEntityType.constant)) {
|
} else if (mathType == MathType.digit && ((mathTypeBefore != MathType.digit && mathTypeBefore != MathType.dot) || mathTypeBefore == MathType.constant)) {
|
||||||
sb.append("*");
|
sb.append("*");
|
||||||
} else {
|
} else {
|
||||||
for (String function : MathEntityType.prefixFunctions) {
|
for (String function : MathType.prefixFunctions) {
|
||||||
if (s.startsWith(function, i)) {
|
if (s.startsWith(function, i)) {
|
||||||
sb.append("*");
|
sb.append("*");
|
||||||
break;
|
break;
|
@ -4,7 +4,7 @@
|
|||||||
* or visit http://se.solovyev.org
|
* or visit http://se.solovyev.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator.model;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
@ -1,4 +1,4 @@
|
|||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator.model;
|
||||||
|
|
||||||
import org.simpleframework.xml.ElementList;
|
import org.simpleframework.xml.ElementList;
|
||||||
import org.simpleframework.xml.Root;
|
import org.simpleframework.xml.Root;
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.content.Context;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 10/6/11
|
||||||
|
* Time: 9:31 PM
|
||||||
|
*/
|
||||||
|
public interface VarsRegister {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
List<Var> getVars();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
List<Var> getSystemVars();
|
||||||
|
|
||||||
|
Var addVar(@Nullable String name, @NotNull Var.Builder builder);
|
||||||
|
|
||||||
|
void remove(@NotNull Var var);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
List<String> getVarNames();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
Var getVar(@NotNull String name);
|
||||||
|
|
||||||
|
boolean contains(@NotNull String name);
|
||||||
|
|
||||||
|
void save(@NotNull Context context);
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
* or visit http://se.solovyev.org
|
* or visit http://se.solovyev.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator.model;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
@ -13,8 +13,9 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.simpleframework.xml.Serializer;
|
import org.simpleframework.xml.Serializer;
|
||||||
import org.simpleframework.xml.core.Persister;
|
import org.simpleframework.xml.core.Persister;
|
||||||
|
import org.solovyev.android.calculator.R;
|
||||||
import org.solovyev.android.calculator.math.MathEntityComparator;
|
import org.solovyev.android.calculator.math.MathEntityComparator;
|
||||||
import org.solovyev.android.calculator.math.MathEntityType;
|
import org.solovyev.android.calculator.math.MathType;
|
||||||
import org.solovyev.common.utils.CollectionsUtils;
|
import org.solovyev.common.utils.CollectionsUtils;
|
||||||
import org.solovyev.common.utils.Finder;
|
import org.solovyev.common.utils.Finder;
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ import java.util.*;
|
|||||||
* Date: 9/29/11
|
* Date: 9/29/11
|
||||||
* Time: 4:57 PM
|
* Time: 4:57 PM
|
||||||
*/
|
*/
|
||||||
public class VarsRegister {
|
class VarsRegisterImpl implements VarsRegister {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final List<Var> vars = new ArrayList<Var>();
|
private final List<Var> vars = new ArrayList<Var>();
|
||||||
@ -34,16 +35,22 @@ public class VarsRegister {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private final List<Var> systemVars = new ArrayList<Var>();
|
private final List<Var> systemVars = new ArrayList<Var>();
|
||||||
|
|
||||||
|
protected VarsRegisterImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<Var> getVars() {
|
public List<Var> getVars() {
|
||||||
return Collections.unmodifiableList(vars);
|
return Collections.unmodifiableList(vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<Var> getSystemVars() {
|
public List<Var> getSystemVars() {
|
||||||
return Collections.unmodifiableList(systemVars);
|
return Collections.unmodifiableList(systemVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Var addVar(@Nullable String name, @NotNull Var.Builder builder) {
|
public Var addVar(@Nullable String name, @NotNull Var.Builder builder) {
|
||||||
final Var var = builder.create();
|
final Var var = builder.create();
|
||||||
|
|
||||||
@ -58,10 +65,12 @@ public class VarsRegister {
|
|||||||
return varFromRegister;
|
return varFromRegister;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void remove(@NotNull Var var) {
|
public void remove(@NotNull Var var) {
|
||||||
this.vars.remove(var);
|
this.vars.remove(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<String> getVarNames() {
|
public List<String> getVarNames() {
|
||||||
final List<String> result = new ArrayList<String>();
|
final List<String> result = new ArrayList<String>();
|
||||||
@ -75,6 +84,7 @@ public class VarsRegister {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public Var getVar(@NotNull final String name) {
|
public Var getVar(@NotNull final String name) {
|
||||||
return CollectionsUtils.get(vars, new Finder<Var>() {
|
return CollectionsUtils.get(vars, new Finder<Var>() {
|
||||||
@ -85,6 +95,7 @@ public class VarsRegister {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean contains(@NotNull final String name) {
|
public boolean contains(@NotNull final String name) {
|
||||||
return CollectionsUtils.get(vars, new Finder<Var>() {
|
return CollectionsUtils.get(vars, new Finder<Var>() {
|
||||||
@Override
|
@Override
|
||||||
@ -107,7 +118,7 @@ public class VarsRegister {
|
|||||||
vars.addAll(result);
|
vars.addAll(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void load(@Nullable Context context) {
|
synchronized void init(@Nullable Context context) {
|
||||||
|
|
||||||
this.vars.clear();
|
this.vars.clear();
|
||||||
this.systemVars.clear();
|
this.systemVars.clear();
|
||||||
@ -128,19 +139,32 @@ public class VarsRegister {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (String systemVarName : MathEntityType.constants) {
|
for (String systemVarName : MathType.constants) {
|
||||||
|
|
||||||
final Var systemVar;
|
final Var.Builder builder;
|
||||||
if ( systemVarName.equals("e") ){
|
final Integer varDescription;
|
||||||
systemVar = new Var.Builder(systemVarName, Math.E).setSystem(true).create();
|
|
||||||
} else if (systemVarName.equals("π")) {
|
if ( systemVarName.equals(MathType.E) ){
|
||||||
systemVar = new Var.Builder(systemVarName, Math.PI).setSystem(true).create();
|
builder = new Var.Builder(systemVarName, Math.E);
|
||||||
} else if (systemVarName.equals("i")) {
|
varDescription = R.string.c_e_description;
|
||||||
systemVar = new Var.Builder(systemVarName, "sqrt(-1)").setSystem(true).create();
|
} else if (systemVarName.equals(MathType.PI)) {
|
||||||
|
builder = new Var.Builder(systemVarName, Math.PI);
|
||||||
|
varDescription = R.string.c_pi_description;
|
||||||
|
} else if (systemVarName.equals(MathType.IMAGINARY_NUMBER)) {
|
||||||
|
builder = new Var.Builder(systemVarName, MathType.IMAGINARY_NUMBER_DEF);
|
||||||
|
varDescription = R.string.c_i_description;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException(systemVarName + " is not supported yet!");
|
throw new IllegalArgumentException(systemVarName + " is not supported yet!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.setSystem(true);
|
||||||
|
|
||||||
|
if (context != null) {
|
||||||
|
builder.setDescription(context.getString(varDescription));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Var systemVar = builder.create();
|
||||||
|
|
||||||
systemVars.add(systemVar);
|
systemVars.add(systemVar);
|
||||||
if (!vars.contains(systemVar)) {
|
if (!vars.contains(systemVar)) {
|
||||||
vars.add(systemVar);
|
vars.add(systemVar);
|
||||||
@ -153,6 +177,7 @@ public class VarsRegister {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public synchronized void save(@NotNull Context context) {
|
public synchronized void save(@NotNull Context context) {
|
||||||
final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
|
final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
final SharedPreferences.Editor editor = settings.edit();
|
final SharedPreferences.Editor editor = settings.edit();
|
@ -80,12 +80,12 @@ public class AutoResizeTextView extends TextView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When text changes, set the force resize flag to true and reset the text size.
|
* When text changes, set the force resize flag to true and resetInterpreter the text size.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
|
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
|
||||||
mNeedsResize = true;
|
mNeedsResize = true;
|
||||||
// Since this view may be reused, it is good to reset the text size
|
// Since this view may be reused, it is good to resetInterpreter the text size
|
||||||
resetTextSize();
|
resetTextSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.math;
|
|
||||||
|
|
||||||
import junit.framework.Assert;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.solovyev.android.calculator.CalculatorModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User: serso
|
|
||||||
* Date: 10/5/11
|
|
||||||
* Time: 1:25 AM
|
|
||||||
*/
|
|
||||||
public class MathEntityTypeTest {
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void setUp() throws Exception {
|
|
||||||
CalculatorModel.init(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetType() throws Exception {
|
|
||||||
Assert.assertEquals(MathEntityType.function, MathEntityType.getType("sin", 0).getMathEntityType());
|
|
||||||
Assert.assertEquals(MathEntityType.text, MathEntityType.getType("sn", 0).getMathEntityType());
|
|
||||||
Assert.assertEquals(MathEntityType.text, MathEntityType.getType("s", 0).getMathEntityType());
|
|
||||||
Assert.assertEquals(MathEntityType.text, MathEntityType.getType("", 0).getMathEntityType());
|
|
||||||
|
|
||||||
try {
|
|
||||||
Assert.assertEquals(MathEntityType.text, MathEntityType.getType("22", -1).getMathEntityType());
|
|
||||||
Assert.fail();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Assert.assertEquals(MathEntityType.text, MathEntityType.getType("22", 2).getMathEntityType());
|
|
||||||
Assert.fail();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.math;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.solovyev.android.calculator.model.CalculatorModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 10/5/11
|
||||||
|
* Time: 1:25 AM
|
||||||
|
*/
|
||||||
|
public class MathTypeTest {
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Exception {
|
||||||
|
CalculatorModel.instance.init(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetType() throws Exception {
|
||||||
|
Assert.assertEquals(MathType.function, MathType.getType("sin", 0).getMathType());
|
||||||
|
Assert.assertEquals(MathType.text, MathType.getType("sn", 0).getMathType());
|
||||||
|
Assert.assertEquals(MathType.text, MathType.getType("s", 0).getMathType());
|
||||||
|
Assert.assertEquals(MathType.text, MathType.getType("", 0).getMathType());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Assert.assertEquals(MathType.text, MathType.getType("22", -1).getMathType());
|
||||||
|
Assert.fail();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Assert.assertEquals(MathType.text, MathType.getType("22", 2).getMathType());
|
||||||
|
Assert.fail();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,12 +3,13 @@
|
|||||||
* For more information, please, contact se.solovyev@gmail.com
|
* For more information, please, contact se.solovyev@gmail.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator.model;
|
||||||
|
|
||||||
import bsh.EvalError;
|
import bsh.EvalError;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.solovyev.android.calculator.JsclOperation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User: serso
|
* User: serso
|
||||||
@ -19,12 +20,12 @@ public class CalculatorModelTest {
|
|||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
CalculatorModel.init(null);
|
CalculatorModel.instance.init(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEvaluate() throws Exception {
|
public void testEvaluate() throws Exception {
|
||||||
final CalculatorModel cm = CalculatorModel.getInstance();
|
final CalculatorModel cm = CalculatorModel.instance;
|
||||||
|
|
||||||
Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "2+2"));
|
Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "2+2"));
|
||||||
Assert.assertEquals("-0.7568", cm.evaluate(JsclOperation.numeric, "sin(4)"));
|
Assert.assertEquals("-0.7568", cm.evaluate(JsclOperation.numeric, "sin(4)"));
|
||||||
@ -47,7 +48,7 @@ public class CalculatorModelTest {
|
|||||||
Assert.assertEquals("-3.41007+3.41007i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)"));
|
Assert.assertEquals("-3.41007+3.41007i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)"));
|
||||||
Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)"));
|
Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)"));
|
||||||
|
|
||||||
CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("si", 5d));
|
CalculatorModel.instance.getVarsRegister().addVar(null, new Var.Builder("si", 5d));
|
||||||
Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si"));
|
Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si"));
|
||||||
try {
|
try {
|
||||||
cm.evaluate(JsclOperation.numeric, "sin");
|
cm.evaluate(JsclOperation.numeric, "sin");
|
||||||
@ -60,17 +61,17 @@ public class CalculatorModelTest {
|
|||||||
Assert.assertEquals("-23.97311", cm.evaluate(JsclOperation.numeric, "si*sin(5)si"));
|
Assert.assertEquals("-23.97311", cm.evaluate(JsclOperation.numeric, "si*sin(5)si"));
|
||||||
Assert.assertEquals("-3.30879", cm.evaluate(JsclOperation.numeric, "sisin(5si)si"));
|
Assert.assertEquals("-3.30879", cm.evaluate(JsclOperation.numeric, "sisin(5si)si"));
|
||||||
|
|
||||||
CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("s", 1d));
|
CalculatorModel.instance.getVarsRegister().addVar(null, new Var.Builder("s", 1d));
|
||||||
Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si"));
|
Assert.assertEquals("5.0", cm.evaluate(JsclOperation.numeric, "si"));
|
||||||
|
|
||||||
CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("k", 3.5d));
|
CalculatorModel.instance.getVarsRegister().addVar(null, new Var.Builder("k", 3.5d));
|
||||||
CalculatorModel.getInstance().getVarsRegister().addVar(null, new Var.Builder("k1", 4d));
|
CalculatorModel.instance.getVarsRegister().addVar(null, new Var.Builder("k1", 4d));
|
||||||
Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "k11"));
|
Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "k11"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComplexNumbers() throws Exception {
|
public void testComplexNumbers() throws Exception {
|
||||||
final CalculatorModel cm = CalculatorModel.getInstance();
|
final FromJsclTextProcessor cm = new FromJsclTextProcessor();
|
||||||
|
|
||||||
Assert.assertEquals("1.22133+23123.0i", cm.createResultForComplexNumber("1.22133232+23123*i"));
|
Assert.assertEquals("1.22133+23123.0i", cm.createResultForComplexNumber("1.22133232+23123*i"));
|
||||||
Assert.assertEquals("1.22133+1.2i", cm.createResultForComplexNumber("1.22133232+1.2*i"));
|
Assert.assertEquals("1.22133+1.2i", cm.createResultForComplexNumber("1.22133232+1.2*i"));
|
@ -4,7 +4,7 @@
|
|||||||
* or visit http://se.solovyev.org
|
* or visit http://se.solovyev.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator.model;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -18,7 +18,7 @@ public class ToJsclPreprocessorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcess() throws Exception {
|
public void testProcess() throws Exception {
|
||||||
final ToJsclPreprocessor preprocessor = new ToJsclPreprocessor();
|
final ToJsclTextProcessor preprocessor = new ToJsclTextProcessor();
|
||||||
|
|
||||||
Assert.assertEquals( "sin(4)*cos(5)", preprocessor.process("sin(4)cos(5)"));
|
Assert.assertEquals( "sin(4)*cos(5)", preprocessor.process("sin(4)cos(5)"));
|
||||||
Assert.assertEquals( "pi*sin(4)*pi*cos(sqrt(5))", preprocessor.process("πsin(4)πcos(√(5))"));
|
Assert.assertEquals( "pi*sin(4)*pi*cos(sqrt(5))", preprocessor.process("πsin(4)πcos(√(5))"));
|
||||||
@ -30,7 +30,7 @@ public class ToJsclPreprocessorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPostfixFunctionsProcessing() throws Exception {
|
public void testPostfixFunctionsProcessing() throws Exception {
|
||||||
final ToJsclPreprocessor preprocessor = new ToJsclPreprocessor();
|
final ToJsclTextProcessor preprocessor = new ToJsclTextProcessor();
|
||||||
|
|
||||||
Assert.assertEquals(-1, preprocessor.getPostfixFunctionStart("5!", 0));
|
Assert.assertEquals(-1, preprocessor.getPostfixFunctionStart("5!", 0));
|
||||||
Assert.assertEquals(0, preprocessor.getPostfixFunctionStart("!", 0));
|
Assert.assertEquals(0, preprocessor.getPostfixFunctionStart("!", 0));
|
Loading…
Reference in New Issue
Block a user