New architecture

This commit is contained in:
Sergey Solovyev 2012-09-23 18:25:15 +04:00
parent 233c685a49
commit f03c2496a6
27 changed files with 1002 additions and 759 deletions

View File

@ -1,85 +1,84 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import jscl.MathEngine; import jscl.NumeralBase;
import jscl.NumeralBase; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.common.text.StringUtils;
import org.solovyev.common.text.StringUtils;
/**
/** * User: serso
* User: serso * Date: 12/15/11
* Date: 12/15/11 * Time: 9:01 PM
* Time: 9:01 PM */
*/ public abstract class AbstractNumberBuilder {
public abstract class AbstractNumberBuilder {
@NotNull
@NotNull protected final CalculatorEngine engine;
protected final MathEngine engine;
@Nullable
@Nullable protected StringBuilder numberBuilder = null;
protected StringBuilder numberBuilder = null;
@Nullable
@Nullable protected NumeralBase nb;
protected NumeralBase nb;
protected AbstractNumberBuilder(@NotNull CalculatorEngine engine) {
protected AbstractNumberBuilder(@NotNull MathEngine engine) { this.engine = engine;
this.engine = engine; this.nb = engine.getNumeralBase();
this.nb = engine.getNumeralBase(); }
}
/**
/** * Method determines if we can continue to process current number
* Method determines if we can continue to process current number *
* * @param mathTypeResult current math type result
* @param mathTypeResult current math type result * @return true if we can continue of processing of current number, if false - new number should be constructed
* @return true if we can continue of processing of current number, if false - new number should be constructed */
*/ protected boolean canContinue(@NotNull MathType.Result mathTypeResult) {
protected boolean canContinue(@NotNull MathType.Result mathTypeResult) { boolean result = mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number &&
boolean result = mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number && !spaceBefore(mathTypeResult) &&
!spaceBefore(mathTypeResult) && numeralBaseCheck(mathTypeResult) &&
numeralBaseCheck(mathTypeResult) && numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult);
numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult); return result;
return result; }
}
private boolean spaceBefore(@NotNull MathType.Result mathTypeResult) {
private boolean spaceBefore(@NotNull MathType.Result mathTypeResult) { return numberBuilder == null && StringUtils.isEmpty(mathTypeResult.getMatch().trim());
return numberBuilder == null && StringUtils.isEmpty(mathTypeResult.getMatch().trim()); }
}
private boolean numeralBaseInTheStart(@NotNull MathType mathType) {
private boolean numeralBaseInTheStart(@NotNull MathType mathType) { return mathType != MathType.numeral_base || numberBuilder == null;
return mathType != MathType.numeral_base || numberBuilder == null; }
}
private boolean numeralBaseCheck(@NotNull MathType.Result mathType) {
private boolean numeralBaseCheck(@NotNull MathType.Result mathType) { return mathType.getMathType() != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.getMatch().charAt(0));
return mathType.getMathType() != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.getMatch().charAt(0)); }
}
private boolean isSignAfterE(@NotNull MathType.Result mathTypeResult) {
private boolean isSignAfterE(@NotNull MathType.Result mathTypeResult) { if (!isHexMode()) {
if (!isHexMode()) { if ("-".equals(mathTypeResult.getMatch()) || "+".equals(mathTypeResult.getMatch())) {
if ("-".equals(mathTypeResult.getMatch()) || "+".equals(mathTypeResult.getMatch())) { final StringBuilder localNb = numberBuilder;
final StringBuilder localNb = numberBuilder; if (localNb != null && localNb.length() > 0) {
if (localNb != null && localNb.length() > 0) { if (localNb.charAt(localNb.length() - 1) == MathType.POWER_10) {
if (localNb.charAt(localNb.length() - 1) == MathType.POWER_10) { return true;
return true; }
} }
} }
} }
} return false;
return false; }
}
public boolean isHexMode() {
public boolean isHexMode() { return nb == NumeralBase.hex || (nb == null && engine.getNumeralBase() == NumeralBase.hex);
return nb == NumeralBase.hex || (nb == null && engine.getNumeralBase() == NumeralBase.hex); }
}
@NotNull
@NotNull protected NumeralBase getNumeralBase() {
protected NumeralBase getNumeralBase() { return nb == null ? engine.getNumeralBase() : nb;
return nb == null ? engine.getNumeralBase() : nb; }
} }
}

View File

@ -15,6 +15,16 @@ import org.solovyev.common.history.HistoryControl;
*/ */
public interface Calculator extends CalculatorEventContainer, HistoryControl<CalculatorHistoryState> { public interface Calculator extends CalculatorEventContainer, HistoryControl<CalculatorHistoryState> {
void init();
/*
**********************************************************************
*
* CALCULATIONS
*
**********************************************************************
*/
void evaluate(); void evaluate();
void simplify(); void simplify();
@ -31,11 +41,16 @@ public interface Calculator extends CalculatorEventContainer, HistoryControl<Cal
@NotNull @NotNull
CalculatorEventDataId convert(@NotNull Generic generic, @NotNull NumeralBase to); CalculatorEventDataId convert(@NotNull Generic generic, @NotNull NumeralBase to);
/*
**********************************************************************
*
* EVENTS
*
**********************************************************************
*/
@NotNull @NotNull
CalculatorEventDataId fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data); CalculatorEventDataId fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data);
@NotNull @NotNull
CalculatorEventDataId fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data, @NotNull Long sequenceId); CalculatorEventDataId fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data, @NotNull Long sequenceId);
void init();
} }

View File

