Files
android-calculatorpp/app/src/main/java/org/solovyev/android/calculator/Engine.java
2016-03-02 08:25:41 +01:00

270 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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;
import android.content.SharedPreferences;
import android.text.TextUtils;
import com.squareup.otto.Bus;
import jscl.AngleUnit;
import jscl.JsclMathEngine;
import jscl.MathEngine;
import jscl.NumeralBase;
import jscl.math.operator.Operator;
import jscl.text.Identifier;
import jscl.text.Parser;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.functions.FunctionsRegistry;
import org.solovyev.android.calculator.operators.OperatorsRegistry;
import org.solovyev.android.calculator.operators.PostfixFunctionsRegistry;
import org.solovyev.android.prefs.BooleanPreference;
import org.solovyev.android.prefs.IntegerPreference;
import org.solovyev.android.prefs.Preference;
import org.solovyev.android.prefs.StringPreference;
import org.solovyev.common.text.EnumMapper;
import org.solovyev.common.text.NumberMapper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
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;
@Singleton
public class Engine implements SharedPreferences.OnSharedPreferenceChangeListener {
@Nonnull
private final MathEngine mathEngine;
@Inject
SharedPreferences preferences;
@Inject
Bus bus;
@Inject
ErrorReporter errorReporter;
@Inject
FunctionsRegistry functionsRegistry;
@Inject
VariablesRegistry variablesRegistry;
@Inject
OperatorsRegistry operatorsRegistry;
@Inject
PostfixFunctionsRegistry postfixFunctionsRegistry;
@Nonnull
private String multiplicationSign = Preferences.multiplicationSign.getDefaultValue();
public Engine(@Nonnull MathEngine mathEngine, @Nonnull VariablesRegistry variablesRegistry, @Nonnull FunctionsRegistry functionsRegistry, @Nonnull OperatorsRegistry operatorsRegistry, @Nonnull PostfixFunctionsRegistry postfixFunctionsRegistry) {
this.mathEngine = mathEngine;
this.variablesRegistry = variablesRegistry;
this.functionsRegistry = functionsRegistry;
this.operatorsRegistry = operatorsRegistry;
this.postfixFunctionsRegistry = postfixFunctionsRegistry;
}
@Inject
public Engine(@Nonnull JsclMathEngine mathEngine) {
this.mathEngine = mathEngine;
this.mathEngine.setRoundResult(true);
this.mathEngine.setUseGroupingSeparator(true);
}
private static void migratePreference(@Nonnull SharedPreferences preferences, @Nonnull BooleanPreference preference, @Nonnull String oldKey, @Nonnull SharedPreferences.Editor editor) {
if (!preferences.contains(oldKey)) {
return;
}
editor.putBoolean(preference.getKey(), preferences.getBoolean(oldKey, false));
}
private static void migratePreference(@Nonnull SharedPreferences preferences, @Nonnull StringPreference<?> preference, @Nonnull String oldKey, @Nonnull SharedPreferences.Editor editor) {
if (!preferences.contains(oldKey)) {
return;
}
editor.putString(preference.getKey(), preferences.getString(oldKey, null));
}
public static boolean isValidName(@Nullable String name) {
if (!TextUtils.isEmpty(name)) {
try {
Identifier.parser.parse(Parser.Parameters.get(name), null);
return true;
} catch (jscl.text.ParseException e) {
// not valid name;
}
}
return false;
}
@Nonnull
public VariablesRegistry getVariablesRegistry() {
return variablesRegistry;
}
@Nonnull
public FunctionsRegistry getFunctionsRegistry() {
return functionsRegistry;
}
@Nonnull
public EntitiesRegistry<Operator> getOperatorsRegistry() {
return operatorsRegistry;
}
@Nonnull
public EntitiesRegistry<Operator> getPostfixFunctionsRegistry() {
return postfixFunctionsRegistry;
}
@Nonnull
public MathEngine getMathEngine() {
return mathEngine;
}
public void init(@Nonnull Executor initThread) {
Check.isMainThread();
checkPreferences();
preferences.registerOnSharedPreferenceChangeListener(this);
applyPreferences();
initThread.execute(new Runnable() {
@Override
public void run() {
initAsync();
}
});
}
private void checkPreferences() {
final int oldVersion;
if (Preferences.version.isSet(preferences)) {
oldVersion = Preferences.version.getPreference(preferences);
} else {
oldVersion = 0;
}
final int newVersion = Preferences.version.getDefaultValue();
if (oldVersion == newVersion) {
return;
}
final SharedPreferences.Editor editor = preferences.edit();
if (oldVersion == 0) {
migratePreference(preferences, Preferences.groupingSeparator, "org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator", editor);
migratePreference(preferences, Preferences.multiplicationSign, "org.solovyev.android.calculator.CalculatorActivity_calc_multiplication_sign", editor);
migratePreference(preferences, Preferences.numeralBase, "org.solovyev.android.calculator.CalculatorActivity_numeral_bases", editor);
migratePreference(preferences, Preferences.angleUnit, "org.solovyev.android.calculator.CalculatorActivity_angle_units", editor);
migratePreference(preferences, Preferences.Output.precision, "org.solovyev.android.calculator.CalculatorModel_result_precision", editor);
migratePreference(preferences, Preferences.Output.scientificNotation, "calculation.output.science_notation", editor);
migratePreference(preferences, Preferences.Output.round, "org.solovyev.android.calculator.CalculatorModel_round_result", editor);
}
Preferences.version.putDefault(editor);
editor.apply();
}
private void initAsync() {
init(variablesRegistry);
init(functionsRegistry);
init(operatorsRegistry);
init(postfixFunctionsRegistry);
}
private void init(@Nonnull EntitiesRegistry<?> registry) {
try {
registry.init();
} catch (Exception e) {
errorReporter.onException(e);
}
}
private void applyPreferences() {
Check.isMainThread();
mathEngine.setAngleUnits(Preferences.angleUnit.getPreference(preferences));
mathEngine.setNumeralBase(Preferences.numeralBase.getPreference(preferences));
setMultiplicationSign(Preferences.multiplicationSign.getPreference(preferences));
mathEngine.setPrecision(Preferences.Output.precision.getPreference(preferences));
mathEngine.setScienceNotation(Preferences.Output.scientificNotation.getPreference(preferences));
mathEngine.setRoundResult(Preferences.Output.round.getPreference(preferences));
final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences);
if (TextUtils.isEmpty(groupingSeparator)) {
mathEngine.setUseGroupingSeparator(false);
} else {
mathEngine.setUseGroupingSeparator(true);
mathEngine.setGroupingSeparator(groupingSeparator.charAt(0));
}
bus.post(ChangedEvent.INSTANCE);
}
@Nonnull
public String getMultiplicationSign() {
return this.multiplicationSign;
}
public void setMultiplicationSign(@Nonnull String multiplicationSign) {
this.multiplicationSign = multiplicationSign;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (Preferences.getPreferenceKeys().contains(key)) {
applyPreferences();
}
}
public static class ChangedEvent {
static final ChangedEvent INSTANCE = new ChangedEvent();
private ChangedEvent() {
}
}
public static class Preferences {
public static final StringPreference<String> groupingSeparator = StringPreference.of("engine.groupingSeparator", JsclMathEngine.GROUPING_SEPARATOR_DEFAULT);
public static final StringPreference<String> multiplicationSign = StringPreference.of("engine.multiplicationSign", "×");
public static final StringPreference<NumeralBase> numeralBase = StringPreference.ofTypedValue("engine.numeralBase", "dec", EnumMapper.of(NumeralBase.class));
public static final StringPreference<AngleUnit> angleUnit = StringPreference.ofTypedValue("engine.angleUnit", "deg", EnumMapper.of(AngleUnit.class));
public static final Preference<Integer> version = IntegerPreference.of("engine.version", 1);
private static final List<String> preferenceKeys = new ArrayList<>();
static {
preferenceKeys.add(groupingSeparator.getKey());
preferenceKeys.add(multiplicationSign.getKey());
preferenceKeys.add(numeralBase.getKey());
preferenceKeys.add(angleUnit.getKey());
preferenceKeys.add(Output.precision.getKey());
preferenceKeys.add(Output.scientificNotation.getKey());
preferenceKeys.add(Output.round.getKey());
}
@Nonnull
public static List<String> getPreferenceKeys() {
return Collections.unmodifiableList(preferenceKeys);
}
public static class Output {
public static final StringPreference<Integer> precision = StringPreference.ofTypedValue("engine.output.precision", "5", NumberMapper.of(Integer.class));
public static final BooleanPreference scientificNotation = BooleanPreference.of("engine.output.scientificNotation", false);
public static final BooleanPreference round = BooleanPreference.of("engine.output.round", true);
}
}
}