FunctionsRegistry refactor
This commit is contained in:
		@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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<T extends MathEntity, P extends PersistedEntity> implements EntitiesRegistry<T> {
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
@@ -42,12 +44,12 @@ public abstract class BaseEntitiesRegistry<T extends MathEntity, P extends Persi
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private final String prefix;
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private final EntityDao<P> entityDao;
 | 
			
		||||
    @Nullable
 | 
			
		||||
    protected final EntityDao<P> entityDao;
 | 
			
		||||
 | 
			
		||||
    protected BaseEntitiesRegistry(@Nonnull MathRegistry<T> mathRegistry,
 | 
			
		||||
                                   @Nonnull String prefix,
 | 
			
		||||
                                   @Nonnull EntityDao<P> entityDao) {
 | 
			
		||||
                                   @Nullable EntityDao<P> entityDao) {
 | 
			
		||||
        this.mathRegistry = mathRegistry;
 | 
			
		||||
        this.prefix = prefix;
 | 
			
		||||
        this.entityDao = entityDao;
 | 
			
		||||
@@ -70,10 +72,28 @@ public abstract class BaseEntitiesRegistry<T extends MathEntity, P extends Persi
 | 
			
		||||
            stringName = prefix + substitute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return entityDao.getDescription(stringName);
 | 
			
		||||
        return getDescription(App.getApplication(), stringName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public synchronized void load() {
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    public String getDescription(@Nonnull Context context, @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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public synchronized void init() {
 | 
			
		||||
        Check.isNotMainThread();
 | 
			
		||||
 | 
			
		||||
        if (entityDao == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        final PersistedEntitiesContainer<P> persistenceContainer = entityDao.load();
 | 
			
		||||
 | 
			
		||||
        final List<P> notCreatedEntities = new ArrayList<P>();
 | 
			
		||||
@@ -112,6 +132,9 @@ public abstract class BaseEntitiesRegistry<T extends MathEntity, P extends Persi
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public synchronized void save() {
 | 
			
		||||
        if (entityDao == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        final PersistedEntitiesContainer<P> container = createPersistenceContainer();
 | 
			
		||||
 | 
			
		||||
        for (T entity : this.getEntities()) {
 | 
			
		||||
@@ -123,7 +146,7 @@ public abstract class BaseEntitiesRegistry<T extends MathEntity, P extends Persi
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.entityDao.save(container);
 | 
			
		||||
        entityDao.save(container);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
 
 | 
			
		||||
@@ -22,13 +22,15 @@
 | 
			
		||||
 | 
			
		||||
package org.solovyev.android.calculator;
 | 
			
		||||
 | 
			
		||||
import android.app.Application;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
 | 
			
		||||
import com.squareup.otto.Bus;
 | 
			
		||||
 | 
			
		||||
import jscl.AngleUnit;
 | 
			
		||||
import jscl.JsclMathEngine;
 | 
			
		||||
import jscl.MathEngine;
 | 
			
		||||
import jscl.NumeralBase;
 | 
			
		||||
import jscl.math.function.IConstant;
 | 
			
		||||
import jscl.math.operator.Operator;
 | 
			
		||||
import org.solovyev.android.calculator.model.EntityDao;
 | 
			
		||||
import org.solovyev.android.calculator.model.Functions;
 | 
			
		||||
import org.solovyev.android.calculator.model.Vars;
 | 
			
		||||
import org.solovyev.android.prefs.BooleanPreference;
 | 
			
		||||
import org.solovyev.android.prefs.IntegerPreference;
 | 
			
		||||
@@ -38,23 +40,14 @@ import org.solovyev.common.text.EnumMapper;
 | 
			
		||||
import org.solovyev.common.text.NumberMapper;
 | 
			
		||||
import org.solovyev.common.text.Strings;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
import javax.inject.Inject;
 | 
			
		||||
import javax.inject.Singleton;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.concurrent.Executor;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
import javax.inject.Inject;
 | 
			
		||||
import javax.inject.Singleton;
 | 
			
		||||
 | 
			
		||||
import jscl.AngleUnit;
 | 
			
		||||
import jscl.JsclMathEngine;
 | 
			
		||||
import jscl.MathEngine;
 | 
			
		||||
import jscl.NumeralBase;
 | 
			
		||||
import jscl.math.function.Function;
 | 
			
		||||
import jscl.math.function.IConstant;
 | 
			
		||||
import jscl.math.operator.Operator;
 | 
			
		||||
 | 
			
		||||
@Singleton
 | 
			
		||||
public class Engine implements SharedPreferences.OnSharedPreferenceChangeListener {
 | 
			
		||||
 | 
			
		||||
@@ -62,8 +55,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene
 | 
			
		||||
    private final MathEngine mathEngine;
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private final EntitiesRegistry<IConstant> varsRegistry;
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private final EntitiesRegistry<Function> functionsRegistry;
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private final EntitiesRegistry<Operator> 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<IConstant> varsRegistry, @Nonnull EntitiesRegistry<Function> functionsRegistry, @Nonnull EntitiesRegistry<Operator> operatorsRegistry, @Nonnull EntitiesRegistry<Operator> postfixFunctionsRegistry) {
 | 
			
		||||
    public Engine(@Nonnull MathEngine mathEngine, @Nonnull EntitiesRegistry<IConstant> varsRegistry, @Nonnull FunctionsRegistry functionsRegistry, @Nonnull EntitiesRegistry<Operator> operatorsRegistry, @Nonnull EntitiesRegistry<Operator> 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<Function> 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);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ public interface EntitiesRegistry<E extends MathEntity> extends MathRegistry<E>
 | 
			
		||||
    @Nullable
 | 
			
		||||
    String getCategory(@Nonnull E entity);
 | 
			
		||||
 | 
			
		||||
    void load();
 | 
			
		||||
    void init();
 | 
			
		||||
 | 
			
		||||
    void save();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<String> names = Arrays.asList("sinh", "cosh", "tanh", "coth", "asinh", "acosh", "atanh", "acoth");
 | 
			
		||||
        private final Set<String> names = new HashSet<>(Arrays.asList("sinh", "cosh", "tanh", "coth", "asinh", "acosh", "atanh", "acoth"));
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean isInCategory(@Nonnull Function function) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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<Function, AFunction> {
 | 
			
		||||
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<Function, OldFunction> {
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private static final Map<String, String> substitutes = new HashMap<String, String>();
 | 
			
		||||
    private static final Map<String, String> substitutes = new HashMap<>();
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private static final String FUNCTION_DESCRIPTION_PREFIX = "c_fun_description_";
 | 
			
		||||
 | 
			
		||||
@@ -55,30 +68,42 @@ public class FunctionsRegistry extends BaseEntitiesRegistry<Function, AFunction>
 | 
			
		||||
        substitutes.put("√", "sqrt");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public FunctionsRegistry(@Nonnull MathRegistry<Function> functionsRegistry,
 | 
			
		||||
                             @Nonnull EntityDao<AFunction> 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<Function> registry,
 | 
			
		||||
                                    @Nonnull MathEntityBuilder<? extends Function> 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<Function, AFunction>
 | 
			
		||||
        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<CppFunction> 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<CppFunction> 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<Function, AFunction>
 | 
			
		||||
    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<? extends Function> createBuilder(@Nonnull AFunction function) {
 | 
			
		||||
        return new FunctionBuilderAdapter(new AFunction.Builder(function));
 | 
			
		||||
    protected JBuilder<? extends Function> 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<Function, AFunction>
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    protected PersistedEntitiesContainer<AFunction> createPersistenceContainer() {
 | 
			
		||||
        return new Functions();
 | 
			
		||||
    protected PersistedEntitiesContainer<OldFunction> createPersistenceContainer() {
 | 
			
		||||
        return new OldFunctions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class WriteTask implements Runnable {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void run() {
 | 
			
		||||
            Check.isMainThread();
 | 
			
		||||
            final List<CppFunction> 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);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<Operator, PersistedEntity> {
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
@@ -49,9 +46,8 @@ public class OperatorsRegistry extends BaseEntitiesRegistry<Operator, PersistedE
 | 
			
		||||
        substitutes.put("Σ", "sum");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public OperatorsRegistry(@Nonnull MathRegistry<Operator> functionsRegistry,
 | 
			
		||||
                             @Nonnull EntityDao<PersistedEntity> entityDao) {
 | 
			
		||||
        super(functionsRegistry, OPERATOR_DESCRIPTION_PREFIX, entityDao);
 | 
			
		||||
    public OperatorsRegistry(@Nonnull MathRegistry<Operator> functionsRegistry) {
 | 
			
		||||
        super(functionsRegistry, OPERATOR_DESCRIPTION_PREFIX, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
@@ -70,22 +66,12 @@ public class OperatorsRegistry extends BaseEntitiesRegistry<Operator, PersistedE
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void load() {
 | 
			
		||||
        // not supported yet
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    protected JBuilder<? extends Operator> 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.
 | 
			
		||||
 
 | 
			
		||||
@@ -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<Operator, PersistedEntity> {
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
@@ -47,12 +44,10 @@ public class PostfixFunctionsRegistry extends BaseEntitiesRegistry<Operator, Per
 | 
			
		||||
        substitutes.put("°", "degree");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public PostfixFunctionsRegistry(@Nonnull MathRegistry<Operator> functionsRegistry,
 | 
			
		||||
                                    @Nonnull EntityDao<PersistedEntity> entityDao) {
 | 
			
		||||
        super(functionsRegistry, POSTFIX_FUNCTION_DESCRIPTION_PREFIX, entityDao);
 | 
			
		||||
    public PostfixFunctionsRegistry(@Nonnull MathRegistry<Operator> functionsRegistry) {
 | 
			
		||||
        super(functionsRegistry, POSTFIX_FUNCTION_DESCRIPTION_PREFIX, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    protected Map<String, String> getSubstitutes() {
 | 
			
		||||
@@ -69,22 +64,12 @@ public class PostfixFunctionsRegistry extends BaseEntitiesRegistry<Operator, Per
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void load() {
 | 
			
		||||
        // not supported yet
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    protected JBuilder<? extends Operator> createBuilder(@Nonnull PersistedEntity entity) {
 | 
			
		||||
        throw new UnsupportedOperationException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void save() {
 | 
			
		||||
        // not supported yet
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected PersistedEntity transform(@Nonnull Operator entity) {
 | 
			
		||||
        return null;
 | 
			
		||||
 
 | 
			
		||||
@@ -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<IConstant, Var> {
 | 
			
		||||
 | 
			
		||||
@@ -82,8 +80,8 @@ public class VarsRegistry extends BaseEntitiesRegistry<IConstant, Var> {
 | 
			
		||||
        return substitutes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public synchronized void load() {
 | 
			
		||||
        super.load();
 | 
			
		||||
    public synchronized void init() {
 | 
			
		||||
        super.init();
 | 
			
		||||
 | 
			
		||||
        tryToAddAuxVar("x");
 | 
			
		||||
        tryToAddAuxVar("y");
 | 
			
		||||
 
 | 
			
		||||
@@ -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<CppFunction> JSON_CREATOR = new Json.Creator<CppFunction>() {
 | 
			
		||||
        @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<String> 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<String> 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<? extends String> 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());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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<Function> {
 | 
			
		||||
 | 
			
		||||
    @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<Function>
 | 
			
		||||
 | 
			
		||||
    @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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<Function> mathRegistry;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public FunctionEditorSaver(@Nonnull AFunction.Builder builder,
 | 
			
		||||
    public FunctionEditorSaver(@Nonnull OldFunction.Builder builder,
 | 
			
		||||
                               @Nullable IFunction editedInstance,
 | 
			
		||||
                               @Nonnull View view,
 | 
			
		||||
                               @Nonnull EntitiesRegistry<Function> 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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -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<HistoryState> 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<HistoryState> 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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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<HistoryState> CREATOR = new Creator<HistoryState>() {
 | 
			
		||||
        @Override
 | 
			
		||||
@@ -27,6 +30,13 @@ public class HistoryState implements Parcelable {
 | 
			
		||||
            return new HistoryState[size];
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    public static final Json.Creator<HistoryState> JSON_CREATOR = new Json.Creator<HistoryState>() {
 | 
			
		||||
        @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";
 | 
			
		||||
 
 | 
			
		||||
@@ -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<HistoryState> 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<HistoryState> fromJson(@NonNull JSONArray array) {
 | 
			
		||||
        final List<HistoryState> 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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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 <T> List<T> fromJson(@NonNull JSONArray array, @NonNull Creator<T> creator) {
 | 
			
		||||
        final List<T> 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<? extends Jsonable> 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 <T> List<T> load(@Nonnull File file, @NonNull Creator<T> 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<T> {
 | 
			
		||||
        @NonNull
 | 
			
		||||
        T create(@NonNull JSONObject json) throws JSONException;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
@@ -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<T extends PersistedEntity> {
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private final String preferenceString;
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private final Context context;
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private final Class<? extends PersistedEntitiesContainer<T>> persistenceContainerClass;
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    private final SharedPreferences preferences;
 | 
			
		||||
 | 
			
		||||
    public EntityDao(@Nullable String preferenceString,
 | 
			
		||||
                     @Nonnull Application application,
 | 
			
		||||
                     @Nullable Class<? extends PersistedEntitiesContainer<T>> persistenceContainerClass) {
 | 
			
		||||
    public EntityDao(@Nonnull String preferenceString,
 | 
			
		||||
                     @Nonnull Class<? extends PersistedEntitiesContainer<T>> persistenceContainerClass, @Nonnull SharedPreferences preferences) {
 | 
			
		||||
        this.preferenceString = preferenceString;
 | 
			
		||||
        this.context = application;
 | 
			
		||||
        this.persistenceContainerClass = persistenceContainerClass;
 | 
			
		||||
        this.preferences = preferences;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void save(@Nonnull PersistedEntitiesContainer<T> 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<T> 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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<AFunction> {
 | 
			
		||||
 | 
			
		||||
    @ElementList(type = AFunction.class)
 | 
			
		||||
    private List<AFunction> functions = new ArrayList<AFunction>();
 | 
			
		||||
 | 
			
		||||
    public Functions() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<AFunction> getEntities() {
 | 
			
		||||
        return functions;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<AFunction> {
 | 
			
		||||
	public static class Builder implements MathEntityBuilder<OldFunction> {
 | 
			
		||||
 | 
			
		||||
        @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;
 | 
			
		||||
@@ -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<OldFunction> {
 | 
			
		||||
 | 
			
		||||
    public static final String PREFS_KEY = "org.solovyev.android.calculator.CalculatorModel_functions";
 | 
			
		||||
 | 
			
		||||
    @ElementList(type = OldFunction.class)
 | 
			
		||||
    private List<OldFunction> functions = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    public OldFunctions() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    public static List<CppFunction> toCppFunctions(@Nonnull OldFunctions oldFunctions) {
 | 
			
		||||
        final List<CppFunction> 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<OldFunction> getEntities() {
 | 
			
		||||
        return functions;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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<HistoryState> states = History.loadStates(new File(HistoryTest.class.getResource("recent-history.json").getFile()));
 | 
			
		||||
        final List<HistoryState> states = Json.load(new File(HistoryTest.class.getResource("recent-history.json").getFile()));
 | 
			
		||||
        assertEquals(8, states.size());
 | 
			
		||||
 | 
			
		||||
        HistoryState state = states.get(0);
 | 
			
		||||
 
 | 
			
		||||
@@ -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 = "<functions>\n" +
 | 
			
		||||
            "   <functions class=\"java.util.ArrayList\">\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());
 | 
			
		||||
		Reference in New Issue
	
	Block a user