@ -1,11 +1,15 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import jscl.AngleUnit;
import jscl.MathEngine; import jscl.MathEngine;
import jscl.NumeralBase;
import jscl.math.function.Function; import jscl.math.function.Function;
import jscl.math.function.IConstant; import jscl.math.function.IConstant;
import jscl.math.operator.Operator; import jscl.math.operator.Operator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.text.DecimalFormatSymbols;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 20.09.12 * Date: 20.09.12
@ -13,8 +17,27 @@ import org.jetbrains.annotations.NotNull;
*/ */
public interface CalculatorEngine { public interface CalculatorEngine {
@NotNull /*
String getMultiplicationSign(); **********************************************************************
*
* INIT
*
**********************************************************************
*/
void init();
void reset();
void softReset();
/*
**********************************************************************
*
* REGISTRIES
*
**********************************************************************
*/
@NotNull @NotNull
CalculatorMathRegistry<IConstant> getVarsRegistry(); CalculatorMathRegistry<IConstant> getVarsRegistry();
@ -29,11 +52,46 @@ public interface CalculatorEngine {
CalculatorMathRegistry<Operator> getPostfixFunctionsRegistry(); CalculatorMathRegistry<Operator> getPostfixFunctionsRegistry();
@NotNull @NotNull
MathEngine getEngine(); CalculatorMathEngine getMathEngine();
void init(); @Deprecated
@NotNull
MathEngine getMathEngine0();
void reset(); /*
**********************************************************************
*
* PREFERENCES
*
**********************************************************************
*/
void softReset(); @NotNull
String getMultiplicationSign();
void setUseGroupingSeparator(boolean useGroupingSeparator);
void setGroupingSeparator(char groupingSeparator);
void setPrecision(@NotNull Integer precision);
void setRoundResult(@NotNull Boolean round);
@NotNull
AngleUnit getAngleUnits();
void setAngleUnits(@NotNull AngleUnit angleUnits);
@NotNull
NumeralBase getNumeralBase();
void setNumeralBase(@NotNull NumeralBase numeralBase);
void setMultiplicationSign(@NotNull String multiplicationSign);
void setScienceNotation(@NotNull Boolean scienceNotation);
void setTimeout(@NotNull Integer timeout);
void setDecimalGroupSymbols(@NotNull DecimalFormatSymbols decimalGroupSymbols);
} }

View File

@ -0,0 +1,320 @@
package org.solovyev.android.calculator;
import jscl.AngleUnit;
import jscl.JsclMathEngine;
import jscl.MathEngine;
import jscl.NumeralBase;
import jscl.math.Generic;
import jscl.math.function.Function;
import jscl.math.function.IConstant;
import jscl.math.operator.Operator;
import jscl.text.ParseException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormatSymbols;
/**
* User: serso
* Date: 9/23/12
* Time: 5:34 PM
*/
public class CalculatorEngineImpl implements CalculatorEngine {
/*
**********************************************************************
*
* CONSTANTS
*
**********************************************************************
*/
private static final String MULTIPLICATION_SIGN_DEFAULT = "×";
private static final String MAX_CALCULATION_TIME_DEFAULT = "5";
/*
**********************************************************************
*
* ENGINE/REGISTRIES
*
**********************************************************************
*/
@NotNull
private final MathEngine engine;
@NotNull
private final CalculatorMathEngine mathEngine;
@NotNull
private final CalculatorMathRegistry<IConstant> varsRegistry;
@NotNull
private final CalculatorMathRegistry<Function> functionsRegistry;
@NotNull
private final CalculatorMathRegistry<Operator> operatorsRegistry;
@NotNull
private final CalculatorMathRegistry<Operator> postfixFunctionsRegistry;
@NotNull
private final Object lock;
/*
**********************************************************************
*
* PREFERENCES
*
**********************************************************************
*/
private int timeout = Integer.valueOf(MAX_CALCULATION_TIME_DEFAULT);
@NotNull
private String multiplicationSign = MULTIPLICATION_SIGN_DEFAULT;
public CalculatorEngineImpl(@NotNull JsclMathEngine engine,
@NotNull CalculatorMathRegistry<IConstant> varsRegistry,
@NotNull CalculatorMathRegistry<Function> functionsRegistry,
@NotNull CalculatorMathRegistry<Operator> operatorsRegistry,
@NotNull CalculatorMathRegistry<Operator> postfixFunctionsRegistry,
@Nullable Object lock) {
this.engine = engine;
this.mathEngine = new JsclCalculatorMathEngine(engine);
this.engine.setRoundResult(true);
this.engine.setUseGroupingSeparator(true);
this.varsRegistry = varsRegistry;
this.functionsRegistry = functionsRegistry;
this.operatorsRegistry = operatorsRegistry;
this.postfixFunctionsRegistry = postfixFunctionsRegistry;
this.lock = lock == null ? new Object() : lock;
}
/*
**********************************************************************
*
* REGISTRIES
*
**********************************************************************
*/
@NotNull
@Override
public CalculatorMathRegistry<IConstant> getVarsRegistry() {
return this.varsRegistry;
}
@NotNull
@Override
public CalculatorMathRegistry<Function> getFunctionsRegistry() {
return this.functionsRegistry;
}
@NotNull
@Override
public CalculatorMathRegistry<Operator> getOperatorsRegistry() {
return this.operatorsRegistry;
}
@NotNull
@Override
public CalculatorMathRegistry<Operator> getPostfixFunctionsRegistry() {
return this.postfixFunctionsRegistry;
}
@NotNull
@Override
public CalculatorMathEngine getMathEngine() {
return this.mathEngine;
}
@NotNull
@Override
public MathEngine getMathEngine0() {
return this.engine;
}
/*
**********************************************************************
*
* INIT
*
**********************************************************************
*/
@Override
public void init() {
synchronized (lock) {
reset();
}
}
@Override
public void reset() {
synchronized (lock) {
varsRegistry.load();
functionsRegistry.load();
operatorsRegistry.load();
postfixFunctionsRegistry.load();
}
}
@Override
public void softReset() {
// do nothing
}
/*
**********************************************************************
*
* PREFERENCES
*
**********************************************************************
*/
@NotNull
@Override
public String getMultiplicationSign() {
return this.multiplicationSign;
}
@Override
public void setUseGroupingSeparator(boolean useGroupingSeparator) {
synchronized (lock) {
this.engine.setUseGroupingSeparator(true);
}
}
@Override
public void setGroupingSeparator(char groupingSeparator) {
synchronized (lock) {
this.engine.setGroupingSeparator(groupingSeparator);
}
}
@Override
public void setPrecision(@NotNull Integer precision) {
synchronized (lock) {
this.engine.setPrecision(precision);
}
}
@Override
public void setRoundResult(@NotNull Boolean round) {
synchronized (lock) {
this.engine.setRoundResult(round);
}
}
@NotNull
@Override
public AngleUnit getAngleUnits() {
synchronized (lock) {
return this.engine.getAngleUnits();
}
}
@Override
public void setAngleUnits(@NotNull AngleUnit angleUnits) {
synchronized (lock) {
this.engine.setAngleUnits(angleUnits);
}
}
@NotNull
@Override
public NumeralBase getNumeralBase() {
synchronized (lock) {
return this.engine.getNumeralBase();
}
}
@Override
public void setNumeralBase(@NotNull NumeralBase numeralBase) {
synchronized (lock) {
this.engine.setNumeralBase(numeralBase);
}
}
@Override
public void setMultiplicationSign(@NotNull String multiplicationSign) {
this.multiplicationSign = multiplicationSign;
}
@Override
public void setScienceNotation(@NotNull Boolean scienceNotation) {
synchronized (lock) {
this.engine.setScienceNotation(scienceNotation);
}
}
@Override
public void setTimeout(@NotNull Integer timeout) {
this.timeout = timeout;
}
@Override
public void setDecimalGroupSymbols(@NotNull DecimalFormatSymbols decimalGroupSymbols) {
synchronized (lock) {
this.engine.setDecimalGroupSymbols(decimalGroupSymbols);
}
}
/*
**********************************************************************
*
* STATIC CLASSES
*
**********************************************************************
*/
private static final class JsclCalculatorMathEngine implements CalculatorMathEngine {
@NotNull
private final MathEngine mathEngine;
private JsclCalculatorMathEngine(@NotNull MathEngine mathEngine) {
this.mathEngine = mathEngine;
}
@NotNull
@Override
public String evaluate(@NotNull String expression) throws ParseException {
return this.mathEngine.evaluate(expression);
}
@NotNull
@Override
public String simplify(@NotNull String expression) throws ParseException {
return this.mathEngine.simplify(expression);
}
@NotNull
@Override
public String elementary(@NotNull String expression) throws ParseException {
return this.mathEngine.elementary(expression);
}
@NotNull
@Override
public Generic evaluateGeneric(@NotNull String expression) throws ParseException {
return this.mathEngine.evaluateGeneric(expression);
}
@NotNull
@Override
public Generic simplifyGeneric(@NotNull String expression) throws ParseException {
return this.mathEngine.simplifyGeneric(expression);
}
@NotNull
@Override
public Generic elementaryGeneric(@NotNull String expression) throws ParseException {
return this.mathEngine.elementaryGeneric(expression);
}
}
}

View File

@ -149,7 +149,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
fireCalculatorEvent(newConversionEventData(sequenceId), CalculatorEventType.conversion_started, null); fireCalculatorEvent(newConversionEventData(sequenceId), CalculatorEventType.conversion_started, null);
final NumeralBase from = CalculatorLocatorImpl.getInstance().getEngine().getEngine().getNumeralBase(); final NumeralBase from = CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase();
if (from != to) { if (from != to) {
String fromString = generic.toString(); String fromString = generic.toString();
@ -236,7 +236,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
try { try {
final Generic result = operation.evaluateGeneric(jsclExpression); final Generic result = operation.evaluateGeneric(jsclExpression, CalculatorLocatorImpl.getInstance().getEngine().getMathEngine());
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!) // NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!)
result.toString(); result.toString();

View File

@ -0,0 +1,31 @@
package org.solovyev.android.calculator;
import jscl.math.Generic;
import jscl.text.ParseException;
import org.jetbrains.annotations.NotNull;
/**
* User: serso
* Date: 9/23/12
* Time: 6:05 PM
*/
public interface CalculatorMathEngine {
@NotNull
String evaluate(@NotNull String expression) throws ParseException;
@NotNull
String simplify(@NotNull String expression) throws ParseException;
@NotNull
String elementary(@NotNull String expression) throws ParseException;
@NotNull
Generic evaluateGeneric(@NotNull String expression) throws ParseException;
@NotNull
Generic simplifyGeneric(@NotNull String expression) throws ParseException;
@NotNull
Generic elementaryGeneric(@NotNull String expression) throws ParseException;
}

View File

@ -1,55 +1,54 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import jscl.MathEngine; import jscl.NumeralBase;
import jscl.NumeralBase; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.NotNull; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.math.MathType;
/**
/** * User: serso
* User: serso * Date: 12/15/11
* Date: 12/15/11 * Time: 8:33 PM
* Time: 8:33 PM */
*/
public class LiteNumberBuilder extends AbstractNumberBuilder {
public class LiteNumberBuilder extends AbstractNumberBuilder {
public LiteNumberBuilder(@NotNull CalculatorEngine engine) {
public LiteNumberBuilder(@NotNull MathEngine engine) { super(engine);
super(engine); this.nb = engine.getNumeralBase();
this.nb = engine.getNumeralBase(); }
}
public void process(@NotNull MathType.Result mathTypeResult) {
public void process(@NotNull MathType.Result mathTypeResult) { if (canContinue(mathTypeResult)) {
if (canContinue(mathTypeResult)) { // let's continue building number
// let's continue building number if (numberBuilder == null) {
if (numberBuilder == null) { // if new number => create new builder
// if new number => create new builder numberBuilder = new StringBuilder();
numberBuilder = new StringBuilder(); }
}
if (mathTypeResult.getMathType() != MathType.numeral_base) {
if (mathTypeResult.getMathType() != MathType.numeral_base) { // just add matching string
// just add matching string numberBuilder.append(mathTypeResult.getMatch());
numberBuilder.append(mathTypeResult.getMatch()); } else {
} else { // set explicitly numeral base (do not include it into number)
// set explicitly numeral base (do not include it into number) nb = NumeralBase.getByPrefix(mathTypeResult.getMatch());
nb = NumeralBase.getByPrefix(mathTypeResult.getMatch()); }
}
} else {
} else { // process current number (and go to the next one)
// process current number (and go to the next one) if (numberBuilder != null) {
if (numberBuilder != null) { numberBuilder = null;
numberBuilder = null;
// must set default numeral base (exit numeral base mode)
// must set default numeral base (exit numeral base mode) nb = engine.getNumeralBase();
nb = engine.getNumeralBase(); }
} }
} }
}
}
}

View File

@ -1,203 +1,202 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import jscl.MathContext; import jscl.MathContext;
import jscl.MathEngine; import jscl.MathEngine;
import jscl.NumeralBase; import jscl.NumeralBase;
import jscl.math.numeric.Real; import jscl.math.numeric.Real;
import jscl.text.*; import jscl.text.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.AbstractNumberBuilder; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.common.MutableObject;
import org.solovyev.common.MutableObject;
import java.util.ArrayList;
import java.util.ArrayList; import java.util.List;
import java.util.List;
/**
/** * User: serso
* User: serso * Date: 10/23/11
* Date: 10/23/11 * Time: 2:57 PM
* Time: 2:57 PM */
*/ public class NumberBuilder extends AbstractNumberBuilder {
public class NumberBuilder extends AbstractNumberBuilder {
public NumberBuilder(@NotNull CalculatorEngine engine) {
public NumberBuilder(@NotNull MathEngine engine) { super(engine);
super(engine); }
}
/**
/** * Method replaces number in text according to some rules (e.g. formatting)
* Method replaces number in text according to some rules (e.g. formatting) *
* * @param text text where number can be replaced
* @param text text where number can be replaced * @param mathTypeResult math type result of current token
* @param mathTypeResult math type result of current token * @param offset offset between new number length and old number length (newNumberLength - oldNumberLength)
* @param offset offset between new number length and old number length (newNumberLength - oldNumberLength) *
* *
* * @return new math type result (as one can be changed due to substituting of number with constant)
* @return new math type result (as one can be changed due to substituting of number with constant) */
*/ @NotNull
@NotNull public MathType.Result process(@NotNull StringBuilder text, @NotNull MathType.Result mathTypeResult, @Nullable MutableObject<Integer> offset) {
public MathType.Result process(@NotNull StringBuilder text, @NotNull MathType.Result mathTypeResult, @Nullable MutableObject<Integer> offset) { final MathType.Result possibleResult;
final MathType.Result possibleResult; if (canContinue(mathTypeResult)) {
if (canContinue(mathTypeResult)) { // let's continue building number
// let's continue building number if (numberBuilder == null) {
if (numberBuilder == null) { // if new number => create new builder
// if new number => create new builder numberBuilder = new StringBuilder();
numberBuilder = new StringBuilder(); }
}
if (mathTypeResult.getMathType() != MathType.numeral_base) {
if (mathTypeResult.getMathType() != MathType.numeral_base) { // just add matching string
// just add matching string numberBuilder.append(mathTypeResult.getMatch());
numberBuilder.append(mathTypeResult.getMatch()); } else {
} else { // set explicitly numeral base (do not include it into number)
// set explicitly numeral base (do not include it into number) nb = NumeralBase.getByPrefix(mathTypeResult.getMatch());
nb = NumeralBase.getByPrefix(mathTypeResult.getMatch()); }
}
possibleResult = null;
possibleResult = null; } else {
} else { // process current number (and go to the next one)
// process current number (and go to the next one) possibleResult = processNumber(text, offset);
possibleResult = processNumber(text, offset); }
}
return possibleResult == null ? mathTypeResult : possibleResult;
return possibleResult == null ? mathTypeResult : possibleResult; }
}
/**
/** * Method replaces number in text according to some rules (e.g. formatting)
* Method replaces number in text according to some rules (e.g. formatting) *
* * @param text text where number can be replaced
* @param text text where number can be replaced * @param offset offset between new number length and old number length (newNumberLength - oldNumberLength)
* @param offset offset between new number length and old number length (newNumberLength - oldNumberLength) *
* * @return new math type result (as one can be changed due to substituting of number with constant)
* @return new math type result (as one can be changed due to substituting of number with constant) */
*/ @Nullable
@Nullable public MathType.Result processNumber(@NotNull StringBuilder text, @Nullable MutableObject<Integer> offset) {
public MathType.Result processNumber(@NotNull StringBuilder text, @Nullable MutableObject<Integer> offset) { // total number of trimmed chars
// total number of trimmed chars int trimmedChars = 0;
int trimmedChars = 0;
String number = null;
String number = null;
// toXml numeral base (as later it might be replaced)
// toXml numeral base (as later it might be replaced) final NumeralBase localNb = getNumeralBase();
final NumeralBase localNb = getNumeralBase();
if (numberBuilder != null) {
if (numberBuilder != null) { try {
try { number = numberBuilder.toString();
number = numberBuilder.toString();
// let's get rid of unnecessary characters (grouping separators, + after E)
// let's get rid of unnecessary characters (grouping separators, + after E) final List<String> tokens = new ArrayList<String>();
final List<String> tokens = new ArrayList<String>(); tokens.addAll(MathType.grouping_separator.getTokens());
tokens.addAll(MathType.grouping_separator.getTokens()); // + after E can be omitted: 10+E = 10E (NOTE: - cannot be omitted )
// + after E can be omitted: 10+E = 10E (NOTE: - cannot be omitted ) tokens.add("+");
tokens.add("+"); for (String groupingSeparator : tokens) {
for (String groupingSeparator : tokens) { final String trimmedNumber = number.replace(groupingSeparator, "");
final String trimmedNumber = number.replace(groupingSeparator, ""); trimmedChars += number.length() - trimmedNumber.length();
trimmedChars += number.length() - trimmedNumber.length(); number = trimmedNumber;
number = trimmedNumber; }
}
// check if number still valid
// check if number still valid toDouble(number, getNumeralBase(), engine.getMathEngine0());
toDouble(number, getNumeralBase(), engine);
} catch (NumberFormatException e) {
} catch (NumberFormatException e) { // number is not valid => stop
// number is not valid => stop number = null;
number = null; }
}
numberBuilder = null;
numberBuilder = null;
// must set default numeral base (exit numeral base mode)
// must set default numeral base (exit numeral base mode) nb = engine.getNumeralBase();
nb = engine.getNumeralBase(); }
}
return replaceNumberInText(text, number, trimmedChars, offset, localNb, engine.getMathEngine0());
return replaceNumberInText(text, number, trimmedChars, offset, localNb, engine); }
}
@Nullable
@Nullable private static MathType.Result replaceNumberInText(@NotNull StringBuilder text,
private static MathType.Result replaceNumberInText(@NotNull StringBuilder text, @Nullable String number,
@Nullable String number, int trimmedChars,
int trimmedChars, @Nullable MutableObject<Integer> offset,
@Nullable MutableObject<Integer> offset, @NotNull NumeralBase nb,
@NotNull NumeralBase nb, @NotNull final MathEngine engine) {
@NotNull final MathEngine engine) { MathType.Result result = null;
MathType.Result result = null;
if (number != null) {
if (number != null) { // in any case remove old number from text
// in any case remove old number from text final int oldNumberLength = number.length() + trimmedChars;
final int oldNumberLength = number.length() + trimmedChars; text.delete(text.length() - oldNumberLength, text.length());
text.delete(text.length() - oldNumberLength, text.length());
final String newNumber = formatNumber(number, nb, engine);
final String newNumber = formatNumber(number, nb, engine); if (offset != null) {
if (offset != null) { // register offset between old number and new number
// register offset between old number and new number offset.setObject(newNumber.length() - oldNumberLength);
offset.setObject(newNumber.length() - oldNumberLength); }
} text.append(newNumber);
text.append(newNumber); }
}
return result;
return result; }
}
@NotNull
@NotNull private static String formatNumber(@NotNull String number, @NotNull NumeralBase nb, @NotNull MathEngine engine) {
private static String formatNumber(@NotNull String number, @NotNull NumeralBase nb, @NotNull MathEngine engine) { String result;
String result;
int indexOfDot = number.indexOf('.');
int indexOfDot = number.indexOf('.');
if (indexOfDot < 0) {
if (indexOfDot < 0) { int indexOfE;
int indexOfE; if (nb == NumeralBase.hex) {
if (nb == NumeralBase.hex) { indexOfE = -1;
indexOfE = -1; } else {
} else { indexOfE = number.indexOf(MathType.POWER_10);
indexOfE = number.indexOf(MathType.POWER_10); }
} if (indexOfE < 0) {
if (indexOfE < 0) { result = engine.addGroupingSeparators(nb, number);
result = engine.addGroupingSeparators(nb, number); } else {
} else { final String partBeforeE;
final String partBeforeE; if (indexOfE != 0) {
if (indexOfE != 0) { partBeforeE = engine.addGroupingSeparators(nb, number.substring(0, indexOfE));
partBeforeE = engine.addGroupingSeparators(nb, number.substring(0, indexOfE)); } else {
} else { partBeforeE = "";
partBeforeE = ""; }
} result = partBeforeE + number.substring(indexOfE);
result = partBeforeE + number.substring(indexOfE); }
} } else {
} else { final String integerPart;
final String integerPart; if (indexOfDot != 0) {
if (indexOfDot != 0) { integerPart = engine.addGroupingSeparators(nb, number.substring(0, indexOfDot));
integerPart = engine.addGroupingSeparators(nb, number.substring(0, indexOfDot)); } else {
} else { integerPart = "";
integerPart = ""; }
} result = integerPart + number.substring(indexOfDot);
result = integerPart + number.substring(indexOfDot); }
}
return result;
return result; }
}
@NotNull
@NotNull private static Double toDouble(@NotNull String s, @NotNull NumeralBase nb, @NotNull final MathContext mc) throws NumberFormatException {
private static Double toDouble(@NotNull String s, @NotNull NumeralBase nb, @NotNull final MathContext mc) throws NumberFormatException { final NumeralBase defaultNb = mc.getNumeralBase();
final NumeralBase defaultNb = mc.getNumeralBase(); try {
try { mc.setNumeralBase(nb);
mc.setNumeralBase(nb);
try {
try { return JsclIntegerParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content().doubleValue();
return JsclIntegerParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content().doubleValue(); } catch (ParseException e) {
} catch (ParseException e) { try {
try { return ((Real) DoubleParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content()).doubleValue();
return ((Real) DoubleParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content()).doubleValue(); } catch (ParseException e1) {
} catch (ParseException e1) { throw new NumberFormatException();
throw new NumberFormatException(); }
} }
}
} finally {
} finally { mc.setNumeralBase(defaultNb);
mc.setNumeralBase(defaultNb); }
} }
} }
}

View File

@ -52,7 +52,7 @@ public class ToJsclTextProcessor implements TextProcessor<PreparedExpression, St
MathType.Result mathTypeResult = null; MathType.Result mathTypeResult = null;
MathType.Result mathTypeBefore; MathType.Result mathTypeBefore;
final LiteNumberBuilder nb = new LiteNumberBuilder(CalculatorLocatorImpl.getInstance().getEngine().getEngine()); final LiteNumberBuilder nb = new LiteNumberBuilder(CalculatorLocatorImpl.getInstance().getEngine());
for (int i = 0; i < s.length(); i++) { for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') continue; if (s.charAt(i) == ' ') continue;
startsWithFinder.setI(i); startsWithFinder.setI(i);

View File

@ -9,7 +9,7 @@ package org.solovyev.android.calculator.jscl;
import jscl.math.Generic; import jscl.math.Generic;
import jscl.text.ParseException; import jscl.text.ParseException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.CalculatorLocatorImpl; import org.solovyev.android.calculator.CalculatorMathEngine;
import org.solovyev.android.calculator.text.DummyTextProcessor; import org.solovyev.android.calculator.text.DummyTextProcessor;
import org.solovyev.android.calculator.text.FromJsclSimplifyTextProcessor; import org.solovyev.android.calculator.text.FromJsclSimplifyTextProcessor;
import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.text.TextProcessor;
@ -39,28 +39,28 @@ public enum JsclOperation {
} }
@NotNull @NotNull
public final String evaluate(@NotNull String expression) throws ParseException { public final String evaluate(@NotNull String expression, @NotNull CalculatorMathEngine engine) throws ParseException {
switch (this) { switch (this) {
case simplify: case simplify:
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().simplify(expression); return engine.simplify(expression);
case elementary: case elementary:
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().elementary(expression); return engine.elementary(expression);
case numeric: case numeric:
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().evaluate(expression); return engine.evaluate(expression);
default: default:
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }
@NotNull @NotNull
public final Generic evaluateGeneric(@NotNull String expression) throws ParseException { public final Generic evaluateGeneric(@NotNull String expression, @NotNull CalculatorMathEngine engine) throws ParseException {
switch (this) { switch (this) {
case simplify: case simplify:
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().simplifyGeneric(expression); return engine.simplifyGeneric(expression);
case elementary: case elementary:
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().elementaryGeneric(expression); return engine.elementaryGeneric(expression);
case numeric: case numeric:
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().evaluateGeneric(expression); return engine.evaluateGeneric(expression);
default: default:
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -15,4 +15,4 @@
a:layout_width="fill_parent" a:layout_width="fill_parent"
a:layout_height="fill_parent" a:layout_height="fill_parent"
style="?controlButtonStyle" style="?controlButtonStyle"
a:onClick="numericButtonClickHandler"/> a:onClick="equalsButtonClickHandler"/>

View File

@ -37,7 +37,7 @@ public class AndroidCalculator implements Calculator {
/* /*
********************************************************************** **********************************************************************
* *
* DELETED TO CALCULATOR * DELEGATED TO CALCULATOR
* *
********************************************************************** **********************************************************************
*/ */

View File

@ -32,7 +32,7 @@ public class AndroidCalculatorDisplayView extends AutoResizeTextView implements
*/ */
@NotNull @NotNull
private final static TextProcessor<TextHighlighter.Result, String> textHighlighter = new TextHighlighter(Color.WHITE, false, CalculatorLocatorImpl.getInstance().getEngine().getEngine()); private final static TextProcessor<TextHighlighter.Result, String> textHighlighter = new TextHighlighter(Color.WHITE, false);
/* /*
********************************************************************** **********************************************************************

View File

@ -31,7 +31,7 @@ public class AndroidCalculatorEditorView extends EditText implements SharedPrefe
private boolean highlightText = true; private boolean highlightText = true;
@NotNull @NotNull
private final static TextProcessor<TextHighlighter.Result, String> textHighlighter = new TextHighlighter(Color.WHITE, true, CalculatorLocatorImpl.getInstance().getEngine().getEngine()); private final static TextProcessor<TextHighlighter.Result, String> textHighlighter = new TextHighlighter(Color.WHITE, true);
@NotNull @NotNull
private volatile CalculatorEditorViewState viewState = CalculatorEditorViewStateImpl.newDefaultInstance(); private volatile CalculatorEditorViewState viewState = CalculatorEditorViewStateImpl.newDefaultInstance();

View File

@ -531,7 +531,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
} }
@SuppressWarnings({"UnusedDeclaration"}) @SuppressWarnings({"UnusedDeclaration"})
public void numericButtonClickHandler(@NotNull View v) { public void equalsButtonClickHandler(@NotNull View v) {
getCalculator().evaluate(); getCalculator().evaluate();
} }
@ -655,8 +655,6 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
if (!theme.equals(newTheme) || !layout.equals(newLayout)) { if (!theme.equals(newTheme) || !layout.equals(newLayout)) {
AndroidUtils.restartActivity(this); AndroidUtils.restartActivity(this);
} }
getCalculator().evaluate();
} }
@Override @Override
@ -674,13 +672,6 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
dpclRegister.announce().onDragPreferencesChange(SimpleOnDragListener.getPreferences(preferences, this)); dpclRegister.announce().onDragPreferencesChange(SimpleOnDragListener.getPreferences(preferences, this));
} }
if (AndroidCalculatorEngine.Preferences.getPreferenceKeys().contains(key)) {
CalculatorLocatorImpl.getInstance().getEngine().softReset();
// reevaluate in order to update values (in case of preferences changed from the main window, like numeral bases and angle units)
this.getCalculator().evaluate();
}
if ( CalculatorPreferences.Gui.usePrevAsBack.getKey().equals(key) ) { if ( CalculatorPreferences.Gui.usePrevAsBack.getKey().equals(key) ) {
useBackAsPrev = CalculatorPreferences.Gui.usePrevAsBack.getPreference(preferences); useBackAsPrev = CalculatorPreferences.Gui.usePrevAsBack.getPreference(preferences);
} }

View File

@ -42,7 +42,7 @@ enum ConversionMenuItem implements AMenuItem<CalculatorDisplayViewState> {
@Override @Override
public void onClick(@NotNull CalculatorDisplayViewState data, @NotNull Context context) { public void onClick(@NotNull CalculatorDisplayViewState data, @NotNull Context context) {
final NumeralBase fromNumeralBase = CalculatorLocatorImpl.getInstance().getEngine().getEngine().getNumeralBase(); final NumeralBase fromNumeralBase = CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase();
final Generic lastResult = data.getResult(); final Generic lastResult = data.getResult();

View File

@ -160,7 +160,7 @@ public class FunctionEditorSaver implements DialogInterface.OnClickListener{
if (!StringUtils.isEmpty(name)) { if (!StringUtils.isEmpty(name)) {
try { try {
assert name != null; assert name != null;
Identifier.parser.parse(Parser.Parameters.newInstance(name, new MutableInt(0), CalculatorLocatorImpl.getInstance().getEngine().getEngine()), null); Identifier.parser.parse(Parser.Parameters.newInstance(name, new MutableInt(0), CalculatorLocatorImpl.getInstance().getEngine().getMathEngine0()), null);
result = true; result = true;
} catch (ParseException e) { } catch (ParseException e) {
// not valid name; // not valid name;

View File

@ -157,7 +157,7 @@ class VarEditorSaver<T extends MathEntity> implements DialogInterface.OnClickLis
if (!StringUtils.isEmpty(name)) { if (!StringUtils.isEmpty(name)) {
try { try {
assert name != null; assert name != null;
Identifier.parser.parse(Parser.Parameters.newInstance(name, new MutableInt(0), CalculatorLocatorImpl.getInstance().getEngine().getEngine()), null); Identifier.parser.parse(Parser.Parameters.newInstance(name, new MutableInt(0), CalculatorLocatorImpl.getInstance().getEngine().getMathEngine0()), null);
result = true; result = true;
} catch (ParseException e) { } catch (ParseException e) {
// not valid name; // not valid name;

View File

@ -9,24 +9,21 @@ import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import jscl.*; import jscl.AngleUnit;
import jscl.math.Generic; import jscl.JsclMathEngine;
import jscl.MathEngine;
import jscl.NumeralBase;
import jscl.math.function.Function; import jscl.math.function.Function;
import jscl.math.function.IConstant; import jscl.math.function.IConstant;
import jscl.math.operator.Operator; import jscl.math.operator.Operator;
import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.CalculatorEngine;
import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.CalculatorEngineImpl;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.CalculatorMathEngine;
import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.CalculatorMathRegistry;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.android.prefs.BooleanPreference; import org.solovyev.android.prefs.BooleanPreference;
import org.solovyev.android.prefs.Preference; import org.solovyev.android.prefs.Preference;
import org.solovyev.android.prefs.StringPreference; import org.solovyev.android.prefs.StringPreference;
import org.solovyev.common.MutableObject;
import org.solovyev.common.msg.MessageRegistry;
import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.EnumMapper; import org.solovyev.common.text.EnumMapper;
import org.solovyev.common.text.NumberMapper; import org.solovyev.common.text.NumberMapper;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.text.StringUtils;
@ -35,8 +32,6 @@ import java.text.DecimalFormatSymbols;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** /**
* User: serso * User: serso
@ -46,270 +41,199 @@ import java.util.concurrent.TimeUnit;
public class AndroidCalculatorEngine implements CalculatorEngine { public class AndroidCalculatorEngine implements CalculatorEngine {
private static final String GROUPING_SEPARATOR_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator"; private static final String GROUPING_SEPARATOR_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator";
private static final String MULTIPLICATION_SIGN_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_multiplication_sign"; private static final String MULTIPLICATION_SIGN_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_multiplication_sign";
private static final String MULTIPLICATION_SIGN_DEFAULT = "×"; private static final String MULTIPLICATION_SIGN_DEFAULT = "×";
private static final String MAX_CALCULATION_TIME_P_KEY = "calculation.max_calculation_time"; private static final String MAX_CALCULATION_TIME_P_KEY = "calculation.max_calculation_time";
private static final String MAX_CALCULATION_TIME_DEFAULT = "5"; private static final String MAX_CALCULATION_TIME_DEFAULT = "5";
private static final String SCIENCE_NOTATION_P_KEY = "calculation.output.science_notation"; private static final String SCIENCE_NOTATION_P_KEY = "calculation.output.science_notation";
private static final boolean SCIENCE_NOTATION_DEFAULT = false; private static final boolean SCIENCE_NOTATION_DEFAULT = false;
private static final String ROUND_RESULT_P_KEY = "org.solovyev.android.calculator.CalculatorModel_round_result"; private static final String ROUND_RESULT_P_KEY = "org.solovyev.android.calculator.CalculatorModel_round_result";
private static final boolean ROUND_RESULT_DEFAULT = true; private static final boolean ROUND_RESULT_DEFAULT = true;
private static final String RESULT_PRECISION_P_KEY = "org.solovyev.android.calculator.CalculatorModel_result_precision"; private static final String RESULT_PRECISION_P_KEY = "org.solovyev.android.calculator.CalculatorModel_result_precision";
private static final String RESULT_PRECISION_DEFAULT = "5"; private static final String RESULT_PRECISION_DEFAULT = "5";
private static final String NUMERAL_BASES_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_numeral_bases"; private static final String NUMERAL_BASES_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_numeral_bases";
private static final String NUMERAL_BASES_DEFAULT = "dec"; private static final String NUMERAL_BASES_DEFAULT = "dec";
private static final String ANGLE_UNITS_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_angle_units"; private static final String ANGLE_UNITS_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_angle_units";
private static final String ANGLE_UNITS_DEFAULT = "deg"; private static final String ANGLE_UNITS_DEFAULT = "deg";
public static class Preferences { public static class Preferences {
public static final Preference<String> groupingSeparator = StringPreference.newInstance(GROUPING_SEPARATOR_P_KEY, JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); public static final Preference<String> groupingSeparator = StringPreference.newInstance(GROUPING_SEPARATOR_P_KEY, JsclMathEngine.GROUPING_SEPARATOR_DEFAULT);
public static final Preference<String> multiplicationSign = StringPreference.newInstance(MULTIPLICATION_SIGN_P_KEY, MULTIPLICATION_SIGN_DEFAULT); public static final Preference<String> multiplicationSign = StringPreference.newInstance(MULTIPLICATION_SIGN_P_KEY, MULTIPLICATION_SIGN_DEFAULT);
public static final Preference<Integer> precision = StringPreference.newInstance(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT, new NumberMapper<Integer>(Integer.class)); public static final Preference<Integer> precision = StringPreference.newInstance(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT, new NumberMapper<Integer>(Integer.class));
public static final Preference<Boolean> roundResult = new BooleanPreference(ROUND_RESULT_P_KEY, ROUND_RESULT_DEFAULT); public static final Preference<Boolean> roundResult = new BooleanPreference(ROUND_RESULT_P_KEY, ROUND_RESULT_DEFAULT);
public static final Preference<NumeralBase> numeralBase = StringPreference.newInstance(NUMERAL_BASES_P_KEY, NUMERAL_BASES_DEFAULT, EnumMapper.newInstance(NumeralBase.class)); public static final Preference<NumeralBase> numeralBase = StringPreference.newInstance(NUMERAL_BASES_P_KEY, NUMERAL_BASES_DEFAULT, EnumMapper.newInstance(NumeralBase.class));
public static final Preference<AngleUnit> angleUnit = StringPreference.newInstance(ANGLE_UNITS_P_KEY, ANGLE_UNITS_DEFAULT, EnumMapper.newInstance(AngleUnit.class)); public static final Preference<AngleUnit> angleUnit = StringPreference.newInstance(ANGLE_UNITS_P_KEY, ANGLE_UNITS_DEFAULT, EnumMapper.newInstance(AngleUnit.class));
public static final Preference<Boolean> scienceNotation = new BooleanPreference(SCIENCE_NOTATION_P_KEY, SCIENCE_NOTATION_DEFAULT); public static final Preference<Boolean> scienceNotation = new BooleanPreference(SCIENCE_NOTATION_P_KEY, SCIENCE_NOTATION_DEFAULT);
public static final Preference<Integer> maxCalculationTime = StringPreference.newInstance(MAX_CALCULATION_TIME_P_KEY, MAX_CALCULATION_TIME_DEFAULT, new NumberMapper<Integer>(Integer.class)); public static final Preference<Integer> maxCalculationTime = StringPreference.newInstance(MAX_CALCULATION_TIME_P_KEY, MAX_CALCULATION_TIME_DEFAULT, new NumberMapper<Integer>(Integer.class));
private static final List<String> preferenceKeys = new ArrayList<String>(); private static final List<String> preferenceKeys = new ArrayList<String>();
static { static {
preferenceKeys.add(groupingSeparator.getKey()); preferenceKeys.add(groupingSeparator.getKey());
preferenceKeys.add(multiplicationSign.getKey()); preferenceKeys.add(multiplicationSign.getKey());
preferenceKeys.add(precision.getKey()); preferenceKeys.add(precision.getKey());
preferenceKeys.add(roundResult.getKey()); preferenceKeys.add(roundResult.getKey());
preferenceKeys.add(numeralBase.getKey()); preferenceKeys.add(numeralBase.getKey());
preferenceKeys.add(angleUnit.getKey()); preferenceKeys.add(angleUnit.getKey());
preferenceKeys.add(scienceNotation.getKey()); preferenceKeys.add(scienceNotation.getKey());
preferenceKeys.add(maxCalculationTime.getKey()); preferenceKeys.add(maxCalculationTime.getKey());
} }
@NotNull @NotNull
public static List<String> getPreferenceKeys() { public static List<String> getPreferenceKeys() {
return Collections.unmodifiableList(preferenceKeys); return Collections.unmodifiableList(preferenceKeys);
} }
} }
@NotNull
private final Object lock = new Object();
@NotNull
private MathEngine engine = JsclMathEngine.instance;
@NotNull
public final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
@NotNull
private final CalculatorMathRegistry<IConstant> varsRegistry;
@NotNull
private final CalculatorMathRegistry<Function> functionsRegistry;
@NotNull
private final CalculatorMathRegistry<Operator> operatorsRegistry;
private final CalculatorMathRegistry<Operator> postfixFunctionsRegistry;
@Nullable
private ThreadKiller threadKiller = new AndroidThreadKiller();
// calculation thread timeout in seconds, after timeout thread would be interrupted
private int timeout = Integer.valueOf(MAX_CALCULATION_TIME_DEFAULT);
@NotNull
private String multiplicationSign = MULTIPLICATION_SIGN_DEFAULT;
@NotNull @NotNull
private final Context context; private final Context context;
public AndroidCalculatorEngine(@NotNull Application application) { @NotNull
private final CalculatorEngine calculatorEngine;
@NotNull
private final Object lock;
public AndroidCalculatorEngine(@NotNull Application application) {
this.context = application; this.context = application;
this.lock = new Object();
this.engine.setRoundResult(true); final JsclMathEngine engine = JsclMathEngine.instance;
this.engine.setUseGroupingSeparator(true); this.calculatorEngine = new CalculatorEngineImpl(engine,
new AndroidVarsRegistryImpl(engine.getConstantsRegistry(), application),
this.varsRegistry = new AndroidVarsRegistryImpl(engine.getConstantsRegistry(), application); new AndroidFunctionsMathRegistry(engine.getFunctionsRegistry(), application),
this.functionsRegistry = new AndroidFunctionsMathRegistry(engine.getFunctionsRegistry(), application); new AndroidOperatorsMathRegistry(engine.getOperatorsRegistry(), application),
this.operatorsRegistry = new AndroidOperatorsMathRegistry(engine.getOperatorsRegistry(), application); new AndroidPostfixFunctionsRegistry(engine.getPostfixFunctionsRegistry(), application),
this.postfixFunctionsRegistry = new AndroidPostfixFunctionsRegistry(engine.getPostfixFunctionsRegistry(), application); this.lock);
} }
@Override @Override
@NotNull @NotNull
public String getMultiplicationSign() { public CalculatorMathRegistry<IConstant> getVarsRegistry() {
return multiplicationSign; return calculatorEngine.getVarsRegistry();
} }
public void setMultiplicationSign(@NotNull String multiplicationSign) { @Override
this.multiplicationSign = multiplicationSign; @NotNull
} public CalculatorMathRegistry<Function> getFunctionsRegistry() {
return calculatorEngine.getFunctionsRegistry();
}
public CalculatorOutput evaluate(@NotNull JsclOperation operation, @Override
@NotNull String expression) throws CalculatorParseException, CalculatorEvalException { @NotNull
return evaluate(operation, expression, null); public CalculatorMathRegistry<Operator> getOperatorsRegistry() {
} return calculatorEngine.getOperatorsRegistry();
}
public CalculatorOutput evaluate(@NotNull final JsclOperation operation, @Override
@NotNull String expression, @NotNull
@Nullable MessageRegistry mr) throws CalculatorParseException, CalculatorEvalException { public CalculatorMathRegistry<Operator> getPostfixFunctionsRegistry() {
synchronized (lock) { return calculatorEngine.getPostfixFunctionsRegistry();
final StringBuilder sb = new StringBuilder(); }
final PreparedExpression preparedExpression = preprocessor.process(expression); @Override
sb.append(preparedExpression); @NotNull
public CalculatorMathEngine getMathEngine() {
return calculatorEngine.getMathEngine();
}
//Log.d(CalculatorEngine.class.getName(), "Preprocessed expression: " + preparedExpression); @NotNull
/*if (operation == JsclOperation.numeric && preparedExpression.isExistsUndefinedVar()) { @Override
operation = JsclOperation.simplify; public MathEngine getMathEngine0() {
return calculatorEngine.getMathEngine0();
}
if (mr != null) { @NotNull
final String undefinedVars = CollectionsUtils.formatValue(preparedExpression.getUndefinedVars(), ", ", new Formatter<Var>() { @Override
@Override public NumeralBase getNumeralBase() {
public String formatValue(@Nullable Var var) throws IllegalArgumentException { return calculatorEngine.getNumeralBase();
return var != null ? var.getName() : ""; }
}
});
mr.addMessage(new AndroidMessage(R.string.c_simplify_instead_of_numeric, MessageType.info, undefinedVars)); @Override
}
}*/
final String jsclExpression = sb.toString();
final MutableObject<Generic> calculationResult = new MutableObject<Generic>(null);
final MutableObject<CalculatorParseException> parseException = new MutableObject<CalculatorParseException>(null);
final MutableObject<CalculatorEvalException> evalException = new MutableObject<CalculatorEvalException>(null);
final MutableObject<Thread> calculationThread = new MutableObject<Thread>(null);
final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable() {
@Override
public void run() {
final Thread thread = Thread.currentThread();
try {
//Log.d(CalculatorEngine.class.getName(), "Calculation thread started work: " + thread.getName());
//System.out.println(jsclExpression);
calculationThread.setObject(thread);
final Generic genericResult = operation.evaluateGeneric(jsclExpression);
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!)
genericResult.toString();
calculationResult.setObject(genericResult);
} catch (AbstractJsclArithmeticException e) {
evalException.setObject(new CalculatorEvalException(e, e, jsclExpression));
} catch (ArithmeticException e) {
//System.out.println(e.getMessage());
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_1, MessageType.error, CalculatorApplication.getInstance(), e.getMessage());
parseException.setObject(new CalculatorParseException(jsclExpression, androidMessage));
} catch (StackOverflowError e) {
//System.out.println(StringUtils.fromStackTrace(e.getStackTrace()));
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_2, MessageType.error, CalculatorApplication.getInstance());
parseException.setObject(new CalculatorParseException(jsclExpression, androidMessage));
} catch (jscl.text.ParseException e) {
//System.out.println(e.getMessage());
parseException.setObject(new CalculatorParseException(e));
} catch (ParseInterruptedException e) {
//System.out.println(e.getMessage());
// do nothing - we ourselves interrupt the calculations
} finally {
//Log.d(CalculatorEngine.class.getName(), "Calculation thread ended work: " + thread.getName());
calculationThread.setObject(null);
latch.countDown();
}
}
}).start();
try {
//Log.d(CalculatorEngine.class.getName(), "Main thread is waiting: " + Thread.currentThread().getName());
latch.await(timeout, TimeUnit.SECONDS);
//Log.d(CalculatorEngine.class.getName(), "Main thread got up: " + Thread.currentThread().getName());
final CalculatorParseException parseExceptionObject = parseException.getObject();
final CalculatorEvalException evalExceptionObject = evalException.getObject();
final Object calculationResultLocal = calculationResult.getObject();
final Thread calculationThreadLocal = calculationThread.getObject();
if (calculationThreadLocal != null) {
if (threadKiller != null) {
threadKiller.killThread(calculationThreadLocal);
}
//calculationThreadLocal.stop();
}
if (parseExceptionObject != null || evalExceptionObject != null) {
if (operation == JsclOperation.numeric &&
(preparedExpression.isExistsUndefinedVar() || (evalExceptionObject != null && evalExceptionObject.getCause() instanceof NumeralBaseException))) {
return evaluate(JsclOperation.simplify, expression, mr);
}
if (parseExceptionObject != null) {
throw parseExceptionObject;
} else {
throw evalExceptionObject;
}
}
if (calculationResultLocal == null) {
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_3, MessageType.error, CalculatorApplication.getInstance());
throw new CalculatorParseException(jsclExpression, androidMessage);
}
} catch (InterruptedException e) {
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_4, MessageType.error, CalculatorApplication.getInstance());
throw new CalculatorParseException(jsclExpression, androidMessage);
}
final Generic genericResult = calculationResult.getObject();
return new CalculatorOutputImpl(operation.getFromProcessor().process(genericResult), operation, genericResult);
}
}
public void setPrecision(int precision) {
this.getEngine().setPrecision(precision);
}
public void setRoundResult(boolean roundResult) {
this.getEngine().setRoundResult(roundResult);
}
@Override
public void init() { public void init() {
synchronized (lock) { synchronized (lock) {
reset(); calculatorEngine.init();
} }
} }
@Override @Override
public void reset() { public void reset() {
synchronized (lock) { synchronized (lock) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
softReset(preferences); softReset(preferences);
varsRegistry.load(); calculatorEngine.reset();
functionsRegistry.load(); }
operatorsRegistry.load(); }
postfixFunctionsRegistry.load();
}
}
@Override @Override
public void softReset() { public void softReset() {
synchronized (lock) { synchronized (lock) {
softReset(PreferenceManager.getDefaultSharedPreferences(context)); softReset(PreferenceManager.getDefaultSharedPreferences(context));
}
} calculatorEngine.softReset();
}
}
@Override
public void setUseGroupingSeparator(boolean useGroupingSeparator) {
calculatorEngine.setUseGroupingSeparator(useGroupingSeparator);
}
@Override
public void setGroupingSeparator(char groupingSeparator) {
calculatorEngine.setGroupingSeparator(groupingSeparator);
}
@Override
public void setPrecision(@NotNull Integer precision) {
calculatorEngine.setPrecision(precision);
}
@Override
public void setRoundResult(@NotNull Boolean round) {
calculatorEngine.setRoundResult(round);
}
@NotNull
@Override
public AngleUnit getAngleUnits() {
return calculatorEngine.getAngleUnits();
}
@Override
public void setAngleUnits(@NotNull AngleUnit angleUnits) {
calculatorEngine.setAngleUnits(angleUnits);
}
@Override
public void setNumeralBase(@NotNull NumeralBase numeralBase) {
calculatorEngine.setNumeralBase(numeralBase);
}
@Override
public void setMultiplicationSign(@NotNull String multiplicationSign) {
calculatorEngine.setMultiplicationSign(multiplicationSign);
}
@Override
public void setScienceNotation(@NotNull Boolean scienceNotation) {
calculatorEngine.setScienceNotation(scienceNotation);
}
@Override
public void setTimeout(@NotNull Integer timeout) {
calculatorEngine.setTimeout(timeout);
}
private void softReset(@NotNull SharedPreferences preferences) { private void softReset(@NotNull SharedPreferences preferences) {
this.setPrecision(Preferences.precision.getPreference(preferences)); this.setPrecision(Preferences.precision.getPreference(preferences));
@ -322,100 +246,32 @@ public class AndroidCalculatorEngine implements CalculatorEngine {
final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences); final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences);
if (StringUtils.isEmpty(groupingSeparator)) { if (StringUtils.isEmpty(groupingSeparator)) {
this.getEngine().setUseGroupingSeparator(false); this.setUseGroupingSeparator(false);
} else { } else {
this.getEngine().setUseGroupingSeparator(true); this.setUseGroupingSeparator(true);
this.getEngine().setGroupingSeparator(groupingSeparator.charAt(0)); setGroupingSeparator(groupingSeparator.charAt(0));
} }
} }
@NotNull
public NumeralBase getNumeralBaseFromPrefs(@NotNull SharedPreferences preferences) {
return Preferences.numeralBase.getPreference(preferences);
}
@NotNull @NotNull
public NumeralBase getNumeralBaseFromPrefs(@NotNull SharedPreferences preferences) { public AngleUnit getAngleUnitsFromPrefs(@NotNull SharedPreferences preferences) {
return Preferences.numeralBase.getPreference(preferences); return Preferences.angleUnit.getPreference(preferences);
} }
@NotNull //for tests only
public AngleUnit getAngleUnitsFromPrefs(@NotNull SharedPreferences preferences) { public void setDecimalGroupSymbols(@NotNull DecimalFormatSymbols decimalGroupSymbols) {
return Preferences.angleUnit.getPreference(preferences); this.calculatorEngine.setDecimalGroupSymbols(decimalGroupSymbols);
} }
//for tests only @Override
void setDecimalGroupSymbols(@NotNull DecimalFormatSymbols decimalGroupSymbols) {
synchronized (lock) {
this.getEngine().setDecimalGroupSymbols(decimalGroupSymbols);
}
}
@Override
@NotNull @NotNull
public CalculatorMathRegistry<IConstant> getVarsRegistry() { public String getMultiplicationSign() {
return varsRegistry; return calculatorEngine.getMultiplicationSign();
} }
@Override
@NotNull
public CalculatorMathRegistry<Function> getFunctionsRegistry() {
return functionsRegistry;
}
@Override
@NotNull
public CalculatorMathRegistry<Operator> getOperatorsRegistry() {
return operatorsRegistry;
}
@Override
@NotNull
public CalculatorMathRegistry<Operator> getPostfixFunctionsRegistry() {
return postfixFunctionsRegistry;
}
@Override
@NotNull
public MathEngine getEngine() {
return engine;
}
// package protected for tests
void setTimeout(int timeout) {
this.timeout = timeout;
}
public void setAngleUnits(@NotNull AngleUnit angleUnits) {
getEngine().setAngleUnits(angleUnits);
}
public void setScienceNotation(boolean scienceNotation) {
getEngine().setScienceNotation(scienceNotation);
}
public void setNumeralBase(@NotNull NumeralBase numeralBase) {
getEngine().setNumeralBase(numeralBase);
}
// for tests only
void setThreadKiller(@Nullable ThreadKiller threadKiller) {
this.threadKiller = threadKiller;
}
private static interface ThreadKiller {
void killThread(@NotNull Thread thread);
}
private static class AndroidThreadKiller implements ThreadKiller {
@Override
public void killThread(@NotNull Thread thread) {
thread.setPriority(Thread.MIN_PRIORITY);
thread.interrupt();
}
}
public static class ThreadKillerImpl implements ThreadKiller {
@Override
public void killThread(@NotNull Thread thread) {
thread.setPriority(Thread.MIN_PRIORITY);
thread.stop();
}
}
} }

