This commit is contained in:
serso 2016-02-01 23:15:10 +01:00
parent 8c56dd1083
commit 89680ef544
17 changed files with 158 additions and 164 deletions

View File

@ -28,17 +28,14 @@ import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import jscl.JsclArithmeticException; import jscl.*;
import jscl.MathEngine;
import jscl.NumeralBase;
import jscl.NumeralBaseException;
import jscl.math.Generic; import jscl.math.Generic;
import jscl.math.function.Constants;
import jscl.math.function.IConstant; import jscl.math.function.IConstant;
import jscl.text.ParseInterruptedException; import jscl.text.ParseInterruptedException;
import org.solovyev.android.calculator.calculations.CalculationCancelledEvent; import org.solovyev.android.calculator.calculations.CalculationCancelledEvent;
import org.solovyev.android.calculator.calculations.CalculationFailedEvent; import org.solovyev.android.calculator.calculations.CalculationFailedEvent;
import org.solovyev.android.calculator.calculations.CalculationFinishedEvent; import org.solovyev.android.calculator.calculations.CalculationFinishedEvent;
import org.solovyev.android.calculator.errors.FixableErrorsActivity;
import org.solovyev.android.calculator.functions.FunctionsRegistry; import org.solovyev.android.calculator.functions.FunctionsRegistry;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.units.CalculatorNumeralBase; import org.solovyev.android.calculator.units.CalculatorNumeralBase;
@ -57,6 +54,7 @@ import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -65,12 +63,13 @@ import java.util.concurrent.atomic.AtomicLong;
@Singleton @Singleton
public class Calculator implements CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener { public class Calculator implements CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener {
public static final long NO_SEQUENCE = -1;
private static final long PREFERENCE_CHECK_INTERVAL = TimeUnit.MINUTES.toMillis(15); private static final long PREFERENCE_CHECK_INTERVAL = TimeUnit.MINUTES.toMillis(15);
@Nonnull @Nonnull
private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer(); private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer();
@Nonnull @Nonnull
private final AtomicLong counter = new AtomicLong(CalculatorUtils.FIRST_ID); private static final AtomicLong SEQUENCER = new AtomicLong(NO_SEQUENCE);
@Nonnull @Nonnull
private final ToJsclTextProcessor preprocessor = ToJsclTextProcessor.getInstance(); private final ToJsclTextProcessor preprocessor = ToJsclTextProcessor.getInstance();
@Nonnull @Nonnull
@ -90,6 +89,8 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
PreferredPreferences preferredPreferences; PreferredPreferences preferredPreferences;
@Inject @Inject
Editor editor; Editor editor;
@Inject
JsclMathEngine mathEngine;
@Inject @Inject
public Calculator(@Nonnull SharedPreferences preferences, @Nonnull Bus bus, @Named(AppModule.THREAD_UI) @Nonnull Executor ui, @Named(AppModule.THREAD_BACKGROUND) @Nonnull Executor background) { public Calculator(@Nonnull SharedPreferences preferences, @Nonnull Bus bus, @Named(AppModule.THREAD_UI) @Nonnull Executor ui, @Named(AppModule.THREAD_BACKGROUND) @Nonnull Executor background) {
@ -113,7 +114,7 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
String fromString = generic.toString(); String fromString = generic.toString();
if (!Strings.isEmpty(fromString)) { if (!Strings.isEmpty(fromString)) {
try { try {
fromString = ToJsclTextProcessor.getInstance().process(fromString).getExpression(); fromString = ToJsclTextProcessor.getInstance().process(fromString).getValue();
} catch (ParseException e) { } catch (ParseException e) {
// ok, problems while processing occurred // ok, problems while processing occurred
} }
@ -130,19 +131,19 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
@Nonnull @Nonnull
private CalculatorEventData nextEventData() { private CalculatorEventData nextEventData() {
long eventId = counter.incrementAndGet(); final long eventId = nextSequence();
return CalculatorEventDataImpl.newInstance(eventId, eventId); return CalculatorEventDataImpl.newInstance(eventId, eventId);
} }
@Nonnull @Nonnull
private CalculatorEventData nextEventData(@Nonnull Object source) { private CalculatorEventData nextEventData(@Nonnull Object source) {
long eventId = counter.incrementAndGet(); long eventId = nextSequence();
return CalculatorEventDataImpl.newInstance(eventId, eventId, source); return CalculatorEventDataImpl.newInstance(eventId, eventId, source);
} }
@Nonnull @Nonnull
private CalculatorEventData nextEventData(@Nonnull Long sequenceId) { private CalculatorEventData nextEventData(@Nonnull Long sequenceId) {
long eventId = counter.incrementAndGet(); long eventId = nextSequence();
return CalculatorEventDataImpl.newInstance(eventId, sequenceId); return CalculatorEventDataImpl.newInstance(eventId, sequenceId);
} }
@ -167,7 +168,7 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
background.execute(new Runnable() { background.execute(new Runnable() {
@Override @Override
public void run() { public void run() {
Calculator.this.evaluateAsync(eventDataId.getSequenceId(), operation, expression, null); evaluateAsync(eventDataId.getSequenceId(), operation, expression);
} }
}); });
@ -181,7 +182,7 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
background.execute(new Runnable() { background.execute(new Runnable() {
@Override @Override
public void run() { public void run() {
evaluateAsync(eventDataId.getSequenceId(), operation, expression, null); evaluateAsync(eventDataId.getSequenceId(), operation, expression);
} }
}); });
@ -215,72 +216,75 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
return CalculatorConversionEventDataImpl.newInstance(nextEventData(sequenceId), value, from, to, displayViewState); return CalculatorConversionEventDataImpl.newInstance(nextEventData(sequenceId), value, from, to, displayViewState);
} }
private void evaluateAsync(long sequence, @Nonnull JsclOperation o, @Nonnull String e) {
evaluateAsync(sequence, o, e, new ListMessageRegistry());
}
private void evaluateAsync(long sequence, private void evaluateAsync(long sequence,
@Nonnull JsclOperation operation, @Nonnull JsclOperation o,
@Nonnull String expression, @Nonnull String e,
@Nullable MessageRegistry mr) { @Nonnull MessageRegistry mr) {
e = e.trim();
if (Strings.isEmpty(e)) {
bus.post(new CalculationFinishedEvent(o, e, sequence));
return;
}
checkPreferredPreferences(); checkPreferredPreferences();
expression = expression.trim(); PreparedExpression pe = null;
PreparedExpression preparedExpression = null;
try { try {
if (Strings.isEmpty(expression)) { pe = prepare(e);
bus.post(new CalculationFinishedEvent(operation, expression, sequence));
return;
}
preparedExpression = prepareExpression(expression);
final String jsclExpression = preparedExpression.toString();
try { try {
final MathEngine mathEngine = Locator.getInstance().getEngine().getMathEngine(); Locator.getInstance().getEngine().getMathEngine().setMessageRegistry(mr);
final MessageRegistry messageRegistry = new ListMessageRegistry(); final Generic result = o.evaluateGeneric(pe.value, mathEngine);
Locator.getInstance().getEngine().getMathEngine().setMessageRegistry(messageRegistry);
final Generic result = operation.evaluateGeneric(jsclExpression, mathEngine);
// 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!)
//noinspection ResultOfMethodCallIgnored
result.toString(); result.toString();
if (messageRegistry.hasMessage()) { final String stringResult = o.getFromProcessor().process(result);
try { bus.post(new CalculationFinishedEvent(o, e, sequence, result, stringResult, collectMessages(mr)));
final List<Message> messages = new ArrayList<>();
while (messageRegistry.hasMessage()) {
messages.add(messageRegistry.getMessage());
}
if (!messages.isEmpty()) {
fireCalculatorEvent(newCalculationEventData(operation, expression, sequence), CalculatorEventType.calculation_messages, messages);
}
} catch (Throwable e) {
// todo serso: not good but we need proper synchronization
Log.e("Calculator", e.getMessage(), e);
}
}
final String stringResult = operation.getFromProcessor().process(result); } catch (JsclArithmeticException exception) {
bus.post(new CalculationFinishedEvent(operation, expression, sequence, result, stringResult)); if (o == JsclOperation.numeric && exception.getCause() instanceof NumeralBaseException) {
evaluateAsync(sequence, JsclOperation.simplify, e, mr);
} catch (JsclArithmeticException e) {
if (operation == JsclOperation.numeric && e.getCause() instanceof NumeralBaseException) {
evaluateAsync(sequence, JsclOperation.simplify, expression, mr);
} else { } else {
bus.post(new CalculationFailedEvent(operation, expression, sequence, e)); bus.post(new CalculationFailedEvent(o, e, sequence, exception));
} }
} }
} catch (ArithmeticException e) { } catch (ArithmeticException exception) {
handleException(sequence, operation, expression, mr, preparedExpression, new ParseException(expression, new CalculatorMessage(CalculatorMessages.msg_001, MessageType.error, e.getMessage()))); onException(sequence, o, e, mr, pe, new ParseException(e, new CalculatorMessage(CalculatorMessages.msg_001, MessageType.error, exception.getMessage())));
} catch (StackOverflowError e) { } catch (StackOverflowError exception) {
handleException(sequence, operation, expression, mr, preparedExpression, new ParseException(expression, new CalculatorMessage(CalculatorMessages.msg_002, MessageType.error))); onException(sequence, o, e, mr, pe, new ParseException(e, new CalculatorMessage(CalculatorMessages.msg_002, MessageType.error)));
} catch (jscl.text.ParseException e) { } catch (jscl.text.ParseException exception) {
handleException(sequence, operation, expression, mr, preparedExpression, new ParseException(e)); onException(sequence, o, e, mr, pe, new ParseException(exception));
} catch (ParseInterruptedException e) { } catch (ParseInterruptedException exception) {
bus.post(new CalculationCancelledEvent(operation, expression, sequence)); bus.post(new CalculationCancelledEvent(o, e, sequence));
} catch (ParseException e) { } catch (ParseException exception) {
handleException(sequence, operation, expression, mr, preparedExpression, e); onException(sequence, o, e, mr, pe, exception);
} }
} }
@Nonnull
private List<Message> collectMessages(@Nonnull MessageRegistry mr) {
if (mr.hasMessage()) {
try {
final List<Message> messages = new ArrayList<>();
while (mr.hasMessage()) {
messages.add(mr.getMessage());
}
return messages;
} catch (Throwable exception) {
// several threads might use the same instance of MessageRegistry, as no proper synchronization is done
// catch Throwable here
Log.e("Calculator", exception.getMessage(), exception);
}
}
return Collections.emptyList();
}
private void checkPreferredPreferences() { private void checkPreferredPreferences() {
if (shouldCheckPreferredPreferences()) { if (shouldCheckPreferredPreferences()) {
preferredPreferences.check(false); preferredPreferences.check(false);
@ -298,30 +302,23 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
} }
@Nonnull @Nonnull
public PreparedExpression prepareExpression(@Nonnull String expression) throws ParseException { public PreparedExpression prepare(@Nonnull String expression) throws ParseException {
return preprocessor.process(expression); return preprocessor.process(expression);
} }
@Nonnull private void onException(long sequence,
private CalculatorEventData newCalculationEventData(@Nonnull JsclOperation operation, @Nonnull JsclOperation operation,
@Nonnull String expression, @Nonnull String e,
@Nonnull Long calculationId) { @Nonnull MessageRegistry mr,
return new CalculatorEvaluationEventDataImpl(nextEventData(calculationId), operation, expression); @Nullable PreparedExpression pe,
} @Nonnull ParseException parseException) {
private void handleException(long sequence,
@Nonnull JsclOperation operation,
@Nonnull String expression,
@Nullable MessageRegistry mr,
@Nullable PreparedExpression preparedExpression,
@Nonnull ParseException parseException) {
if (operation == JsclOperation.numeric if (operation == JsclOperation.numeric
&& preparedExpression != null && pe != null
&& preparedExpression.isExistsUndefinedVar()) { && pe.hasUndefinedVariables()) {
evaluateAsync(sequence, JsclOperation.simplify, expression, mr); evaluateAsync(sequence, JsclOperation.simplify, e, mr);
} else { return;
bus.post(new CalculationFailedEvent(operation, expression, sequence, parseException));
} }
bus.post(new CalculationFailedEvent(operation, e, sequence, parseException));
} }
@Nonnull @Nonnull
@ -423,9 +420,9 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
private void updateAnsVariable(@NonNull String value) { private void updateAnsVariable(@NonNull String value) {
final VariablesRegistry variablesRegistry = Locator.getInstance().getEngine().getVariablesRegistry(); final VariablesRegistry variablesRegistry = Locator.getInstance().getEngine().getVariablesRegistry();
final IConstant variable = variablesRegistry.get(VariablesRegistry.ANS); final IConstant variable = variablesRegistry.get(Constants.ANS);
final CppVariable.Builder b = variable != null ? CppVariable.builder(variable) : CppVariable.builder(VariablesRegistry.ANS); final CppVariable.Builder b = variable != null ? CppVariable.builder(variable) : CppVariable.builder(Constants.ANS);
b.withValue(value); b.withValue(value);
b.withSystem(true); b.withSystem(true);
b.withDescription(CalculatorMessages.getBundle().getString(CalculatorMessages.ans_description)); b.withDescription(CalculatorMessages.getBundle().getString(CalculatorMessages.ans_description));
@ -460,7 +457,7 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
@Subscribe @Subscribe
public void onVariableChanged(@NonNull VariablesRegistry.ChangedEvent e) { public void onVariableChanged(@NonNull VariablesRegistry.ChangedEvent e) {
if (!e.newVariable.getName().equals(VariablesRegistry.ANS)) { if (!e.newVariable.getName().equals(Constants.ANS)) {
evaluate(); evaluate();
} }
} }
@ -468,9 +465,6 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) { switch (calculatorEventType) {
case calculation_messages:
FixableErrorsActivity.show(App.getApplication(), (List<Message>) data);
break;
case show_history: case show_history:
ActivityLauncher.showHistory(App.getApplication()); ActivityLauncher.showHistory(App.getApplication());
break; break;
@ -520,4 +514,7 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
} }
} }
public static long nextSequence() {
return SEQUENCER.incrementAndGet();
}
} }

View File

@ -22,15 +22,14 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nonnull;
import jscl.math.Generic; import jscl.math.Generic;
import jscl.math.function.Constant; import jscl.math.function.Constant;
import jscl.math.function.IConstant; import jscl.math.function.IConstant;
import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Set;
/** /**
* User: serso * User: serso
* Date: 9/22/12 * Date: 9/22/12
@ -38,15 +37,13 @@ import jscl.math.function.IConstant;
*/ */
public final class CalculatorUtils { public final class CalculatorUtils {
static final long FIRST_ID = 0;
private CalculatorUtils() { private CalculatorUtils() {
throw new AssertionError(); throw new AssertionError();
} }
@Nonnull @Nonnull
public static CalculatorEventData createFirstEventDataId() { public static CalculatorEventData createFirstEventDataId() {
return CalculatorEventDataImpl.newInstance(FIRST_ID, FIRST_ID); return CalculatorEventDataImpl.newInstance(Calculator.NO_SEQUENCE, Calculator.NO_SEQUENCE);
} }
@Nonnull @Nonnull

View File

@ -22,6 +22,8 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.app.Application;
import android.content.Context;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@ -33,6 +35,7 @@ import org.solovyev.android.Check;
import org.solovyev.android.calculator.calculations.CalculationCancelledEvent; import org.solovyev.android.calculator.calculations.CalculationCancelledEvent;
import org.solovyev.android.calculator.calculations.CalculationFailedEvent; import org.solovyev.android.calculator.calculations.CalculationFailedEvent;
import org.solovyev.android.calculator.calculations.CalculationFinishedEvent; import org.solovyev.android.calculator.calculations.CalculationFinishedEvent;
import org.solovyev.android.calculator.errors.FixableErrorsActivity;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.view.NumeralBaseConverterDialog; import org.solovyev.android.calculator.view.NumeralBaseConverterDialog;
@ -53,6 +56,8 @@ public class Display implements CalculatorEventListener, View.OnClickListener, V
@Nonnull @Nonnull
private final Bus bus; private final Bus bus;
@Inject @Inject
Application application;
@Inject
Lazy<Keyboard> keyboard; Lazy<Keyboard> keyboard;
@Inject @Inject
Lazy<Clipboard> clipboard; Lazy<Clipboard> clipboard;
@ -84,6 +89,10 @@ public class Display implements CalculatorEventListener, View.OnClickListener, V
public void onCalculationFinished(@Nonnull CalculationFinishedEvent e) { public void onCalculationFinished(@Nonnull CalculationFinishedEvent e) {
if (e.sequence < state.sequence) return; if (e.sequence < state.sequence) return;
setState(DisplayState.createValid(e.operation, e.result, e.stringResult, e.sequence)); setState(DisplayState.createValid(e.operation, e.result, e.stringResult, e.sequence));
if (!e.messages.isEmpty()) {
final Context context = view != null ? view.getContext() : application;
FixableErrorsActivity.show(context, e.messages);
}
} }
@Subscribe @Subscribe

View File

@ -64,18 +64,18 @@ public class DisplayState implements Parcelable, ContextMenu.ContextMenuInfo {
} }
DisplayState(@Nonnull JSONObject json) { DisplayState(@Nonnull JSONObject json) {
this(json.optString(JSON_TEXT), true, EditorState.NO_SEQUENCE); this(json.optString(JSON_TEXT), true, Calculator.NO_SEQUENCE);
} }
private DisplayState(Parcel in) { private DisplayState(Parcel in) {
text = in.readString(); text = in.readString();
valid = in.readByte() != 0; valid = in.readByte() != 0;
sequence = EditorState.NO_SEQUENCE; sequence = Calculator.NO_SEQUENCE;
} }
@Nonnull @Nonnull
public static DisplayState empty() { public static DisplayState empty() {
return new DisplayState("", true, EditorState.NO_SEQUENCE); return new DisplayState("", true, Calculator.NO_SEQUENCE);
} }
@Nonnull @Nonnull

View File

@ -25,18 +25,14 @@ package org.solovyev.android.calculator;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.text.TextUtils; import android.text.TextUtils;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class EditorState implements Parcelable { public class EditorState implements Parcelable {
public static final long NO_SEQUENCE = -1;
public static final Creator<EditorState> CREATOR = new Creator<EditorState>() { public static final Creator<EditorState> CREATOR = new Creator<EditorState>() {
@Override @Override
public EditorState createFromParcel(Parcel in) { public EditorState createFromParcel(Parcel in) {
@ -50,7 +46,6 @@ public class EditorState implements Parcelable {
}; };
private static final String JSON_TEXT = "t"; private static final String JSON_TEXT = "t";
private static final String JSON_SELECTION = "s"; private static final String JSON_SELECTION = "s";
private static AtomicLong counter = new AtomicLong(NO_SEQUENCE + 1);
public final long sequence; public final long sequence;
@Nonnull @Nonnull
public final CharSequence text; public final CharSequence text;
@ -63,7 +58,7 @@ public class EditorState implements Parcelable {
} }
private EditorState(@Nonnull CharSequence text, int selection) { private EditorState(@Nonnull CharSequence text, int selection) {
this.sequence = counter.getAndIncrement(); this.sequence = Calculator.nextSequence();
this.text = text; this.text = text;
this.selection = selection; this.selection = selection;
} }
@ -73,7 +68,7 @@ public class EditorState implements Parcelable {
} }
private EditorState(Parcel in) { private EditorState(Parcel in) {
sequence = NO_SEQUENCE; sequence = Calculator.NO_SEQUENCE;
selection = in.readInt(); selection = in.readInt();
textString = in.readString(); textString = in.readString();
text = textString; text = textString;

View File

@ -31,48 +31,43 @@ import java.util.List;
public class PreparedExpression implements CharSequence { public class PreparedExpression implements CharSequence {
@Nonnull @Nonnull
private String expression; public final String value;
@Nonnull @Nonnull
private List<IConstant> undefinedVars; public final List<IConstant> undefinedVariables;
public PreparedExpression(@Nonnull String expression, @Nonnull List<IConstant> undefinedVars) { public PreparedExpression(@Nonnull String value, @Nonnull List<IConstant> undefinedVariables) {
this.expression = expression; this.value = value;
this.undefinedVars = undefinedVars; this.undefinedVariables = undefinedVariables;
} }
@Nonnull @Nonnull
public String getExpression() { public String getValue() {
return expression; return value;
} }
public boolean isExistsUndefinedVar() { public boolean hasUndefinedVariables() {
return !this.undefinedVars.isEmpty(); return !undefinedVariables.isEmpty();
}
@Nonnull
public List<IConstant> getUndefinedVars() {
return undefinedVars;
} }
@Override @Override
public int length() { public int length() {
return expression.length(); return value.length();
} }
@Override @Override
public char charAt(int i) { public char charAt(int i) {
return expression.charAt(i); return value.charAt(i);
} }
@Override @Override
public CharSequence subSequence(int i, int i1) { public CharSequence subSequence(int i, int i1) {
return expression.subSequence(i, i1); return value.subSequence(i, i1);
} }
@NonNull @NonNull
@Override @Override
public String toString() { public String toString() {
return this.expression; return this.value;
} }
} }

View File

@ -52,9 +52,6 @@ import java.util.Map;
@Singleton @Singleton
public class VariablesRegistry extends BaseEntitiesRegistry<IConstant> { public class VariablesRegistry extends BaseEntitiesRegistry<IConstant> {
@Nonnull
public static final String ANS = "ans";
@Nonnull @Nonnull
private static final Map<String, String> substitutes = new HashMap<>(); private static final Map<String, String> substitutes = new HashMap<>();

View File

@ -2,25 +2,32 @@ package org.solovyev.android.calculator.calculations;
import jscl.math.Generic; import jscl.math.Generic;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.msg.Message;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
public final class CalculationFinishedEvent extends BaseCalculationEvent { public final class CalculationFinishedEvent extends BaseCalculationEvent {
@Nullable @Nullable
public final Generic result; public final Generic result;
@Nonnull @Nonnull
public final String stringResult; public final String stringResult;
@Nonnull
public final List<Message> messages;
public CalculationFinishedEvent(@Nonnull JsclOperation operation, @Nonnull String expression, long sequence) { public CalculationFinishedEvent(@Nonnull JsclOperation operation, @Nonnull String expression, long sequence) {
super(operation, expression, sequence); super(operation, expression, sequence);
result = null; result = null;
stringResult = ""; stringResult = "";
messages = Collections.emptyList();
} }
public CalculationFinishedEvent(@Nonnull JsclOperation operation, @Nonnull String expression, long sequence, @Nullable Generic result, @Nonnull String stringResult) { public CalculationFinishedEvent(@Nonnull JsclOperation operation, @Nonnull String expression, long sequence, @Nullable Generic result, @Nonnull String stringResult, @Nonnull List<Message> messages) {
super(operation, expression, sequence); super(operation, expression, sequence);
this.result = result; this.result = result;
this.stringResult = stringResult; this.stringResult = stringResult;
this.messages = messages;
} }
} }

View File

@ -271,7 +271,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements View.OnC
private boolean applyData() { private boolean applyData() {
try { try {
final String body = calculator.prepareExpression(bodyView.getText().toString()).getExpression(); final String body = calculator.prepare(bodyView.getText().toString()).getValue();
final CppFunction newFunction = CppFunction.builder(nameView.getText().toString(), body) final CppFunction newFunction = CppFunction.builder(nameView.getText().toString(), body)
.withId(isNewFunction() ? NO_ID : function.id) .withId(isNewFunction() ? NO_ID : function.id)
@ -326,7 +326,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements View.OnC
return false; return false;
} }
try { try {
calculator.prepareExpression(body); calculator.prepare(body);
clearError(bodyLabel); clearError(bodyLabel);
return true; return true;
} catch (ParseException e) { } catch (ParseException e) {

View File

@ -100,7 +100,7 @@ public class History {
final OldDisplayHistoryState oldDisplay = state.getDisplayState(); final OldDisplayHistoryState oldDisplay = state.getDisplayState();
final String editorText = oldEditor.getText(); final String editorText = oldEditor.getText();
final EditorState editor = EditorState.create(Strings.nullToEmpty(editorText), oldEditor.getCursorPosition()); final EditorState editor = EditorState.create(Strings.nullToEmpty(editorText), oldEditor.getCursorPosition());
final DisplayState display = DisplayState.createValid(oldDisplay.getJsclOperation(), null, Strings.nullToEmpty(oldDisplay.getEditorState().getText()), EditorState.NO_SEQUENCE); final DisplayState display = DisplayState.createValid(oldDisplay.getJsclOperation(), null, Strings.nullToEmpty(oldDisplay.getEditorState().getText()), Calculator.NO_SEQUENCE);
states.add(HistoryState.builder(editor, display).withTime(state.getTime()).withComment(state.getComment()).build()); states.add(HistoryState.builder(editor, display).withTime(state.getTime()).withComment(state.getComment()).build());
} }
return states; return states;

View File

@ -61,9 +61,8 @@ public class VariablesFragment extends BaseEntitiesFragment<IConstant> {
public static boolean isValidValue(@Nonnull String value) { public static boolean isValidValue(@Nonnull String value) {
try { try {
final PreparedExpression expression = ToJsclTextProcessor.getInstance().process(value); final PreparedExpression pe = ToJsclTextProcessor.getInstance().process(value);
final List<IConstant> variables = expression.getUndefinedVars(); return !pe.hasUndefinedVariables();
return variables.isEmpty();
} catch (RuntimeException e) { } catch (RuntimeException e) {
return false; return false;
} }

View File

@ -57,7 +57,7 @@ public class NumeralBaseConverterDialog {
if (!Strings.isEmpty(initialFromValue)) { if (!Strings.isEmpty(initialFromValue)) {
String value = initialFromValue; String value = initialFromValue;
try { try {
value = ToJsclTextProcessor.getInstance().process(value).getExpression(); value = ToJsclTextProcessor.getInstance().process(value).getValue();
b.setFromValue(UnitImpl.newInstance(value, CalculatorNumeralBase.valueOf(Locator.getInstance().getEngine().getMathEngine().getNumeralBase()))); b.setFromValue(UnitImpl.newInstance(value, CalculatorNumeralBase.valueOf(Locator.getInstance().getEngine().getMathEngine().getNumeralBase())));
} catch (ParseException e) { } catch (ParseException e) {
b.setFromValue(UnitImpl.newInstance(value, CalculatorNumeralBase.valueOf(Locator.getInstance().getEngine().getMathEngine().getNumeralBase()))); b.setFromValue(UnitImpl.newInstance(value, CalculatorNumeralBase.valueOf(Locator.getInstance().getEngine().getMathEngine().getNumeralBase())));

View File

@ -90,7 +90,7 @@ public class AndroidEngineTest extends AbstractCalculatorTest {
} }
@Test @Test
public void testI() throws ParseException, EvalException { public void testI() throws ParseException {
final MathEngine cm = Locator.getInstance().getEngine().getMathEngine(); final MathEngine cm = Locator.getInstance().getEngine().getMathEngine();
CalculatorTestUtils.assertEval("-i", cm.evaluate("i^3")); CalculatorTestUtils.assertEval("-i", cm.evaluate("i^3"));

View File

@ -22,26 +22,24 @@
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.solovyev.android.calculator.AbstractCalculatorTest;
import org.solovyev.android.calculator.ParseException;
import org.solovyev.android.calculator.CalculatorTestUtils;
import org.solovyev.android.calculator.Locator;
import org.solovyev.common.Converter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import au.com.bytecode.opencsv.CSVReader; import au.com.bytecode.opencsv.CSVReader;
import jscl.JsclMathEngine; import jscl.JsclMathEngine;
import jscl.MathEngine; import jscl.MathEngine;
import jscl.math.Expression; import jscl.math.Expression;
import jscl.util.ExpressionGeneratorWithInput; import jscl.util.ExpressionGeneratorWithInput;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.solovyev.android.calculator.AbstractCalculatorTest;
import org.solovyev.android.calculator.CalculatorTestUtils;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.ParseException;
import org.solovyev.common.Converter;
import javax.annotation.Nonnull;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
/** /**
* User: serso * User: serso
@ -56,7 +54,7 @@ public class NumeralBaseTest extends AbstractCalculatorTest {
Locator.getInstance().getEngine().getMathEngine().setPrecision(3); Locator.getInstance().getEngine().getMathEngine().setPrecision(3);
} }
public static void testExpression(@Nonnull String[] line, @Nonnull Converter<String, String> converter) throws jscl.text.ParseException, EvalException, ParseException { public static void testExpression(@Nonnull String[] line, @Nonnull Converter<String, String> converter) throws jscl.text.ParseException, ParseException {
final String dec = line[0].toUpperCase(); final String dec = line[0].toUpperCase();
final String hex = "0x:" + line[1].toUpperCase(); final String hex = "0x:" + line[1].toUpperCase();
final String bin = "0b:" + line[2].toUpperCase(); final String bin = "0b:" + line[2].toUpperCase();

View File

@ -149,7 +149,7 @@ public class ToJsclTextProcessorTest extends AbstractCalculatorTest {
Assert.assertEquals("101", JsclMathEngine.getInstance().evaluate("10+11")); Assert.assertEquals("101", JsclMathEngine.getInstance().evaluate("10+11"));
JsclMathEngine.getInstance().setNumeralBase(NumeralBase.hex); JsclMathEngine.getInstance().setNumeralBase(NumeralBase.hex);
Assert.assertEquals("56CE+CAD", processor.process("56CE+CAD").getExpression()); Assert.assertEquals("56CE+CAD", processor.process("56CE+CAD").getValue());
} finally { } finally {
JsclMathEngine.getInstance().setNumeralBase(defaultNumeralBase); JsclMathEngine.getInstance().setNumeralBase(defaultNumeralBase);
} }

View File

@ -16,7 +16,6 @@ import org.solovyev.common.msg.MessageRegistry;
import org.solovyev.common.msg.Messages; import org.solovyev.common.msg.Messages;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
@ -168,19 +167,16 @@ public class JsclMathEngine implements MathEngine {
// detect if current number is precisely equals to constant in constants' registry (NOTE: ONLY FOR SYSTEM CONSTANTS) // detect if current number is precisely equals to constant in constants' registry (NOTE: ONLY FOR SYSTEM CONSTANTS)
final Double localValue = value; final Double localValue = value;
IConstant constant = Collections.find(this.getConstantsRegistry().getSystemEntities(), new JPredicate<IConstant>() { IConstant constant = Collections.find(getConstantsRegistry().getSystemEntities(), new JPredicate<IConstant>() {
public boolean apply(@Nullable IConstant constant) { public boolean apply(@Nonnull IConstant constant) {
if (constant != null) { if (!localValue.equals(constant.getDoubleValue())) {
if (localValue.equals(constant.getDoubleValue())) { return false;
if (!constant.getName().equals(Constants.PI_INV.getName())) {
if (!constant.getName().equals(Constants.PI.getName()) || JsclMathEngine.getInstance().getAngleUnits() == AngleUnit.rad) {
return true;
}
}
}
} }
final String name = constant.getName();
return false; if (name.equals(Constants.PI_INV.getName()) || name.equals(Constants.ANS)) {
return false;
}
return !name.equals(Constants.PI.getName()) || JsclMathEngine.getInstance().getAngleUnits() == AngleUnit.rad;
} }
}); });

View File

@ -2,6 +2,8 @@ package jscl.math.function;
import jscl.math.JsclInteger; import jscl.math.JsclInteger;
import javax.annotation.Nonnull;
/** /**
* User: serso * User: serso
* Date: 1/7/12 * Date: 1/7/12
@ -14,6 +16,8 @@ public final class Constants {
public static final Constant I = new Constant("i"); public static final Constant I = new Constant("i");
public static final Constant INF = new Constant(""); public static final Constant INF = new Constant("");
public static final Constant INF_2 = new Constant("Infinity"); public static final Constant INF_2 = new Constant("Infinity");
@Nonnull
public static final String ANS = "ans";
// not intended for instantiation // not intended for instantiation
private Constants() { private Constants() {