From 3a879b0de87ba7765b2a42d2e0301a0898e17fc8 Mon Sep 17 00:00:00 2001 From: serso Date: Wed, 20 Jan 2016 21:51:21 +0100 Subject: [PATCH] FunctionsRegistry refactor --- .../android/calculator/AppModule.java | 24 ++- .../calculator/BaseEntitiesRegistry.java | 41 +++- .../solovyev/android/calculator/Engine.java | 57 +++--- .../android/calculator/EntitiesRegistry.java | 2 +- .../android/calculator/FunctionCategory.java | 14 +- .../android/calculator/FunctionsRegistry.java | 193 +++++++++++++----- .../android/calculator/OperatorsRegistry.java | 22 +- .../calculator/PostfixFunctionsRegistry.java | 23 +-- .../android/calculator/VarsRegistry.java | 14 +- .../calculator/function/CppFunction.java | 187 +++++++++++++++++ .../function/EditFunctionFragment.java | 55 ++--- .../function/FunctionBuilderAdapter.java | 19 +- .../function/FunctionEditorSaver.java | 31 ++- .../android/calculator/history/History.java | 20 +- .../calculator/history/HistoryState.java | 12 +- .../calculator/history/RecentHistory.java | 31 --- .../android/calculator/json/Json.java | 74 +++++++ .../android/calculator/json/Jsonable.java | 11 + .../android/calculator/model/EntityDao.java | 79 +++---- .../android/calculator/model/Functions.java | 44 ---- .../{AFunction.java => OldFunction.java} | 30 ++- .../calculator/model/OldFunctions.java | 65 ++++++ .../calculator/CalculatorTestUtils.java | 23 +-- .../calculator/history/HistoryTest.java | 3 +- ...nctionsTest.java => OldFunctionsTest.java} | 42 ++-- 25 files changed, 689 insertions(+), 427 deletions(-) create mode 100644 app/src/main/java/org/solovyev/android/calculator/function/CppFunction.java create mode 100644 app/src/main/java/org/solovyev/android/calculator/json/Json.java create mode 100644 app/src/main/java/org/solovyev/android/calculator/json/Jsonable.java delete mode 100644 app/src/main/java/org/solovyev/android/calculator/model/Functions.java rename app/src/main/java/org/solovyev/android/calculator/model/{AFunction.java => OldFunction.java} (92%) create mode 100644 app/src/main/java/org/solovyev/android/calculator/model/OldFunctions.java rename app/src/test/java/org/solovyev/android/calculator/model/{FunctionsTest.java => OldFunctionsTest.java} (81%) diff --git a/app/src/main/java/org/solovyev/android/calculator/AppModule.java b/app/src/main/java/org/solovyev/android/calculator/AppModule.java index af9ef661..06f25c32 100644 --- a/app/src/main/java/org/solovyev/android/calculator/AppModule.java +++ b/app/src/main/java/org/solovyev/android/calculator/AppModule.java @@ -6,22 +6,19 @@ import android.os.Handler; import android.os.Looper; import android.preference.PreferenceManager; import android.support.annotation.NonNull; - import com.squareup.otto.Bus; - +import dagger.Module; +import dagger.Provides; +import jscl.JsclMathEngine; import org.solovyev.android.UiThreadExecutor; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; - import javax.annotation.Nonnull; import javax.inject.Named; import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; @Module public class AppModule { @@ -89,6 +86,7 @@ public class AppModule { return Executors.newFixedThreadPool(5, new ThreadFactory() { @NonNull private final AtomicInteger counter = new AtomicInteger(); + @Override public Thread newThread(@Nonnull Runnable r) { return new Thread(r, "Background #" + counter.getAndIncrement()); @@ -109,6 +107,12 @@ public class AppModule { return new UiThreadExecutor(); } + @Provides + @Singleton + JsclMathEngine provideJsclMathEngine() { + return JsclMathEngine.getInstance(); + } + private static class AppBus extends Bus { @NonNull diff --git a/app/src/main/java/org/solovyev/android/calculator/BaseEntitiesRegistry.java b/app/src/main/java/org/solovyev/android/calculator/BaseEntitiesRegistry.java index 850b7ac1..fc221cc9 100644 --- a/app/src/main/java/org/solovyev/android/calculator/BaseEntitiesRegistry.java +++ b/app/src/main/java/org/solovyev/android/calculator/BaseEntitiesRegistry.java @@ -22,18 +22,20 @@ package org.solovyev.android.calculator; +import android.content.Context; +import android.content.res.Resources; +import org.solovyev.android.Check; import org.solovyev.android.calculator.model.EntityDao; import org.solovyev.common.JBuilder; import org.solovyev.common.math.MathEntity; import org.solovyev.common.math.MathRegistry; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - public abstract class BaseEntitiesRegistry implements EntitiesRegistry { @Nonnull @@ -42,12 +44,12 @@ public abstract class BaseEntitiesRegistry entityDao; + @Nullable + protected final EntityDao

entityDao; protected BaseEntitiesRegistry(@Nonnull MathRegistry mathRegistry, @Nonnull String prefix, - @Nonnull EntityDao

entityDao) { + @Nullable EntityDao

entityDao) { this.mathRegistry = mathRegistry; this.prefix = prefix; this.entityDao = entityDao; @@ -70,10 +72,28 @@ public abstract class BaseEntitiesRegistry persistenceContainer = entityDao.load(); final List

notCreatedEntities = new ArrayList

(); @@ -112,6 +132,9 @@ public abstract class BaseEntitiesRegistry container = createPersistenceContainer(); for (T entity : this.getEntities()) { @@ -123,7 +146,7 @@ public abstract class BaseEntitiesRegistry varsRegistry; - @Nonnull - private final EntitiesRegistry functionsRegistry; + @Nonnull private final EntitiesRegistry operatorsRegistry; @Nonnull @@ -74,10 +66,12 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene Bus bus; @Inject ErrorReporter errorReporter; + @Inject + FunctionsRegistry functionsRegistry; @Nonnull private String multiplicationSign = Preferences.multiplicationSign.getDefaultValue(); - public Engine(@Nonnull MathEngine mathEngine, @Nonnull EntitiesRegistry varsRegistry, @Nonnull EntitiesRegistry functionsRegistry, @Nonnull EntitiesRegistry operatorsRegistry, @Nonnull EntitiesRegistry postfixFunctionsRegistry) { + public Engine(@Nonnull MathEngine mathEngine, @Nonnull EntitiesRegistry varsRegistry, @Nonnull FunctionsRegistry functionsRegistry, @Nonnull EntitiesRegistry operatorsRegistry, @Nonnull EntitiesRegistry postfixFunctionsRegistry) { this.mathEngine = mathEngine; this.varsRegistry = varsRegistry; this.functionsRegistry = functionsRegistry; @@ -86,16 +80,15 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene } @Inject - public Engine(@Nonnull Application application) { - this.mathEngine = JsclMathEngine.getInstance(); + public Engine(@Nonnull SharedPreferences preferences, @Nonnull JsclMathEngine mathEngine) { + this.mathEngine = mathEngine; this.mathEngine.setRoundResult(true); this.mathEngine.setUseGroupingSeparator(true); - this.varsRegistry = new VarsRegistry(mathEngine.getConstantsRegistry(), new EntityDao<>("org.solovyev.android.calculator.CalculatorModel_vars", application, Vars.class)); - this.functionsRegistry = new FunctionsRegistry(mathEngine.getFunctionsRegistry(), new EntityDao<>("org.solovyev.android.calculator.CalculatorModel_functions", application, Functions.class)); - this.operatorsRegistry = new OperatorsRegistry(mathEngine.getOperatorsRegistry(), new EntityDao<>(null, application, null)); - this.postfixFunctionsRegistry = new PostfixFunctionsRegistry(mathEngine.getPostfixFunctionsRegistry(), new EntityDao<>(null, application, null)); + this.varsRegistry = new VarsRegistry(mathEngine.getConstantsRegistry(), new EntityDao<>("org.solovyev.android.calculator.CalculatorModel_vars", Vars.class, preferences)); + this.operatorsRegistry = new OperatorsRegistry(mathEngine.getOperatorsRegistry()); + this.postfixFunctionsRegistry = new PostfixFunctionsRegistry(mathEngine.getPostfixFunctionsRegistry()); } private static void migratePreference(@Nonnull SharedPreferences preferences, @Nonnull BooleanPreference preference, @Nonnull String oldKey, @Nonnull SharedPreferences.Editor editor) { @@ -118,7 +111,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene } @Nonnull - public EntitiesRegistry getFunctionsRegistry() { + public FunctionsRegistry getFunctionsRegistry() { return functionsRegistry; } @@ -175,15 +168,15 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene } private void initAsync() { - safeLoadRegistry(varsRegistry); - safeLoadRegistry(functionsRegistry); - safeLoadRegistry(operatorsRegistry); - safeLoadRegistry(postfixFunctionsRegistry); + init(varsRegistry); + init(functionsRegistry); + init(operatorsRegistry); + init(postfixFunctionsRegistry); } - private void safeLoadRegistry(@Nonnull EntitiesRegistry registry) { + private void init(@Nonnull EntitiesRegistry registry) { try { - registry.load(); + registry.init(); } catch (Exception e) { errorReporter.onException(e); } diff --git a/app/src/main/java/org/solovyev/android/calculator/EntitiesRegistry.java b/app/src/main/java/org/solovyev/android/calculator/EntitiesRegistry.java index 6da58d59..95971203 100644 --- a/app/src/main/java/org/solovyev/android/calculator/EntitiesRegistry.java +++ b/app/src/main/java/org/solovyev/android/calculator/EntitiesRegistry.java @@ -36,7 +36,7 @@ public interface EntitiesRegistry extends MathRegistry @Nullable String getCategory(@Nonnull E entity); - void load(); + void init(); void save(); } diff --git a/app/src/main/java/org/solovyev/android/calculator/FunctionCategory.java b/app/src/main/java/org/solovyev/android/calculator/FunctionCategory.java index 1184b0fe..8b28eb70 100644 --- a/app/src/main/java/org/solovyev/android/calculator/FunctionCategory.java +++ b/app/src/main/java/org/solovyev/android/calculator/FunctionCategory.java @@ -22,18 +22,14 @@ package org.solovyev.android.calculator; -import org.solovyev.common.collections.Collections; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; - -import javax.annotation.Nonnull; - import jscl.math.function.ArcTrigonometric; import jscl.math.function.Comparison; import jscl.math.function.Function; import jscl.math.function.Trigonometric; +import org.solovyev.common.collections.Collections; + +import javax.annotation.Nonnull; +import java.util.*; /** * User: serso @@ -51,7 +47,7 @@ public enum FunctionCategory { hyperbolic_trigonometric(300) { - private final List names = Arrays.asList("sinh", "cosh", "tanh", "coth", "asinh", "acosh", "atanh", "acoth"); + private final Set names = new HashSet<>(Arrays.asList("sinh", "cosh", "tanh", "coth", "asinh", "acosh", "atanh", "acoth")); @Override public boolean isInCategory(@Nonnull Function function) { diff --git a/app/src/main/java/org/solovyev/android/calculator/FunctionsRegistry.java b/app/src/main/java/org/solovyev/android/calculator/FunctionsRegistry.java index ca3b5422..12524a50 100644 --- a/app/src/main/java/org/solovyev/android/calculator/FunctionsRegistry.java +++ b/app/src/main/java/org/solovyev/android/calculator/FunctionsRegistry.java @@ -22,32 +22,45 @@ package org.solovyev.android.calculator; -import org.solovyev.android.calculator.function.FunctionBuilderAdapter; -import org.solovyev.android.calculator.model.AFunction; -import org.solovyev.android.calculator.model.Functions; -import org.solovyev.android.calculator.model.MathEntityBuilder; -import org.solovyev.android.calculator.model.EntityDao; -import org.solovyev.common.JBuilder; -import org.solovyev.common.math.MathRegistry; -import org.solovyev.common.text.Strings; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import jscl.CustomFunctionCalculationException; +import android.app.Application; +import android.content.SharedPreferences; +import android.os.Handler; +import android.support.annotation.NonNull; +import jscl.JsclMathEngine; import jscl.math.function.CustomFunction; import jscl.math.function.Function; import jscl.math.function.IFunction; +import org.json.JSONArray; +import org.json.JSONException; +import org.simpleframework.xml.Serializer; +import org.simpleframework.xml.core.Persister; +import org.solovyev.android.Check; +import org.solovyev.android.calculator.function.CppFunction; +import org.solovyev.android.calculator.function.FunctionBuilderAdapter; +import org.solovyev.android.calculator.json.Json; +import org.solovyev.android.calculator.model.OldFunction; +import org.solovyev.android.calculator.model.OldFunctions; +import org.solovyev.android.io.FileSaver; +import org.solovyev.common.JBuilder; +import org.solovyev.common.text.Strings; -public class FunctionsRegistry extends BaseEntitiesRegistry { +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.Executor; + +import static android.text.TextUtils.isEmpty; + +@Singleton +public class FunctionsRegistry extends BaseEntitiesRegistry { @Nonnull - private static final Map substitutes = new HashMap(); + private static final Map substitutes = new HashMap<>(); @Nonnull private static final String FUNCTION_DESCRIPTION_PREFIX = "c_fun_description_"; @@ -55,30 +68,42 @@ public class FunctionsRegistry extends BaseEntitiesRegistry substitutes.put("√", "sqrt"); } - public FunctionsRegistry(@Nonnull MathRegistry functionsRegistry, - @Nonnull EntityDao entityDao) { - super(functionsRegistry, FUNCTION_DESCRIPTION_PREFIX, entityDao); + @NonNull + private final WriteTask writeTask = new WriteTask(); + @Inject + @Named(AppModule.THREAD_BACKGROUND) + Executor backgroundThread; + @Inject + Handler handler; + @Inject + ErrorReporter errorReporter; + @Inject + Calculator calculator; + @Inject + SharedPreferences preferences; + @Inject + Application application; + + @Inject + public FunctionsRegistry(@Nonnull JsclMathEngine mathEngine) { + super(mathEngine.getFunctionsRegistry(), FUNCTION_DESCRIPTION_PREFIX, null); } - public static void saveFunction(@Nonnull EntitiesRegistry registry, - @Nonnull MathEntityBuilder builder, - @Nullable IFunction editedInstance, - @Nonnull Object source, boolean save) throws CustomFunctionCalculationException, AFunction.Builder.CreationException { - final Function addedFunction = registry.add(builder); - - if (save) { - registry.save(); - } - + public void add(@NonNull FunctionBuilderAdapter builder, @Nullable IFunction editedInstance, Object source) { + final Function function = add(builder); + save(); if (editedInstance == null) { - Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.function_added, addedFunction, source); + calculator.fireCalculatorEvent(CalculatorEventType.function_added, function, source); } else { - Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.function_changed, ChangeImpl.newInstance(editedInstance, addedFunction), source); + calculator.fireCalculatorEvent(CalculatorEventType.function_changed, ChangeImpl.newInstance(editedInstance, function), source); } } @Override - public void load() { + public void init() { + Check.isNotMainThread(); + migrateOldFunctions(); + add(new CustomFunction.Builder(true, "log", Arrays.asList("base", "x"), "ln(x)/ln(base)")); add(new CustomFunction.Builder(true, "√3", Collections.singletonList("x"), "x^(1/3)")); add(new CustomFunction.Builder(true, "√4", Collections.singletonList("x"), "x^(1/4)")); @@ -86,7 +111,50 @@ public class FunctionsRegistry extends BaseEntitiesRegistry add(new CustomFunction.Builder(true, "re", Collections.singletonList("x"), "(x+conjugate(x))/2")); add(new CustomFunction.Builder(true, "im", Collections.singletonList("x"), "(x-conjugate(x))/(2*i)")); - super.load(); + for (CppFunction function : loadFunctions()) { + final CustomFunction.Builder builder = new CustomFunction.Builder(function.getName(), function.getParameters(), function.getBody()); + builder.setDescription(function.getDescription()); + add(builder); + } + } + + @NonNull + private List loadFunctions() { + try { + return Json.load(getFunctionsFile(), CppFunction.JSON_CREATOR); + } catch (IOException | JSONException e) { + errorReporter.onException(e); + } + return Collections.emptyList(); + } + + private void migrateOldFunctions() { + final String xml = preferences.getString(OldFunctions.PREFS_KEY, null); + if (isEmpty(xml)) { + return; + } + try { + final Serializer serializer = new Persister(); + final OldFunctions oldFunctions = serializer.read(OldFunctions.class, xml); + if (oldFunctions != null) { + List functions = OldFunctions.toCppFunctions(oldFunctions); + FileSaver.save(getFunctionsFile(), Json.toJson(functions).toString()); + } + preferences.edit().remove(OldFunctions.PREFS_KEY).apply(); + } catch (Exception e) { + errorReporter.onException(e); + } + } + + @Override + public synchronized void save() { + handler.removeCallbacks(writeTask); + handler.postDelayed(writeTask, 500); + } + + @NonNull + private File getFunctionsFile() { + return new File(application.getFilesDir(), "functions.json"); } @Nonnull @@ -111,29 +179,28 @@ public class FunctionsRegistry extends BaseEntitiesRegistry public String getDescription(@Nonnull String name) { final Function function = get(name); - String result = null; + String description = null; if (function instanceof CustomFunction) { - result = ((CustomFunction) function).getDescription(); + description = ((CustomFunction) function).getDescription(); } - if (Strings.isEmpty(result)) { - result = super.getDescription(name); + if (!Strings.isEmpty(description)) { + return description; } - - return result; + return super.getDescription(name); } @Nonnull @Override - protected JBuilder createBuilder(@Nonnull AFunction function) { - return new FunctionBuilderAdapter(new AFunction.Builder(function)); + protected JBuilder createBuilder(@Nonnull OldFunction function) { + return new FunctionBuilderAdapter(new OldFunction.Builder(function)); } @Override - protected AFunction transform(@Nonnull Function function) { + protected OldFunction transform(@Nonnull Function function) { if (function instanceof CustomFunction) { - return AFunction.fromIFunction((CustomFunction) function); + return OldFunction.fromIFunction((CustomFunction) function); } else { return null; } @@ -141,7 +208,35 @@ public class FunctionsRegistry extends BaseEntitiesRegistry @Nonnull @Override - protected PersistedEntitiesContainer createPersistenceContainer() { - return new Functions(); + protected PersistedEntitiesContainer createPersistenceContainer() { + return new OldFunctions(); + } + + private class WriteTask implements Runnable { + + @Override + public void run() { + Check.isMainThread(); + final List functions = new ArrayList<>(); + for (Function function : getEntities()) { + if (function.isSystem()) { + continue; + } + if (function instanceof CustomFunction) { + functions.add(CppFunction.builder((CustomFunction) function).build()); + } + } + backgroundThread.execute(new Runnable() { + @Override + public void run() { + final JSONArray array = Json.toJson(functions); + try { + FileSaver.save(getFunctionsFile(), array.toString()); + } catch (IOException e) { + errorReporter.onException(e); + } + } + }); + } } } diff --git a/app/src/main/java/org/solovyev/android/calculator/OperatorsRegistry.java b/app/src/main/java/org/solovyev/android/calculator/OperatorsRegistry.java index d1d2e419..38aa7f66 100644 --- a/app/src/main/java/org/solovyev/android/calculator/OperatorsRegistry.java +++ b/app/src/main/java/org/solovyev/android/calculator/OperatorsRegistry.java @@ -22,17 +22,14 @@ package org.solovyev.android.calculator; -import org.solovyev.android.calculator.model.EntityDao; +import jscl.math.operator.Operator; import org.solovyev.common.JBuilder; import org.solovyev.common.math.MathRegistry; +import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; -import javax.annotation.Nonnull; - -import jscl.math.operator.Operator; - public class OperatorsRegistry extends BaseEntitiesRegistry { @Nonnull @@ -49,9 +46,8 @@ public class OperatorsRegistry extends BaseEntitiesRegistry functionsRegistry, - @Nonnull EntityDao entityDao) { - super(functionsRegistry, OPERATOR_DESCRIPTION_PREFIX, entityDao); + public OperatorsRegistry(@Nonnull MathRegistry functionsRegistry) { + super(functionsRegistry, OPERATOR_DESCRIPTION_PREFIX, null); } @Nonnull @@ -70,22 +66,12 @@ public class OperatorsRegistry extends BaseEntitiesRegistry createBuilder(@Nonnull PersistedEntity entity) { return null; //To change body of implemented methods use File | Settings | File Templates. } - @Override - public void save() { - // not supported yet - } - @Override protected PersistedEntity transform(@Nonnull Operator entity) { return null; //To change body of implemented methods use File | Settings | File Templates. diff --git a/app/src/main/java/org/solovyev/android/calculator/PostfixFunctionsRegistry.java b/app/src/main/java/org/solovyev/android/calculator/PostfixFunctionsRegistry.java index 9af51fd1..dd230c11 100644 --- a/app/src/main/java/org/solovyev/android/calculator/PostfixFunctionsRegistry.java +++ b/app/src/main/java/org/solovyev/android/calculator/PostfixFunctionsRegistry.java @@ -22,17 +22,14 @@ package org.solovyev.android.calculator; -import org.solovyev.android.calculator.model.EntityDao; +import jscl.math.operator.Operator; import org.solovyev.common.JBuilder; import org.solovyev.common.math.MathRegistry; +import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; -import javax.annotation.Nonnull; - -import jscl.math.operator.Operator; - public class PostfixFunctionsRegistry extends BaseEntitiesRegistry { @Nonnull @@ -47,12 +44,10 @@ public class PostfixFunctionsRegistry extends BaseEntitiesRegistry functionsRegistry, - @Nonnull EntityDao entityDao) { - super(functionsRegistry, POSTFIX_FUNCTION_DESCRIPTION_PREFIX, entityDao); + public PostfixFunctionsRegistry(@Nonnull MathRegistry functionsRegistry) { + super(functionsRegistry, POSTFIX_FUNCTION_DESCRIPTION_PREFIX, null); } - @Nonnull @Override protected Map getSubstitutes() { @@ -69,22 +64,12 @@ public class PostfixFunctionsRegistry extends BaseEntitiesRegistry createBuilder(@Nonnull PersistedEntity entity) { throw new UnsupportedOperationException(); } - @Override - public void save() { - // not supported yet - } - @Override protected PersistedEntity transform(@Nonnull Operator entity) { return null; diff --git a/app/src/main/java/org/solovyev/android/calculator/VarsRegistry.java b/app/src/main/java/org/solovyev/android/calculator/VarsRegistry.java index b37456a4..c1b536c5 100644 --- a/app/src/main/java/org/solovyev/android/calculator/VarsRegistry.java +++ b/app/src/main/java/org/solovyev/android/calculator/VarsRegistry.java @@ -22,21 +22,19 @@ package org.solovyev.android.calculator; -import org.solovyev.android.calculator.model.MathEntityBuilder; +import jscl.math.function.IConstant; import org.solovyev.android.calculator.model.EntityDao; +import org.solovyev.android.calculator.model.MathEntityBuilder; import org.solovyev.android.calculator.model.Var; import org.solovyev.android.calculator.model.Vars; import org.solovyev.common.JBuilder; import org.solovyev.common.math.MathEntity; import org.solovyev.common.math.MathRegistry; -import java.util.HashMap; -import java.util.Map; - import javax.annotation.Nonnull; import javax.annotation.Nullable; - -import jscl.math.function.IConstant; +import java.util.HashMap; +import java.util.Map; public class VarsRegistry extends BaseEntitiesRegistry { @@ -82,8 +80,8 @@ public class VarsRegistry extends BaseEntitiesRegistry { return substitutes; } - public synchronized void load() { - super.load(); + public synchronized void init() { + super.init(); tryToAddAuxVar("x"); tryToAddAuxVar("y"); diff --git a/app/src/main/java/org/solovyev/android/calculator/function/CppFunction.java b/app/src/main/java/org/solovyev/android/calculator/function/CppFunction.java new file mode 100644 index 00000000..61c94420 --- /dev/null +++ b/app/src/main/java/org/solovyev/android/calculator/function/CppFunction.java @@ -0,0 +1,187 @@ +package org.solovyev.android.calculator.function; + +import android.support.annotation.NonNull; +import android.text.TextUtils; +import jscl.math.function.IFunction; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.solovyev.android.Check; +import org.solovyev.android.calculator.json.Json; +import org.solovyev.android.calculator.json.Jsonable; +import org.solovyev.common.text.Strings; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class CppFunction implements Jsonable { + + public static final Json.Creator JSON_CREATOR = new Json.Creator() { + @NonNull + @Override + public CppFunction create(@NonNull JSONObject json) throws JSONException { + return new CppFunction(json); + } + }; + private static final String JSON_NAME = "n"; + private static final String JSON_BODY = "b"; + private static final String JSON_PARAMETERS = "ps"; + private static final String JSON_DESCRIPTION = "d"; + @Nonnull + protected final List parameters = new ArrayList<>(); + @Nonnull + protected String name; + @Nonnull + protected String body; + @Nonnull + protected String description = ""; + + private CppFunction(@Nonnull String name, @Nonnull String body) { + Check.isNotEmpty(name); + Check.isNotEmpty(body); + this.name = name; + this.body = body; + } + + private CppFunction(@NonNull JSONObject json) throws JSONException { + name = json.getString(JSON_NAME); + body = json.getString(JSON_BODY); + final JSONArray array = json.optJSONArray(JSON_PARAMETERS); + if (array != null) { + for (int i = 0; i < array.length(); i++) { + final String parameter = array.getString(i); + if (!TextUtils.isEmpty(parameter)) { + parameters.add(parameter); + } + } + } + description = json.optString(JSON_DESCRIPTION, ""); + } + + private CppFunction(@NonNull CppFunction that) { + name = that.name; + body = that.body; + description = that.description; + parameters.addAll(that.parameters); + } + + private CppFunction(@NonNull IFunction that) { + name = that.getName(); + body = that.getContent(); + description = Strings.getNotEmpty(that.getDescription(), ""); + parameters.addAll(that.getParameterNames()); + } + + @Nonnull + public static Builder builder(@Nonnull String name, @Nonnull String body) { + return new Builder(name, body); + } + + @Nonnull + public static Builder builder(@Nonnull CppFunction function) { + return new Builder(function); + } + + @Nonnull + public static Builder builder(@Nonnull IFunction function) { + return new Builder(function); + } + + @Nonnull + @Override + public JSONObject toJson() throws JSONException { + final JSONObject json = new JSONObject(); + json.put(JSON_NAME, name); + json.put(JSON_BODY, body); + if (!parameters.isEmpty()) { + final JSONArray array = new JSONArray(); + int j = 0; + for (int i = 0; i < parameters.size(); i++) { + final String parameter = parameters.get(i); + if (!TextUtils.isEmpty(parameter)) { + array.put(j++, parameter); + } + } + json.put(JSON_PARAMETERS, array); + } + if (!TextUtils.isEmpty(description)) { + json.put(JSON_DESCRIPTION, description); + } + return json; + } + + @Nonnull + public String getBody() { + return body; + } + + @Nonnull + public String getDescription() { + return description; + } + + @Nonnull + public List getParameters() { + return parameters; + } + + @Nonnull + public String getName() { + return name; + } + + public static final class Builder extends CppFunction { + + private boolean built; + + private Builder(@Nonnull String name, @Nonnull String body) { + super(name, body); + } + + public Builder(@NonNull CppFunction function) { + super(function); + } + + public Builder(@NonNull IFunction function) { + super(function); + } + + @Nonnull + public Builder withDescription(@Nonnull String description) { + Check.isTrue(!built); + this.description = description; + return this; + } + + @Nonnull + public Builder withParameters(@Nonnull Collection parameters) { + Check.isTrue(!built); + this.parameters.addAll(parameters); + return this; + } + + @Nonnull + public Builder withParameter(@Nonnull String parameter) { + Check.isTrue(!built); + parameters.add(parameter); + return this; + } + + @Nonnull + public CppFunction build() { + built = true; + return this; + } + + public void withValuesFrom(@Nonnull IFunction that) { + Check.isTrue(!built); + name = that.getName(); + body = that.getContent(); + description = Strings.getNotEmpty(that.getDescription(), ""); + parameters.clear(); + parameters.addAll(that.getParameterNames()); + } + } +} diff --git a/app/src/main/java/org/solovyev/android/calculator/function/EditFunctionFragment.java b/app/src/main/java/org/solovyev/android/calculator/function/EditFunctionFragment.java index ff4679f3..eebd79c7 100644 --- a/app/src/main/java/org/solovyev/android/calculator/function/EditFunctionFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/function/EditFunctionFragment.java @@ -36,52 +36,29 @@ import android.support.v4.app.FragmentManager; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.text.Editable; -import android.view.ContextMenu; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; +import android.view.*; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; - -import org.solovyev.android.calculator.App; -import org.solovyev.android.calculator.BaseDialogFragment; -import org.solovyev.android.calculator.CalculatorEventData; -import org.solovyev.android.calculator.CalculatorEventListener; -import org.solovyev.android.calculator.CalculatorEventType; -import org.solovyev.android.calculator.CalculatorUtils; -import org.solovyev.android.calculator.DisplayState; -import org.solovyev.android.calculator.KeyboardUi; -import org.solovyev.android.calculator.KeyboardWindow; -import org.solovyev.android.calculator.Locator; -import org.solovyev.android.calculator.R; +import butterknife.Bind; +import butterknife.ButterKnife; +import jscl.math.Generic; +import jscl.math.function.*; +import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity; import org.solovyev.android.calculator.math.edit.FunctionsFragment; import org.solovyev.android.calculator.math.edit.MathEntityRemover; import org.solovyev.android.calculator.math.edit.VarEditorSaver; -import org.solovyev.android.calculator.model.AFunction; +import org.solovyev.android.calculator.model.OldFunction; import org.solovyev.common.math.MathRegistry; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import butterknife.Bind; -import butterknife.ButterKnife; -import jscl.math.Generic; -import jscl.math.function.Constant; -import jscl.math.function.CustomFunction; -import jscl.math.function.Function; -import jscl.math.function.IConstant; -import jscl.math.function.IFunction; - public class EditFunctionFragment extends BaseDialogFragment implements CalculatorEventListener, View.OnClickListener, View.OnFocusChangeListener, View.OnKeyListener { private static final String ARG_INPUT = "input"; @@ -143,7 +120,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat protected void onPrepareDialog(@NonNull AlertDialog.Builder builder) { builder.setNegativeButton(R.string.c_cancel, null); builder.setPositiveButton(R.string.ok, null); - final AFunction function = input.getFunction(); + final OldFunction function = input.getFunction(); builder.setTitle(function == null ? R.string.function_create_function : R.string.function_edit_function); if (function != null) { builder.setNeutralButton(R.string.c_remove, null); @@ -168,7 +145,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat tryClose(); } }); - final AFunction function = input.getFunction(); + final OldFunction function = input.getFunction(); if (function != null) { final Function customFunction = new CustomFunction.Builder(function).create(); final Button neutral = dialog.getButton(AlertDialog.BUTTON_NEUTRAL); @@ -308,7 +285,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat } }; @Nullable - private AFunction function; + private OldFunction function; @Nullable private String name; @Nullable @@ -343,7 +320,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat in.readTypedList(parameterNames, STRING_CREATOR); result.parameterNames = parameterNames; - result.function = (AFunction) in.readSerializable(); + result.function = (OldFunction) in.readSerializable(); return result; } @@ -356,7 +333,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat @Nonnull public static Input newFromFunction(@Nonnull IFunction function) { final Input result = new Input(); - result.function = AFunction.fromIFunction(function); + result.function = OldFunction.fromIFunction(function); return result; } @@ -369,7 +346,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat final Input result = new Input(); if (function != null) { - result.function = AFunction.fromIFunction(function); + result.function = OldFunction.fromIFunction(function); } result.name = name; result.content = value; @@ -398,7 +375,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat } @Nullable - public AFunction getFunction() { + public OldFunction getFunction() { return function; } diff --git a/app/src/main/java/org/solovyev/android/calculator/function/FunctionBuilderAdapter.java b/app/src/main/java/org/solovyev/android/calculator/function/FunctionBuilderAdapter.java index 2e096098..41fa5e60 100644 --- a/app/src/main/java/org/solovyev/android/calculator/function/FunctionBuilderAdapter.java +++ b/app/src/main/java/org/solovyev/android/calculator/function/FunctionBuilderAdapter.java @@ -22,15 +22,14 @@ package org.solovyev.android.calculator.function; -import org.solovyev.android.calculator.model.AFunction; -import org.solovyev.android.calculator.model.MathEntityBuilder; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - import jscl.CustomFunctionCalculationException; import jscl.math.function.CustomFunction; import jscl.math.function.Function; +import org.solovyev.android.calculator.model.MathEntityBuilder; +import org.solovyev.android.calculator.model.OldFunction; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; /** * User: serso @@ -40,9 +39,9 @@ import jscl.math.function.Function; public final class FunctionBuilderAdapter implements MathEntityBuilder { @Nonnull - private final AFunction.Builder nestedBuilder; + private final OldFunction.Builder nestedBuilder; - public FunctionBuilderAdapter(@Nonnull AFunction.Builder nestedBuilder) { + public FunctionBuilderAdapter(@Nonnull OldFunction.Builder nestedBuilder) { this.nestedBuilder = nestedBuilder; } @@ -69,8 +68,8 @@ public final class FunctionBuilderAdapter implements MathEntityBuilder @Nonnull @Override - public Function create() throws CustomFunctionCalculationException, AFunction.Builder.CreationException { - final AFunction function = nestedBuilder.create(); + public Function create() throws CustomFunctionCalculationException, OldFunction.Builder.CreationException { + final OldFunction function = nestedBuilder.create(); return new CustomFunction.Builder(function).create(); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/function/FunctionEditorSaver.java b/app/src/main/java/org/solovyev/android/calculator/function/FunctionEditorSaver.java index 6d866dc0..e8195c80 100644 --- a/app/src/main/java/org/solovyev/android/calculator/function/FunctionEditorSaver.java +++ b/app/src/main/java/org/solovyev/android/calculator/function/FunctionEditorSaver.java @@ -24,25 +24,22 @@ package org.solovyev.android.calculator.function; import android.view.View; import android.widget.EditText; - +import jscl.CustomFunctionCalculationException; +import jscl.math.function.Function; +import jscl.math.function.IFunction; import org.solovyev.android.calculator.EntitiesRegistry; import org.solovyev.android.calculator.FunctionsRegistry; import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.math.edit.VarEditorSaver; -import org.solovyev.android.calculator.model.AFunction; +import org.solovyev.android.calculator.model.OldFunction; import org.solovyev.common.msg.MessageType; import org.solovyev.common.text.Strings; -import java.util.Collections; -import java.util.List; - import javax.annotation.Nonnull; import javax.annotation.Nullable; - -import jscl.CustomFunctionCalculationException; -import jscl.math.function.Function; -import jscl.math.function.IFunction; +import java.util.Collections; +import java.util.List; public class FunctionEditorSaver implements View.OnClickListener { @@ -50,7 +47,7 @@ public class FunctionEditorSaver implements View.OnClickListener { private final Object source; @Nonnull - private final AFunction.Builder builder; + private final OldFunction.Builder builder; @Nullable private final IFunction editedInstance; @@ -58,11 +55,7 @@ public class FunctionEditorSaver implements View.OnClickListener { @Nonnull private final View view; - @Nonnull - private final EntitiesRegistry mathRegistry; - - - public FunctionEditorSaver(@Nonnull AFunction.Builder builder, + public FunctionEditorSaver(@Nonnull OldFunction.Builder builder, @Nullable IFunction editedInstance, @Nonnull View view, @Nonnull EntitiesRegistry registry, @@ -71,7 +64,6 @@ public class FunctionEditorSaver implements View.OnClickListener { this.builder = builder; this.editedInstance = editedInstance; this.view = view; - this.mathRegistry = registry; this.source = source; } @@ -107,11 +99,12 @@ public class FunctionEditorSaver implements View.OnClickListener { parameterNames = Collections.emptyList(); } + final FunctionsRegistry registry = Locator.getInstance().getEngine().getFunctionsRegistry(); if (VarEditorSaver.isValidName(name)) { boolean canBeSaved = false; - final Function entityFromRegistry = mathRegistry.get(name); + final Function entityFromRegistry = registry.get(name); if (entityFromRegistry == null) { canBeSaved = true; } else if (editedInstance != null && entityFromRegistry.getId().equals(editedInstance.getId())) { @@ -144,10 +137,10 @@ public class FunctionEditorSaver implements View.OnClickListener { Locator.getInstance().getNotifier().showMessage(error, MessageType.error); } else { try { - FunctionsRegistry.saveFunction(mathRegistry, new FunctionBuilderAdapter(builder), editedInstance, source, true); + registry.add(new FunctionBuilderAdapter(builder), editedInstance, source); } catch (CustomFunctionCalculationException e) { Locator.getInstance().getNotifier().showMessage(e); - } catch (AFunction.Builder.CreationException e) { + } catch (OldFunction.Builder.CreationException e) { Locator.getInstance().getNotifier().showMessage(e); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/history/History.java b/app/src/main/java/org/solovyev/android/calculator/history/History.java index e619a6db..8306bc18 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/History.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/History.java @@ -35,7 +35,7 @@ import org.json.JSONException; import org.solovyev.android.Check; import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.Engine.Preferences; -import org.solovyev.android.io.FileLoader; +import org.solovyev.android.calculator.json.Json; import org.solovyev.android.io.FileSaver; import javax.annotation.Nonnull; @@ -106,18 +106,6 @@ public class History { return states; } - @Nonnull - static List loadStates(@Nonnull File file) throws IOException, JSONException { - if (!file.exists()) { - return Collections.emptyList(); - } - final CharSequence json = FileLoader.load(file); - if (isEmpty(json)) { - return Collections.emptyList(); - } - return RecentHistory.fromJson(new JSONArray(json.toString())); - } - private static boolean isIntermediate(@Nonnull String olderText, @Nonnull String newerText, @NonNull String groupingSeparator) { @@ -200,7 +188,7 @@ public class History { if (states == null) { return; } - final JSONArray json = RecentHistory.toJson(states); + final JSONArray json = Json.toJson(states); FileSaver.save(getSavedHistoryFile(), json.toString()); preferences.edit().remove(OLD_HISTORY_PREFS_KEY).apply(); } catch (IOException e) { @@ -227,7 +215,7 @@ public class History { @Nonnull private List tryLoadStates(@NonNull File file) { try { - return loadStates(file); + return Json.load(file, HistoryState.JSON_CREATOR); } catch (IOException | JSONException e) { errorReporter.onException(e); } @@ -411,7 +399,7 @@ public class History { @Override public void run() { final File file = recent ? getRecentHistoryFile() : getSavedHistoryFile(); - final JSONArray array = RecentHistory.toJson(states); + final JSONArray array = Json.toJson(states); try { FileSaver.save(file, array.toString()); } catch (IOException e) { diff --git a/app/src/main/java/org/solovyev/android/calculator/history/HistoryState.java b/app/src/main/java/org/solovyev/android/calculator/history/HistoryState.java index 57c24f46..7ef8ac24 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/HistoryState.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/HistoryState.java @@ -3,18 +3,21 @@ package org.solovyev.android.calculator.history; import android.annotation.SuppressLint; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.NonNull; import org.json.JSONException; import org.json.JSONObject; import org.solovyev.android.Check; import org.solovyev.android.calculator.DisplayState; import org.solovyev.android.calculator.EditorState; +import org.solovyev.android.calculator.json.Json; +import org.solovyev.android.calculator.json.Jsonable; import javax.annotation.Nonnull; import javax.annotation.Nullable; import static android.text.TextUtils.isEmpty; -public class HistoryState implements Parcelable { +public class HistoryState implements Parcelable, Jsonable { public static final Creator CREATOR = new Creator() { @Override @@ -27,6 +30,13 @@ public class HistoryState implements Parcelable { return new HistoryState[size]; } }; + public static final Json.Creator JSON_CREATOR = new Json.Creator() { + @NonNull + @Override + public HistoryState create(@NonNull JSONObject json) throws JSONException { + return new HistoryState(json); + } + }; private static final String JSON_EDITOR = "e"; private static final String JSON_DISPLAY = "d"; private static final String JSON_TIME = "t"; diff --git a/app/src/main/java/org/solovyev/android/calculator/history/RecentHistory.java b/app/src/main/java/org/solovyev/android/calculator/history/RecentHistory.java index 2e344a18..84c8c717 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/RecentHistory.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/RecentHistory.java @@ -3,7 +3,6 @@ package org.solovyev.android.calculator.history; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -117,34 +116,4 @@ public class RecentHistory { return Collections.unmodifiableList(list.subList(0, current + 1)); } - @NonNull - public static JSONArray toJson(@NonNull List states) { - final JSONArray array = new JSONArray(); - for (int i = 0; i < states.size(); i++) { - final HistoryState state = states.get(i); - try { - array.put(i, state.toJson()); - } catch (JSONException e) { - Log.e(History.TAG, e.getMessage(), e); - } - } - return array; - } - - @NonNull - public static List fromJson(@NonNull JSONArray array) { - final List states = new ArrayList<>(array.length()); - for (int i = 0; i < array.length(); i++) { - final JSONObject json = array.optJSONObject(i); - if (json == null) { - continue; - } - try { - states.add(HistoryState.create(json)); - } catch (JSONException e) { - Log.e(History.TAG, e.getMessage(), e); - } - } - return states; - } } diff --git a/app/src/main/java/org/solovyev/android/calculator/json/Json.java b/app/src/main/java/org/solovyev/android/calculator/json/Json.java new file mode 100644 index 00000000..efc2b6d5 --- /dev/null +++ b/app/src/main/java/org/solovyev/android/calculator/json/Json.java @@ -0,0 +1,74 @@ +package org.solovyev.android.calculator.json; + +import android.support.annotation.NonNull; +import android.util.Log; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.solovyev.android.io.FileLoader; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static android.text.TextUtils.isEmpty; + +public final class Json { + + @NonNull + private static final String TAG = "Json"; + + private Json() { + } + + @NonNull + public static List fromJson(@NonNull JSONArray array, @NonNull Creator creator) { + final List items = new ArrayList<>(array.length()); + for (int i = 0; i < array.length(); i++) { + final JSONObject json = array.optJSONObject(i); + if (json == null) { + continue; + } + try { + items.add(creator.create(json)); + } catch (JSONException e) { + Log.e(TAG, e.getMessage(), e); + } + } + return items; + } + + @NonNull + public static JSONArray toJson(@NonNull List items) { + final JSONArray array = new JSONArray(); + for (int i = 0; i < items.size(); i++) { + final Jsonable item = items.get(i); + try { + array.put(i, item.toJson()); + } catch (JSONException e) { + Log.e(TAG, e.getMessage(), e); + } + } + return array; + } + + @Nonnull + public static List load(@Nonnull File file, @NonNull Creator creator) throws IOException, JSONException { + if (!file.exists()) { + return Collections.emptyList(); + } + final CharSequence json = FileLoader.load(file); + if (isEmpty(json)) { + return Collections.emptyList(); + } + return fromJson(new JSONArray(json.toString()), creator); + } + + public interface Creator { + @NonNull + T create(@NonNull JSONObject json) throws JSONException; + } +} diff --git a/app/src/main/java/org/solovyev/android/calculator/json/Jsonable.java b/app/src/main/java/org/solovyev/android/calculator/json/Jsonable.java new file mode 100644 index 00000000..52ba8497 --- /dev/null +++ b/app/src/main/java/org/solovyev/android/calculator/json/Jsonable.java @@ -0,0 +1,11 @@ +package org.solovyev.android.calculator.json; + +import org.json.JSONException; +import org.json.JSONObject; + +import javax.annotation.Nonnull; + +public interface Jsonable { + @Nonnull + JSONObject toJson() throws JSONException; +} diff --git a/app/src/main/java/org/solovyev/android/calculator/model/EntityDao.java b/app/src/main/java/org/solovyev/android/calculator/model/EntityDao.java index 5322f42d..5122be79 100644 --- a/app/src/main/java/org/solovyev/android/calculator/model/EntityDao.java +++ b/app/src/main/java/org/solovyev/android/calculator/model/EntityDao.java @@ -22,91 +22,60 @@ package org.solovyev.android.calculator.model; -import android.app.Application; -import android.content.Context; import android.content.SharedPreferences; -import android.content.res.Resources; -import android.preference.PreferenceManager; - import org.simpleframework.xml.Serializer; import org.simpleframework.xml.core.Persister; -import org.solovyev.android.calculator.CalculatorApplication; import org.solovyev.android.calculator.PersistedEntitiesContainer; import org.solovyev.android.calculator.PersistedEntity; -import java.io.StringWriter; - import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.io.StringWriter; public class EntityDao { - @Nullable + @Nonnull private final String preferenceString; @Nonnull - private final Context context; - - @Nullable private final Class> persistenceContainerClass; + @Nonnull + private final SharedPreferences preferences; - public EntityDao(@Nullable String preferenceString, - @Nonnull Application application, - @Nullable Class> persistenceContainerClass) { + public EntityDao(@Nonnull String preferenceString, + @Nonnull Class> persistenceContainerClass, @Nonnull SharedPreferences preferences) { this.preferenceString = preferenceString; - this.context = application; this.persistenceContainerClass = persistenceContainerClass; + this.preferences = preferences; } public void save(@Nonnull PersistedEntitiesContainer container) { - if (preferenceString != null) { - final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); - final SharedPreferences.Editor editor = settings.edit(); + final SharedPreferences.Editor editor = preferences.edit(); - final StringWriter sw = new StringWriter(); - final Serializer serializer = new Persister(); - try { - serializer.write(container, sw); - } catch (Exception e) { - throw new RuntimeException(e); - } - - editor.putString(preferenceString, sw.toString()); - - editor.apply(); + final StringWriter sw = new StringWriter(); + final Serializer serializer = new Persister(); + try { + serializer.write(container, sw); + } catch (Exception e) { + throw new RuntimeException(e); } + + editor.putString(preferenceString, sw.toString()); + editor.apply(); } @Nullable public PersistedEntitiesContainer load() { - if (persistenceContainerClass != null && preferenceString != null) { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); - - if (preferences != null) { - final String value = preferences.getString(preferenceString, null); - if (value != null) { - final Serializer serializer = new Persister(); - try { - return serializer.read(persistenceContainerClass, value); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + final String value = preferences.getString(preferenceString, null); + if (value != null) { + final Serializer serializer = new Persister(); + try { + return serializer.read(persistenceContainerClass, value); + } catch (Exception e) { + throw new RuntimeException(e); } } return null; } - - @Nullable - public String getDescription(@Nonnull String descriptionId) { - final Resources resources = context.getResources(); - - final int stringId = resources.getIdentifier(descriptionId, "string", CalculatorApplication.class.getPackage().getName()); - try { - return resources.getString(stringId); - } catch (Resources.NotFoundException e) { - return null; - } - } } diff --git a/app/src/main/java/org/solovyev/android/calculator/model/Functions.java b/app/src/main/java/org/solovyev/android/calculator/model/Functions.java deleted file mode 100644 index 88b3479f..00000000 --- a/app/src/main/java/org/solovyev/android/calculator/model/Functions.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013 serso aka se.solovyev - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Contact details - * - * Email: se.solovyev@gmail.com - * Site: http://se.solovyev.org - */ - -package org.solovyev.android.calculator.model; - -import org.simpleframework.xml.ElementList; -import org.simpleframework.xml.Root; -import org.solovyev.android.calculator.PersistedEntitiesContainer; - -import java.util.ArrayList; -import java.util.List; - -@Root -public class Functions implements PersistedEntitiesContainer { - - @ElementList(type = AFunction.class) - private List functions = new ArrayList(); - - public Functions() { - } - - public List getEntities() { - return functions; - } -} diff --git a/app/src/main/java/org/solovyev/android/calculator/model/AFunction.java b/app/src/main/java/org/solovyev/android/calculator/model/OldFunction.java similarity index 92% rename from app/src/main/java/org/solovyev/android/calculator/model/AFunction.java rename to app/src/main/java/org/solovyev/android/calculator/model/OldFunction.java index 47c2617b..5f2380dc 100644 --- a/app/src/main/java/org/solovyev/android/calculator/model/AFunction.java +++ b/app/src/main/java/org/solovyev/android/calculator/model/OldFunction.java @@ -22,6 +22,7 @@ package org.solovyev.android.calculator.model; +import jscl.math.function.IFunction; import org.simpleframework.xml.Element; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Root; @@ -34,19 +35,16 @@ import org.solovyev.common.msg.Message; import org.solovyev.common.msg.MessageLevel; import org.solovyev.common.text.Strings; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import jscl.math.function.IFunction; - @Root(name = "function") -public class AFunction implements IFunction, PersistedEntity, Serializable { +public class OldFunction implements IFunction, PersistedEntity, Serializable { @Transient private Integer id; @@ -70,22 +68,22 @@ public class AFunction implements IFunction, PersistedEntity, Serializable { @Nonnull private String description = ""; - public AFunction() { + public OldFunction() { } - public AFunction(Integer id) { + public OldFunction(Integer id) { this.id = id; } - public static AFunction fromIFunction(@Nonnull IFunction function) { - final AFunction result = new AFunction(); + public static OldFunction fromIFunction(@Nonnull IFunction function) { + final OldFunction result = new OldFunction(); copy(result, function); return result; } - private static void copy(@Nonnull AFunction target, + private static void copy(@Nonnull OldFunction target, @Nonnull IFunction source) { target.name = source.getName(); target.content = source.getContent(); @@ -174,7 +172,7 @@ public class AFunction implements IFunction, PersistedEntity, Serializable { this.parameterNames = parameterNames; } - public static class Builder implements MathEntityBuilder { + public static class Builder implements MathEntityBuilder { @Nonnull private String name; @@ -243,12 +241,12 @@ public class AFunction implements IFunction, PersistedEntity, Serializable { } @Nonnull - public AFunction create() throws AFunction.Builder.CreationException { - final AFunction result; + public OldFunction create() throws OldFunction.Builder.CreationException { + final OldFunction result; if (id != null) { - result = new AFunction(id); + result = new OldFunction(id); } else { - result = new AFunction(); + result = new OldFunction(); } result.name = name; diff --git a/app/src/main/java/org/solovyev/android/calculator/model/OldFunctions.java b/app/src/main/java/org/solovyev/android/calculator/model/OldFunctions.java new file mode 100644 index 00000000..b8eee7dd --- /dev/null +++ b/app/src/main/java/org/solovyev/android/calculator/model/OldFunctions.java @@ -0,0 +1,65 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.model; + +import android.text.TextUtils; +import org.simpleframework.xml.ElementList; +import org.simpleframework.xml.Root; +import org.solovyev.android.calculator.PersistedEntitiesContainer; +import org.solovyev.android.calculator.function.CppFunction; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +@Root(name = "Functions") +public class OldFunctions implements PersistedEntitiesContainer { + + public static final String PREFS_KEY = "org.solovyev.android.calculator.CalculatorModel_functions"; + + @ElementList(type = OldFunction.class) + private List functions = new ArrayList<>(); + + public OldFunctions() { + } + + @Nonnull + public static List toCppFunctions(@Nonnull OldFunctions oldFunctions) { + final List functions = new ArrayList<>(); + for (OldFunction oldFunction : oldFunctions.getEntities()) { + final String name = oldFunction.getName(); + final String body = oldFunction.getContent(); + if (TextUtils.isEmpty(name) || TextUtils.isEmpty(body)) { + continue; + } + functions.add(CppFunction.builder(name, body) + .withParameters(oldFunction.getParameterNames()) + .withDescription(oldFunction.getDescription()).build()); + } + return functions; + } + + public List getEntities() { + return functions; + } +} diff --git a/app/src/test/java/org/solovyev/android/calculator/CalculatorTestUtils.java b/app/src/test/java/org/solovyev/android/calculator/CalculatorTestUtils.java index 24a78bef..83d4e5af 100644 --- a/app/src/test/java/org/solovyev/android/calculator/CalculatorTestUtils.java +++ b/app/src/test/java/org/solovyev/android/calculator/CalculatorTestUtils.java @@ -23,9 +23,8 @@ package org.solovyev.android.calculator; import android.content.Context; - import com.squareup.otto.Bus; - +import jscl.JsclMathEngine; import org.junit.Assert; import org.mockito.Mockito; import org.robolectric.fakes.RoboSharedPreferences; @@ -34,12 +33,9 @@ import org.solovyev.android.calculator.language.Languages; import org.solovyev.android.calculator.model.EntityDao; import org.solovyev.android.calculator.plot.CalculatorPlotter; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.*; import java.text.DecimalFormatSymbols; import java.util.HashMap; import java.util.Map; @@ -47,11 +43,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import jscl.JsclMathEngine; - /** * User: serso * Date: 10/7/12 @@ -104,9 +95,9 @@ public class CalculatorTestUtils { final JsclMathEngine jsclEngine = JsclMathEngine.getInstance(); final VarsRegistry varsRegistry = new VarsRegistry(jsclEngine.getConstantsRegistry(), entityDao); - final FunctionsRegistry functionsRegistry = new FunctionsRegistry(jsclEngine.getFunctionsRegistry(), entityDao); - final OperatorsRegistry operatorsRegistry = new OperatorsRegistry(jsclEngine.getOperatorsRegistry(), entityDao); - final PostfixFunctionsRegistry postfixFunctionsRegistry = new PostfixFunctionsRegistry(jsclEngine.getPostfixFunctionsRegistry(), entityDao); + final FunctionsRegistry functionsRegistry = new FunctionsRegistry(jsclEngine.getFunctionsRegistry()); + final OperatorsRegistry operatorsRegistry = new OperatorsRegistry(jsclEngine.getOperatorsRegistry()); + final PostfixFunctionsRegistry postfixFunctionsRegistry = new PostfixFunctionsRegistry(jsclEngine.getPostfixFunctionsRegistry()); return new Engine(jsclEngine, varsRegistry, functionsRegistry, operatorsRegistry, postfixFunctionsRegistry); } diff --git a/app/src/test/java/org/solovyev/android/calculator/history/HistoryTest.java b/app/src/test/java/org/solovyev/android/calculator/history/HistoryTest.java index f510f4ed..7105749b 100644 --- a/app/src/test/java/org/solovyev/android/calculator/history/HistoryTest.java +++ b/app/src/test/java/org/solovyev/android/calculator/history/HistoryTest.java @@ -34,6 +34,7 @@ import org.robolectric.annotation.Config; import org.solovyev.android.CalculatorTestRunner; import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.jscl.JsclOperation; +import org.solovyev.android.calculator.json.Json; import javax.annotation.Nonnull; import java.io.File; @@ -280,7 +281,7 @@ public class HistoryTest { @Test public void testShouldLoadStates() throws Exception { - final List states = History.loadStates(new File(HistoryTest.class.getResource("recent-history.json").getFile())); + final List states = Json.load(new File(HistoryTest.class.getResource("recent-history.json").getFile())); assertEquals(8, states.size()); HistoryState state = states.get(0); diff --git a/app/src/test/java/org/solovyev/android/calculator/model/FunctionsTest.java b/app/src/test/java/org/solovyev/android/calculator/model/OldFunctionsTest.java similarity index 81% rename from app/src/test/java/org/solovyev/android/calculator/model/FunctionsTest.java rename to app/src/test/java/org/solovyev/android/calculator/model/OldFunctionsTest.java index 372be86a..ddcf5793 100644 --- a/app/src/test/java/org/solovyev/android/calculator/model/FunctionsTest.java +++ b/app/src/test/java/org/solovyev/android/calculator/model/OldFunctionsTest.java @@ -22,6 +22,7 @@ package org.solovyev.android.calculator.model; +import jscl.util.ExpressionGenerator; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Assert; @@ -34,24 +35,17 @@ import org.solovyev.common.Objects; import org.solovyev.common.equals.CollectionEqualizer; import org.solovyev.common.text.Strings; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Random; - import javax.annotation.Nonnull; import javax.annotation.Nullable; - -import jscl.util.ExpressionGenerator; +import java.io.StringWriter; +import java.util.*; /** * User: serso * Date: 11/14/12 * Time: 8:06 PM */ -public class FunctionsTest { +public class OldFunctionsTest { private static final String xml = "\n" + " \n" + @@ -95,23 +89,23 @@ public class FunctionsTest { @Test public void testXml() throws Exception { - final Functions in = new Functions(); + final OldFunctions in = new OldFunctions(); - AFunction first = new AFunction.Builder("test", "x+y", Arrays.asList("x", "y")).setDescription("description").setSystem(false).create(); + OldFunction first = new OldFunction.Builder("test", "x+y", Arrays.asList("x", "y")).setDescription("description").setSystem(false).create(); in.getEntities().add(first); - AFunction second = new AFunction.Builder("z_2", "e^(z_1^2+z_2^2)", Arrays.asList("z_1", "z_2")).setSystem(true).create(); + OldFunction second = new OldFunction.Builder("z_2", "e^(z_1^2+z_2^2)", Arrays.asList("z_1", "z_2")).setSystem(true).create(); in.getEntities().add(second); - AFunction third = new AFunction.Builder("z_2", "e^(z_1^2+z_2^2)", Arrays.asList("z_1", "z_2")).setSystem(true).setDescription("").create(); + OldFunction third = new OldFunction.Builder("z_2", "e^(z_1^2+z_2^2)", Arrays.asList("z_1", "z_2")).setSystem(true).setDescription("").create(); in.getEntities().add(third); - final Functions out = testXml(in, xml); + final OldFunctions out = testXml(in, xml); Assert.assertTrue(!out.getEntities().isEmpty()); - final AFunction firstOut = out.getEntities().get(0); - final AFunction secondOut = out.getEntities().get(1); + final OldFunction firstOut = out.getEntities().get(0); + final OldFunction secondOut = out.getEntities().get(1); assertEquals(first, firstOut); assertEquals(second, secondOut); @@ -119,7 +113,7 @@ public class FunctionsTest { } @Nonnull - private Functions testXml(@Nonnull Functions in, @Nullable String expectedXml) throws Exception { + private OldFunctions testXml(@Nonnull OldFunctions in, @Nullable String expectedXml) throws Exception { final String actualXml = toXml(in); if (expectedXml != null) { @@ -127,13 +121,13 @@ public class FunctionsTest { } final Serializer serializer = new Persister(); - final Functions out = serializer.read(Functions.class, actualXml); + final OldFunctions out = serializer.read(OldFunctions.class, actualXml); final String actualXml2 = toXml(out); Assert.assertEquals(actualXml, actualXml2); return out; } - private String toXml(Functions in) throws Exception { + private String toXml(OldFunctions in) throws Exception { final StringWriter sw = new StringWriter(); final Serializer serializer = new Persister(); serializer.write(in, sw); @@ -142,7 +136,7 @@ public class FunctionsTest { @Test public void testRandomXml() throws Exception { - final Functions in = new Functions(); + final OldFunctions in = new OldFunctions(); final Random random = new Random(new Date().getTime()); @@ -156,7 +150,7 @@ public class FunctionsTest { parameterNames.add(String.valueOf(paramsString.charAt(j))); } - final AFunction.Builder builder = new AFunction.Builder("test_" + i, content, parameterNames); + final OldFunction.Builder builder = new OldFunction.Builder("test_" + i, content, parameterNames); if (random.nextBoolean()) { builder.setDescription(Strings.generateRandomString(random.nextInt(100))); @@ -170,8 +164,8 @@ public class FunctionsTest { testXml(in, null); } - private void assertEquals(@Nonnull final AFunction expected, - @Nonnull AFunction actual) { + private void assertEquals(@Nonnull final OldFunction expected, + @Nonnull OldFunction actual) { //Assert.assertEquals(expected.getId(), actual.getId()); Assert.assertEquals(expected.getContent(), actual.getContent()); Assert.assertEquals(expected.getDescription(), actual.getDescription());