diff --git a/pom.xml b/pom.xml
index 40d7c787..e7c475ff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,9 +54,15 @@
- de.congrace
- exp4j
- 0.2.8
+ org.simpleframework
+ simple-xml
+ 2.6.1
+
+
+ stax-api
+ stax
+
+
diff --git a/res/values/default_values.xml b/res/values/default_values.xml
index 735826ac..ca207e09 100644
--- a/res/values/default_values.xml
+++ b/res/values/default_values.xml
@@ -18,4 +18,6 @@
org.solovyev.android.calculator.CalculatorModel_color_display
true
+
+ org.solovyev.android.calculator.CalculatorModel_vars
\ No newline at end of file
diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java
index 7d1b7006..b025ee62 100644
--- a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java
+++ b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java
@@ -57,7 +57,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
setContentView(R.layout.main);
try {
- this.calculatorModel = new CalculatorModel();
+ CalculatorModel.init(this);
+ this.calculatorModel = CalculatorModel.getInstance();
} catch (EvalError evalError) {
// todo serso: create serso runtime exception
throw new RuntimeException("Could not initialize interpreter!");
@@ -258,8 +259,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String s) {
dpclRegister.announce().onDragPreferencesChange(SimpleOnDragListener.getPreferences(CalculatorActivity.this));
- final NumberMapper integerNumberMapper = new NumberMapper(Integer.class);
- this.calculatorModel.setNumberOfFractionDigits(integerNumberMapper.parseValue(sharedPreferences.getString(this.getString(R.string.p_calc_result_precision_key), this.getString(R.string.p_calc_result_precision))));
+ this.calculatorModel.load(this);
final Boolean colorExpressionsInBracketsDefault = new BooleanMapper().parseValue(this.getString(R.string.p_calc_color_display));
assert colorExpressionsInBracketsDefault != null;
diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java
index 419c9c3c..bcec4bee 100644
--- a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java
+++ b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java
@@ -5,9 +5,14 @@
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;
@@ -21,16 +26,24 @@ import org.solovyev.util.math.Complex;
public class CalculatorModel {
@NotNull
- private Interpreter interpreter;
+ private final Interpreter interpreter;
private int numberOfFractionDigits = 5;
@NotNull
- public Preprocessor preprocessor = new ToJsclPreprocessor();
+ public final Preprocessor preprocessor = new ToJsclPreprocessor();
+
+ @NotNull
+ private final VarsRegister varsRegister = new VarsRegister();
+
+ private static CalculatorModel instance;
+
+ private CalculatorModel(@Nullable Context context) throws EvalError {
+ if (context != null) {
+ load(context);
+ }
- public CalculatorModel() throws EvalError {
interpreter = new Interpreter();
-
interpreter.eval(ToJsclPreprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
}
@@ -99,6 +112,15 @@ public class CalculatorModel {
return MathUtils.round(dResult, numberOfFractionDigits);
}
+ public synchronized void load(@NotNull Context context) {
+ final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ final NumberMapper integerNumberMapper = new NumberMapper(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);
@@ -112,4 +134,25 @@ public class CalculatorModel {
public void setNumberOfFractionDigits(int numberOfFractionDigits) {
this.numberOfFractionDigits = numberOfFractionDigits;
}
+
+ public static synchronized void init(@Nullable Context context) throws EvalError {
+ if ( instance == null ) {
+ instance = new CalculatorModel(context);
+ } else {
+ throw new RuntimeException("Calculator model already instantiated!");
+ }
+ }
+
+ public static CalculatorModel getInstance() {
+ if ( instance == null ) {
+ throw new RuntimeException("CalculatorModel must be instantiated!");
+ }
+
+ return instance;
+ }
+
+ @NotNull
+ public VarsRegister getVarsRegister() {
+ return varsRegister;
+ }
}
diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorVarsActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorVarsActivity.java
index 8b1b2048..225cd54b 100644
--- a/src/main/java/org/solovyev/android/calculator/CalculatorVarsActivity.java
+++ b/src/main/java/org/solovyev/android/calculator/CalculatorVarsActivity.java
@@ -30,10 +30,8 @@ public class CalculatorVarsActivity extends ListActivity {
setTheme(android.R.style.Theme_Dialog);
- final List vars = new ArrayList();
- vars.add(new VariableContainer("e", 2.71, true));
- vars.add(new VariableContainer("π", 3.14, true));
- setListAdapter(new ArrayAdapter(this, R.layout.var, R.id.var_text, vars));
+ final List vars = new ArrayList(CalculatorModel.getInstance().getVarsRegister().getVars());
+ setListAdapter(new ArrayAdapter(this, R.layout.var, R.id.var_text, vars));
final ListView lv = getListView();
lv.setTextFilterEnabled(true);
@@ -42,7 +40,7 @@ public class CalculatorVarsActivity extends ListActivity {
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
final Intent intent = new Intent(CalculatorActivity.INSERT_TEXT_INTENT);
- intent.putExtra(CalculatorActivity.INSERT_TEXT_INTENT_EXTRA_STRING, vars.get(position).getId());
+ intent.putExtra(CalculatorActivity.INSERT_TEXT_INTENT_EXTRA_STRING, vars.get(position).getName());
sendOrderedBroadcast(intent, null);
CalculatorVarsActivity.this.finish();
diff --git a/src/main/java/org/solovyev/android/calculator/Var.java b/src/main/java/org/solovyev/android/calculator/Var.java
new file mode 100644
index 00000000..2f0d4a7f
--- /dev/null
+++ b/src/main/java/org/solovyev/android/calculator/Var.java
@@ -0,0 +1,89 @@
+/*
+ * 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 org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.simpleframework.xml.Element;
+import org.simpleframework.xml.Root;
+
+/**
+ * User: serso
+ * Date: 9/28/11
+ * Time: 11:22 PM
+ */
+
+@Root
+public class Var {
+
+ @Element
+ @NotNull
+ private String name;
+
+ @Element
+ @NotNull
+ private String value;
+
+ private boolean system;
+
+ @Element(required = false)
+ @Nullable
+ private String description;
+
+ public Var() {
+ }
+
+ public Var(@NotNull String name, @NotNull Double value, boolean system) {
+ this(name, String.valueOf(value), system);
+ }
+
+ public Var(@NotNull String name, @NotNull String value, boolean system) {
+ this.name = name;
+ this.value = value;
+ this.system = system;
+ }
+
+ @NotNull
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(@NotNull String value) {
+ this.value = value;
+ }
+
+ public boolean isSystem() {
+ return system;
+ }
+
+ public void setSystem(boolean system) {
+ this.system = system;
+ }
+
+ @NotNull
+ public String getName() {
+ return name;
+ }
+
+ public void setName(@NotNull String name) {
+ this.name = name;
+ }
+
+ @Nullable
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(@Nullable String description) {
+ this.description = description;
+ }
+
+ @Override
+ public String toString() {
+ return getName() + " = " + value;
+ }
+}
diff --git a/src/main/java/org/solovyev/android/calculator/VariableContainer.java b/src/main/java/org/solovyev/android/calculator/VariableContainer.java
deleted file mode 100644
index cbeabdda..00000000
--- a/src/main/java/org/solovyev/android/calculator/VariableContainer.java
+++ /dev/null
@@ -1,51 +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;
-
-import org.jetbrains.annotations.NotNull;
-import org.solovyev.common.definitions.Identity;
-
-/**
- * User: serso
- * Date: 9/28/11
- * Time: 11:22 PM
- */
-public class VariableContainer extends Identity{
-
- @NotNull
- private Double value;
-
- private boolean system;
-
- public VariableContainer(@NotNull String id, @NotNull Double value, boolean system) {
- super(id);
- this.value = value;
- this.system = system;
- }
-
- @NotNull
- public Double getValue() {
- return value;
- }
-
- public void setValue(@NotNull Double value) {
- this.value = value;
- }
-
- public boolean isSystem() {
- return system;
- }
-
- public void setSystem(boolean system) {
- this.system = system;
- }
-
- @Override
- public String toString() {
- return getId() + " = " + value;
- }
-}
diff --git a/src/main/java/org/solovyev/android/calculator/Vars.java b/src/main/java/org/solovyev/android/calculator/Vars.java
new file mode 100644
index 00000000..bf90e2b5
--- /dev/null
+++ b/src/main/java/org/solovyev/android/calculator/Vars.java
@@ -0,0 +1,27 @@
+package org.solovyev.android.calculator;
+
+import org.simpleframework.xml.ElementList;
+import org.simpleframework.xml.Root;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: serso
+ * Date: 9/29/11
+ * Time: 5:19 PM
+ */
+
+@Root
+public class Vars {
+
+ @ElementList
+ private final List vars = new ArrayList();
+
+ public Vars() {
+ }
+
+ public List getVars() {
+ return vars;
+ }
+}
diff --git a/src/main/java/org/solovyev/android/calculator/VarsRegister.java b/src/main/java/org/solovyev/android/calculator/VarsRegister.java
new file mode 100644
index 00000000..ed7822a6
--- /dev/null
+++ b/src/main/java/org/solovyev/android/calculator/VarsRegister.java
@@ -0,0 +1,117 @@
+package org.solovyev.android.calculator;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.simpleframework.xml.Serializer;
+import org.simpleframework.xml.core.Persister;
+import org.solovyev.android.calculator.math.MathEntityType;
+import org.solovyev.android.view.widgets.SimpleOnDragListener;
+import org.solovyev.common.utils.CollectionsUtils;
+import org.solovyev.common.utils.Finder;
+
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * User: serso
+ * Date: 9/29/11
+ * Time: 4:57 PM
+ */
+public class VarsRegister {
+
+ @NotNull
+ private final Set vars = new HashSet();
+
+ @NotNull
+ private final Set systemVars = new HashSet();
+
+ @NotNull
+ public Set getVars() {
+ return Collections.unmodifiableSet(vars);
+ }
+
+ @NotNull
+ public Set getSystemVars() {
+ return Collections.unmodifiableSet(systemVars);
+ }
+
+ @Nullable
+ public Var getVar(@NotNull final String name) {
+ return CollectionsUtils.get(vars, new Finder() {
+ @Override
+ public boolean isFound(@Nullable Var var) {
+ return var != null && name.equals(var.getName());
+ }
+ });
+ }
+
+ public void merge(@NotNull final List varsParam) {
+ final Set result = new HashSet(varsParam);
+
+ for (Var systemVar : systemVars) {
+ if (!result.contains(systemVar)) {
+ result.add(systemVar);
+ }
+ }
+
+ vars.clear();
+ vars.addAll(result);
+ }
+
+ public synchronized void load(@NotNull Context context) {
+ final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ this.vars.clear();
+ this.systemVars.clear();
+
+ final String value = preferences.getString(context.getString(R.string.p_calc_vars), null);
+ if (value != null) {
+ final Serializer serializer = new Persister();
+ try {
+ final Vars vars = serializer.read(Vars.class, value);
+ this.vars.addAll(vars.getVars());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ for (Var systemVar : MathEntityType.constants) {
+
+ systemVars.add(systemVar);
+ if (!vars.contains(systemVar)) {
+ vars.add(systemVar);
+ }
+ }
+ }
+
+ public synchronized void save(@NotNull Context context) {
+ final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
+ final SharedPreferences.Editor editor = settings.edit();
+
+ final Vars vars = new Vars();
+ for (Var var : this.vars) {
+ if (!var.isSystem()) {
+ vars.getVars().add(var);
+ }
+ }
+
+ final StringWriter sw = new StringWriter();
+ final Serializer serializer = new Persister();
+ try {
+ serializer.write(vars, sw);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ editor.putString(context.getString(R.string.p_calc_vars),sw.toString());
+
+ editor.commit();
+ }
+}
diff --git a/src/main/java/org/solovyev/android/calculator/math/MathEntityType.java b/src/main/java/org/solovyev/android/calculator/math/MathEntityType.java
index b6db3d24..3f81e051 100644
--- a/src/main/java/org/solovyev/android/calculator/math/MathEntityType.java
+++ b/src/main/java/org/solovyev/android/calculator/math/MathEntityType.java
@@ -5,14 +5,18 @@
package org.solovyev.android.calculator.math;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.solovyev.android.calculator.Var;
+import org.solovyev.common.utils.CollectionsUtils;
+import org.solovyev.common.utils.Finder;
+
+import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
public enum MathEntityType {
digit,
@@ -25,7 +29,14 @@ public enum MathEntityType {
group_symbols,
group_symbol;
- public static final List constants = Arrays.asList('e', 'π', 'i');
+ public static final List constants;
+ static {
+ final List result = new ArrayList();
+ result.add(new Var("e", Math.exp(1), true));
+ result.add(new Var("π", Math.PI, true));
+ result.add(new Var("i", "√(-1)", true));
+ constants = Collections.unmodifiableList(result);
+ }
public static final List dots = Arrays.asList('.');
@@ -72,7 +83,7 @@ public enum MathEntityType {
}
@Nullable
- public static MathEntityType getType(char ch) {
+ public static MathEntityType getType(final char ch) {
MathEntityType result = null;
if ( Character.isDigit(ch) ) {
@@ -85,11 +96,22 @@ public enum MathEntityType {
result = MathEntityType.binary_operation;
} else if ( singleGroupSymbols.contains(ch) ) {
result = MathEntityType.group_symbol;
- } else if ( constants.contains(ch) ) {
+ } else if (isConstant(ch)) {
result = MathEntityType.constant;
} else if ( dots.contains(ch) ) {
result = MathEntityType.dot;
}
return result;
}
+
+ private static boolean isConstant(final char ch) {
+ final String name = String.valueOf(ch);
+
+ return CollectionsUtils.get(constants, new Finder() {
+ @Override
+ public boolean isFound(@Nullable Var var) {
+ return var != null && var.getName().equals(name);
+ }
+ }) != null;
+ }
}
diff --git a/src/test/java/org/solovyev/android/calculator/CalculatorModelTest.java b/src/test/java/org/solovyev/android/calculator/CalculatorModelTest.java
index 1b397501..ff2930bb 100644
--- a/src/test/java/org/solovyev/android/calculator/CalculatorModelTest.java
+++ b/src/test/java/org/solovyev/android/calculator/CalculatorModelTest.java
@@ -6,6 +6,8 @@
package org.solovyev.android.calculator;
import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
/**
@@ -14,9 +16,15 @@ import org.junit.Test;
* Time: 9:47 PM
*/
public class CalculatorModelTest {
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ CalculatorModel.init(null);
+ }
+
@Test
public void testEvaluate() throws Exception {
- final CalculatorModel cm = new CalculatorModel();
+ final CalculatorModel cm = CalculatorModel.getInstance();
Assert.assertEquals("4.0", cm.evaluate(JsclOperation.numeric, "2+2"));
Assert.assertEquals("-0.7568", cm.evaluate(JsclOperation.numeric, "sin(4)"));
@@ -43,7 +51,7 @@ public class CalculatorModelTest {
@Test
public void testComplexNumbers() throws Exception {
- final CalculatorModel cm = new CalculatorModel();
+ final CalculatorModel cm = CalculatorModel.getInstance();
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"));