View File

@ -34,7 +34,7 @@ public class AngleUnitsButton extends DirectionDragButton {
super.initDirectionTextPaint(basePaint, directionTextData, resources); super.initDirectionTextPaint(basePaint, directionTextData, resources);
final TextPaint directionTextPaint = directionTextData.getPaint(); final TextPaint directionTextPaint = directionTextData.getPaint();
if (CalculatorLocatorImpl.getInstance().getEngine().getEngine().getAngleUnits().name().equals(directionTextData.getText())) { if (CalculatorLocatorImpl.getInstance().getEngine().getAngleUnits().name().equals(directionTextData.getText())) {
directionTextPaint.setColor(resources.getColor(R.color.selected_angle_unit_text_color)); directionTextPaint.setColor(resources.getColor(R.color.selected_angle_unit_text_color));
} else { } else {
directionTextPaint.setColor(resources.getColor(R.color.default_text_color)); directionTextPaint.setColor(resources.getColor(R.color.default_text_color));

View File

@ -37,12 +37,12 @@ public class NumeralBaseConverterDialog {
String value = initialFromValue; String value = initialFromValue;
try { try {
value = ToJsclTextProcessor.getInstance().process(value).getExpression(); value = ToJsclTextProcessor.getInstance().process(value).getExpression();
b.setFromValue(UnitImpl.newInstance(value, AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getEngine().getNumeralBase()))); b.setFromValue(UnitImpl.newInstance(value, AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase())));
} catch (CalculatorParseException e) { } catch (CalculatorParseException e) {
b.setFromValue(UnitImpl.newInstance(value, AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getEngine().getNumeralBase()))); b.setFromValue(UnitImpl.newInstance(value, AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase())));
} }
} else { } else {
b.setFromValue(UnitImpl.newInstance("", AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getEngine().getNumeralBase()))); b.setFromValue(UnitImpl.newInstance("", AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase())));
} }
b.setConverter(AndroidNumeralBase.getConverter()); b.setConverter(AndroidNumeralBase.getConverter());
@ -63,7 +63,7 @@ public class NumeralBaseConverterDialog {
public void onClick(@NotNull Unit<String> fromUnits, @NotNull Unit<String> toUnits) { public void onClick(@NotNull Unit<String> fromUnits, @NotNull Unit<String> toUnits) {
String toUnitsValue = toUnits.getValue(); String toUnitsValue = toUnits.getValue();
if (!toUnits.getUnitType().equals(AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getEngine().getNumeralBase()))) { if (!toUnits.getUnitType().equals(AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase()))) {
toUnitsValue = ((AndroidNumeralBase) toUnits.getUnitType()).getNumeralBase().getJsclPrefix() + toUnitsValue; toUnitsValue = ((AndroidNumeralBase) toUnits.getUnitType()).getNumeralBase().getJsclPrefix() + toUnitsValue;
} }

View File

@ -34,7 +34,7 @@ public class NumeralBasesButton extends DirectionDragButton {
super.initDirectionTextPaint(basePaint, directionTextData, resources); super.initDirectionTextPaint(basePaint, directionTextData, resources);
final TextPaint directionTextPaint = directionTextData.getPaint(); final TextPaint directionTextPaint = directionTextData.getPaint();
if (CalculatorLocatorImpl.getInstance().getEngine().getEngine().getNumeralBase().name().equals(directionTextData.getText())) { if (CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase().name().equals(directionTextData.getText())) {
directionTextPaint.setColor(resources.getColor(R.color.selected_angle_unit_text_color)); directionTextPaint.setColor(resources.getColor(R.color.selected_angle_unit_text_color));
} else { } else {
directionTextPaint.setColor(resources.getColor(R.color.default_text_color)); directionTextPaint.setColor(resources.getColor(R.color.default_text_color));

View File

@ -6,7 +6,6 @@
package org.solovyev.android.calculator.view; package org.solovyev.android.calculator.view;
import jscl.MathContext;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.*;
@ -30,9 +29,6 @@ public class TextHighlighter implements TextProcessor<TextHighlighter.Result, St
nbFontAttributes.put("color", "#008000"); nbFontAttributes.put("color", "#008000");
} }
@NotNull
public final MathContext mathContext;
public static class Result implements CharSequence { public static class Result implements CharSequence {
@NotNull @NotNull
@ -76,10 +72,9 @@ public class TextHighlighter implements TextProcessor<TextHighlighter.Result, St
private final int colorBlue; private final int colorBlue;
private final boolean formatNumber; private final boolean formatNumber;
public TextHighlighter(int baseColor, boolean formatNumber, @NotNull MathContext mathContext) { public TextHighlighter(int baseColor, boolean formatNumber) {
this.color = baseColor; this.color = baseColor;
this.formatNumber = formatNumber; this.formatNumber = formatNumber;
this.mathContext = mathContext;
//this.colorRed = Color.red(baseColor); //this.colorRed = Color.red(baseColor);
this.colorRed = (baseColor >> 16) & 0xFF; this.colorRed = (baseColor >> 16) & 0xFF;
//this.colorGreen = Color.green(baseColor); //this.colorGreen = Color.green(baseColor);
@ -102,9 +97,9 @@ public class TextHighlighter implements TextProcessor<TextHighlighter.Result, St
final AbstractNumberBuilder numberBuilder; final AbstractNumberBuilder numberBuilder;
if (!formatNumber) { if (!formatNumber) {
numberBuilder = new LiteNumberBuilder(CalculatorLocatorImpl.getInstance().getEngine().getEngine()); numberBuilder = new LiteNumberBuilder(CalculatorLocatorImpl.getInstance().getEngine());
} else { } else {
numberBuilder = new NumberBuilder(CalculatorLocatorImpl.getInstance().getEngine().getEngine()); numberBuilder = new NumberBuilder(CalculatorLocatorImpl.getInstance().getEngine());
} }
for (int i = 0; i < text.length(); i++) { for (int i = 0; i < text.length(); i++) {
MathType.Result mathType = MathType.getType(text, i, numberBuilder.isHexMode()); MathType.Result mathType = MathType.getType(text, i, numberBuilder.isHexMode());

View File

@ -6,7 +6,6 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import jscl.JsclMathEngine;
import jscl.MathEngine; import jscl.MathEngine;
import jscl.NumeralBase; import jscl.NumeralBase;
import junit.framework.Assert; import junit.framework.Assert;
@ -26,7 +25,7 @@ public class TextHighlighterTest {
@Test @Test
public void testProcess() throws Exception { public void testProcess() throws Exception {
TextProcessor<?, String> textHighlighter = new TextHighlighter(0, false, JsclMathEngine.instance); TextProcessor<?, String> textHighlighter = new TextHighlighter(0, false);
final Random random = new Random(new Date().getTime()); final Random random = new Random(new Date().getTime());
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
@ -46,7 +45,7 @@ public class TextHighlighterTest {
Assert.assertEquals(")", textHighlighter.process(")").toString()); Assert.assertEquals(")", textHighlighter.process(")").toString());
Assert.assertEquals(")()(", textHighlighter.process(")()(").toString()); Assert.assertEquals(")()(", textHighlighter.process(")()(").toString());
textHighlighter = new TextHighlighter(0, true, JsclMathEngine.instance); textHighlighter = new TextHighlighter(0, true);
Assert.assertEquals("1 000 000", textHighlighter.process("1000000").toString()); Assert.assertEquals("1 000 000", textHighlighter.process("1000000").toString());
Assert.assertEquals("1 000 000", textHighlighter.process("1000000").toString()); Assert.assertEquals("1 000 000", textHighlighter.process("1000000").toString());
Assert.assertEquals("0.1E3", textHighlighter.process("0.1E3").toString()); Assert.assertEquals("0.1E3", textHighlighter.process("0.1E3").toString());
@ -65,7 +64,7 @@ public class TextHighlighterTest {
Assert.assertEquals("-1 000 000E3", textHighlighter.process("-1000000E3").toString()); Assert.assertEquals("-1 000 000E3", textHighlighter.process("-1000000E3").toString());
Assert.assertEquals("-1 000 000E-3", textHighlighter.process("-1000000E-3").toString()); Assert.assertEquals("-1 000 000E-3", textHighlighter.process("-1000000E-3").toString());
Assert.assertEquals("-1 000 000E-30000", textHighlighter.process("-1000000E-30000").toString()); Assert.assertEquals("-1 000 000E-30000", textHighlighter.process("-1000000E-30000").toString());
textHighlighter = new TextHighlighter(0, false, JsclMathEngine.instance); textHighlighter = new TextHighlighter(0, false);
textHighlighter.process("cannot calculate 3^10^10 !!!\n" + textHighlighter.process("cannot calculate 3^10^10 !!!\n" +
" unable to enter 0. FIXED\n" + " unable to enter 0. FIXED\n" +
@ -92,7 +91,7 @@ public class TextHighlighterTest {
Assert.assertEquals("<b>0x:</b>FF33233FFE", textHighlighter.process("0x:FF33233FFE").toString()); Assert.assertEquals("<b>0x:</b>FF33233FFE", textHighlighter.process("0x:FF33233FFE").toString());
Assert.assertEquals("<b>0x:</b>FF33 233 FFE", textHighlighter.process("0x:FF33 233 FFE").toString()); Assert.assertEquals("<b>0x:</b>FF33 233 FFE", textHighlighter.process("0x:FF33 233 FFE").toString());
final MathEngine me = CalculatorLocatorImpl.getInstance().getEngine().getEngine(); final MathEngine me = CalculatorLocatorImpl.getInstance().getEngine().getMathEngine0();
try { try {
me.setNumeralBase(NumeralBase.hex); me.setNumeralBase(NumeralBase.hex);
Assert.assertEquals("E", textHighlighter.process("E").toString()); Assert.assertEquals("E", textHighlighter.process("E").toString());

View File

@ -5,25 +5,8 @@
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import jscl.AngleUnit;
import jscl.JsclMathEngine;
import jscl.NumeralBase;
import jscl.math.Expression;
import jscl.math.Generic;
import jscl.math.function.Constant;
import jscl.math.function.CustomFunction;
import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test;
import org.solovyev.android.calculator.CalculatorEvalException;
import org.solovyev.android.calculator.CalculatorLocatorImpl; import org.solovyev.android.calculator.CalculatorLocatorImpl;
import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.jscl.JsclOperation;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import static junit.framework.Assert.fail;
/** /**
* User: serso * User: serso
@ -37,9 +20,8 @@ public class AndroidCalculatorEngineTest {
public static void setUp() throws Exception { public static void setUp() throws Exception {
CalculatorLocatorImpl.getInstance().getEngine().init(); CalculatorLocatorImpl.getInstance().getEngine().init();
((AndroidCalculatorEngine) CalculatorLocatorImpl.getInstance().getEngine()).setPrecision(3); ((AndroidCalculatorEngine) CalculatorLocatorImpl.getInstance().getEngine()).setPrecision(3);
((AndroidCalculatorEngine) CalculatorLocatorImpl.getInstance().getEngine()).setThreadKiller(new AndroidCalculatorEngine.ThreadKillerImpl());
} }
/*
@Test @Test
public void testDegrees() throws Exception { public void testDegrees() throws Exception {
final AndroidCalculatorEngine cm = (AndroidCalculatorEngine) CalculatorLocatorImpl.getInstance().getEngine(); final AndroidCalculatorEngine cm = (AndroidCalculatorEngine) CalculatorLocatorImpl.getInstance().getEngine();
@ -95,7 +77,7 @@ public class AndroidCalculatorEngineTest {
} }
} }
/*final long start = System.currentTimeMillis(); *//*final long start = System.currentTimeMillis();
try { try {
cm.evaluate(JsclOperation.numeric, "3^10^10^10"); cm.evaluate(JsclOperation.numeric, "3^10^10^10");
Assert.fail(); Assert.fail();
@ -106,7 +88,7 @@ public class AndroidCalculatorEngineTest {
} else { } else {
Assert.fail(); Assert.fail();
} }
}*/ }*//*
} }
@ -157,7 +139,7 @@ public class AndroidCalculatorEngineTest {
Assert.assertEquals("-2+2.5i", cm.evaluate(JsclOperation.numeric, "-2+2.5i").getStringResult()); Assert.assertEquals("-2+2.5i", cm.evaluate(JsclOperation.numeric, "-2+2.5i").getStringResult());
Assert.assertEquals("-2+2.1i", cm.evaluate(JsclOperation.numeric, "-2+2.1i").getStringResult()); Assert.assertEquals("-2+2.1i", cm.evaluate(JsclOperation.numeric, "-2+2.1i").getStringResult());
Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)").getStringResult()); Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)").getStringResult());
junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "4!").getStringResult()); junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "4!").getStringResult());
junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "(2+2)!").getStringResult()); junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "(2+2)!").getStringResult());
junit.framework.Assert.assertEquals("120", cm.evaluate(JsclOperation.numeric, "(2+2+1)!").getStringResult()); junit.framework.Assert.assertEquals("120", cm.evaluate(JsclOperation.numeric, "(2+2+1)!").getStringResult());
@ -230,7 +212,7 @@ public class AndroidCalculatorEngineTest {
Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))").getStringResult()); Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))").getStringResult());
/* Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "30°").getResult()); *//* Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "30°").getResult());
Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "(10+20)°").getResult()); Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "(10+20)°").getResult());
Assert.assertEquals("1.047", cm.evaluate(JsclOperation.numeric, "(10+20)°*2").getResult()); Assert.assertEquals("1.047", cm.evaluate(JsclOperation.numeric, "(10+20)°*2").getResult());
try { try {
@ -240,14 +222,14 @@ public class AndroidCalculatorEngineTest {
if ( !e.getMessage().equals("Power operation after postfix function is currently unsupported!") ) { if ( !e.getMessage().equals("Power operation after postfix function is currently unsupported!") ) {
junit.framework.Assert.fail(); junit.framework.Assert.fail();
} }
}*/ }*//*
/* try { *//* try {
cm.setTimeout(5000); cm.setTimeout(5000);
Assert.assertEquals("2", cm.evaluate(JsclOperation.numeric, "2!").getResult()); Assert.assertEquals("2", cm.evaluate(JsclOperation.numeric, "2!").getResult());
} finally { } finally {
cm.setTimeout(3000); cm.setTimeout(3000);
}*/ }*//*
CalculatorLocatorImpl.getInstance().getEngine().getVarsRegistry().add(new Var.Builder("t", (String) null)); CalculatorLocatorImpl.getInstance().getEngine().getVarsRegistry().add(new Var.Builder("t", (String) null));
Assert.assertEquals("2t", cm.evaluate(JsclOperation.simplify, "∂(t^2,t)").getStringResult()); Assert.assertEquals("2t", cm.evaluate(JsclOperation.simplify, "∂(t^2,t)").getStringResult());
@ -442,5 +424,5 @@ public class AndroidCalculatorEngineTest {
Assert.assertEquals("1/(bln(a))", cm.evaluate(JsclOperation.simplify, "∂(log(a, b), b)").getStringResult()); Assert.assertEquals("1/(bln(a))", cm.evaluate(JsclOperation.simplify, "∂(log(a, b), b)").getStringResult());
Assert.assertEquals("-ln(b)/(aln(a)^2)", cm.evaluate(JsclOperation.simplify, "∂(log(a, b), a)").getStringResult()); Assert.assertEquals("-ln(b)/(aln(a)^2)", cm.evaluate(JsclOperation.simplify, "∂(log(a, b), a)").getStringResult());
} }*/
} }

View File

@ -30,7 +30,6 @@ public class NumeralBaseTest {
public static void setUp() throws Exception { public static void setUp() throws Exception {
CalculatorLocatorImpl.getInstance().getEngine().init(); CalculatorLocatorImpl.getInstance().getEngine().init();
((AndroidCalculatorEngine) CalculatorLocatorImpl.getInstance().getEngine()).setPrecision(3); ((AndroidCalculatorEngine) CalculatorLocatorImpl.getInstance().getEngine()).setPrecision(3);
((AndroidCalculatorEngine) CalculatorLocatorImpl.getInstance().getEngine()).setThreadKiller(new AndroidCalculatorEngine.ThreadKillerImpl());
} }
@Test @Test
@ -100,11 +99,11 @@ public class NumeralBaseTest {
final String bin = "0b:" + line[2].toUpperCase(); final String bin = "0b:" + line[2].toUpperCase();
final String decExpression = converter.convert(dec); final String decExpression = converter.convert(dec);
final String decResult = CalculatorLocatorImpl.getInstance().getEngine().getEngine().evaluate(decExpression); final String decResult = CalculatorLocatorImpl.getInstance().getEngine().getMathEngine().evaluate(decExpression);
final String hexExpression = converter.convert(hex); final String hexExpression = converter.convert(hex);
final String hexResult = CalculatorLocatorImpl.getInstance().getEngine().getEngine().evaluate(hexExpression); final String hexResult = CalculatorLocatorImpl.getInstance().getEngine().getMathEngine().evaluate(hexExpression);
final String binExpression = converter.convert(bin); final String binExpression = converter.convert(bin);
final String binResult = CalculatorLocatorImpl.getInstance().getEngine().getEngine().evaluate(binExpression); final String binResult = CalculatorLocatorImpl.getInstance().getEngine().getMathEngine().evaluate(binExpression);
Assert.assertEquals("dec-hex: " + decExpression + " : " + hexExpression, decResult, hexResult); Assert.assertEquals("dec-hex: " + decExpression + " : " + hexExpression, decResult, hexResult);
Assert.assertEquals("dec-bin: " + decExpression + " : " + binExpression, decResult, binResult); Assert.assertEquals("dec-bin: " + decExpression + " : " + binExpression, decResult, binResult);

View File

@ -68,10 +68,10 @@ public class ToJsclTextProcessorTest {
Assert.assertEquals( "EE", preprocessor.process("EE").toString()); Assert.assertEquals( "EE", preprocessor.process("EE").toString());
try { try {
CalculatorLocatorImpl.getInstance().getEngine().getEngine().setNumeralBase(NumeralBase.hex); CalculatorLocatorImpl.getInstance().getEngine().setNumeralBase(NumeralBase.hex);
Assert.assertEquals( "22F*exp(F)", preprocessor.process("22Fexp(F)").toString()); Assert.assertEquals( "22F*exp(F)", preprocessor.process("22Fexp(F)").toString());
} finally { } finally {
CalculatorLocatorImpl.getInstance().getEngine().getEngine().setNumeralBase(NumeralBase.dec); CalculatorLocatorImpl.getInstance().getEngine().setNumeralBase(NumeralBase.dec);
} }
Assert.assertEquals( "0x:ABCDEF", preprocessor.process("0x:ABCDEF").toString()); Assert.assertEquals( "0x:ABCDEF", preprocessor.process("0x:ABCDEF").toString());
Assert.assertEquals( "0x:ABCDEF", preprocessor.process("0x:A BC DEF").toString()); Assert.assertEquals( "0x:ABCDEF", preprocessor.process("0x:A BC DEF").toString());