diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b8d540bf..63493307 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -68,5 +68,10 @@
a:configChanges="orientation|keyboardHidden">
+
+
+
\ No newline at end of file
diff --git a/res/layout/display_error_message.xml b/res/layout/display_error_message.xml
new file mode 100644
index 00000000..46851234
--- /dev/null
+++ b/res/layout/display_error_message.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4385074d..6ea43e89 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -276,4 +276,6 @@ Check the \'Round result\' preference in application settings - it should be tur
No parameters are specified for function: {0}
Infinite loop is detected in expression
+ Graph
+
diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java b/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java
index 3e3d58c7..4c06922f 100644
--- a/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java
+++ b/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java
@@ -3,6 +3,19 @@ package org.solovyev.android.calculator;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
+import jscl.math.Expression;
+import jscl.math.Generic;
+import jscl.math.JsclInteger;
+import jscl.math.NumericWrapper;
+import jscl.math.function.Constant;
+import jscl.math.numeric.Complex;
+import jscl.math.numeric.Numeric;
+import jscl.math.numeric.Real;
+import org.achartengine.ChartFactory;
+import org.achartengine.model.XYMultipleSeriesDataset;
+import org.achartengine.model.XYSeries;
+import org.achartengine.renderer.XYMultipleSeriesRenderer;
+import org.achartengine.renderer.XYSeriesRenderer;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.help.HelpActivity;
import org.solovyev.common.utils.StringUtils;
@@ -42,6 +55,48 @@ public class CalculatorActivityLauncher {
context.startActivity(new Intent(context, CalculatorVarsActivity.class));
}
+ public static void plotGraph(@NotNull final Context context, @NotNull Generic generic, @NotNull Constant constant) throws ArithmeticException {
+
+ final XYSeries series = new XYSeries(generic.toString());
+
+ final double min = -10;
+ final double max = 10;
+ final double step = 0.5;
+ double x = min;
+ while (x <= max) {
+ Generic numeric = generic.substitute(constant, Expression.valueOf(x)).numeric();
+ series.add(x, unwrap(numeric));
+ x += step;
+ }
+ final XYMultipleSeriesDataset data = new XYMultipleSeriesDataset();
+ data.addSeries(series);
+ final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
+ renderer.addSeriesRenderer(new XYSeriesRenderer());
+ final Intent intent = ChartFactory.getLineChartIntent(context, data, renderer);
+ intent.setClass(context, CalculatorPlotActivity.class);
+ context.startActivity(intent);
+ }
+
+ private static double unwrap(Generic numeric) {
+ if ( numeric instanceof JsclInteger) {
+ return ((JsclInteger) numeric).intValue();
+ } else if ( numeric instanceof NumericWrapper ) {
+ return unwrap(((NumericWrapper) numeric).content());
+ } else {
+ throw new ArithmeticException();
+ }
+ }
+
+ private static double unwrap(Numeric content) {
+ if (content instanceof Real) {
+ return ((Real) content).doubleValue();
+ } else if ( content instanceof Complex) {
+ return ((Complex) content).realPart();
+ } else {
+ throw new ArithmeticException();
+ }
+ }
+
public static void createVar(@NotNull final Context context, @NotNull CalculatorModel calculatorModel) {
if (calculatorModel.getDisplay().isValid() ) {
final String varValue = calculatorModel.getDisplay().getText().toString();
diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java
index 662018cb..130041d9 100644
--- a/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java
+++ b/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java
@@ -10,6 +10,7 @@ import android.graphics.Color;
import android.text.Html;
import android.util.AttributeSet;
import android.util.Log;
+import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
@@ -35,6 +36,9 @@ public class CalculatorDisplay extends AutoResizeTextView {
@NotNull
private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, true);
+ @Nullable
+ private Generic genericResult;
+
public CalculatorDisplay(Context context) {
super(context);
}
@@ -106,4 +110,12 @@ public class CalculatorDisplay extends AutoResizeTextView {
resizeText();
}
+ public void setGenericResult(@Nullable Generic genericResult) {
+ this.genericResult = genericResult;
+ }
+
+ @Nullable
+ public Generic getGenericResult() {
+ return genericResult;
+ }
}
diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorDisplayHistoryState.java b/src/main/java/org/solovyev/android/calculator/CalculatorDisplayHistoryState.java
index d3fd0b81..bf7b827f 100644
--- a/src/main/java/org/solovyev/android/calculator/CalculatorDisplayHistoryState.java
+++ b/src/main/java/org/solovyev/android/calculator/CalculatorDisplayHistoryState.java
@@ -5,6 +5,7 @@
package org.solovyev.android.calculator;
+import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
@@ -27,6 +28,9 @@ public class CalculatorDisplayHistoryState {
@NotNull
private JsclOperation jsclOperation;
+ @Nullable
+ private Generic genericResult;
+
private CalculatorDisplayHistoryState() {
}
@@ -37,6 +41,7 @@ public class CalculatorDisplayHistoryState {
result.editorHistoryState = EditorHistoryState.newInstance(display);
result.valid = display.isValid();
result.jsclOperation = display.getJsclOperation();
+ result.genericResult = display.getGenericResult();
result.errorMessage = display.getErrorMessage();
return result;
@@ -61,6 +66,11 @@ public class CalculatorDisplayHistoryState {
return errorMessage;
}
+ @Nullable
+ public Generic getGenericResult() {
+ return genericResult;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java
index c2d2fb79..823a5af1 100644
--- a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java
+++ b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java
@@ -12,23 +12,31 @@ import android.content.SharedPreferences;
import android.os.Handler;
import android.text.ClipboardManager;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
+import jscl.math.Generic;
+import jscl.math.function.Constant;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.model.ParseException;
+import org.solovyev.android.calculator.model.Var;
import org.solovyev.android.view.CursorControl;
import org.solovyev.android.view.HistoryControl;
import org.solovyev.common.BooleanMapper;
+import org.solovyev.common.utils.CollectionsUtils;
import org.solovyev.common.utils.MutableObject;
import org.solovyev.common.utils.StringUtils;
import org.solovyev.common.utils.history.HistoryAction;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* User: serso
* Date: 9/12/11
@@ -67,7 +75,42 @@ public enum CalculatorModel implements CursorControl, HistoryControl notSystemConstants = new HashSet();
+ for (Constant constant : genericResult.getConstants()) {
+ Var var = CalculatorEngine.instance.getVarsRegister().get(constant.getName());
+ if (var != null && !var.isSystem()) {
+ notSystemConstants.add(constant);
+ }
+ }
+
+ if ( notSystemConstants.size() > 0 ) {
+ if (notSystemConstants.size() > 1) {
+ copyResult(activity, cd);
+ } else {
+ final Constant constant = CollectionsUtils.getFirstCollectionElement(notSystemConstants);
+ assert constant != null;
+ try {
+ CalculatorActivityLauncher.plotGraph(activity, genericResult, constant);
+ } catch (ArithmeticException e) {
+ copyResult(activity, cd);
+ }
+ }
+ } else {
+ copyResult(activity, cd);
+ }
+ } else {
+ copyResult(activity, cd);
+ }
+ break;
+ case elementary:
+ case numeric:
+ copyResult(activity, cd);
+ break;
+ }
} else {
final String errorMessage = cd.getErrorMessage();
if ( errorMessage != null ) {
@@ -91,11 +134,14 @@ public enum CalculatorModel implements CursorControl, HistoryControl tokens = new ArrayList(10);
{
@@ -37,7 +37,7 @@ public enum MathType {
public List getTokens() {
return tokens;
}
- },
+ },*/
dot(200, true, true, ".") {
@Override
@@ -138,7 +138,7 @@ public enum MathType {
}
@Override
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
- return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit && mathTypeBefore != dot && mathTypeBefore != numeral_base;
+ return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit && mathTypeBefore != dot /*&& mathTypeBefore != numeral_base*/;
}
@NotNull
diff --git a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java
index b306065a..df3835da 100644
--- a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java
+++ b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java
@@ -10,13 +10,13 @@ import android.content.SharedPreferences;
import jscl.AngleUnit;
import jscl.JsclMathEngine;
import jscl.MathEngine;
+import jscl.math.Generic;
import jscl.math.function.Function;
import jscl.math.operator.Operator;
import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
-import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.NumberMapper;
import org.solovyev.common.msg.MessageRegistry;
import org.solovyev.common.utils.MutableObject;
@@ -50,6 +50,7 @@ public enum CalculatorEngine {
public static final String ANGLE_UNITS_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_angle_units";
public static final String ANGLE_UNITS_DEFAULT = "deg";
+ public static final int DEFAULT_TIMEOUT = 3000;
@NotNull
private final Object lock = new Object();
@@ -89,7 +90,7 @@ public enum CalculatorEngine {
private ThreadKiller threadKiller = new AndroidThreadKiller();
// calculation thread timeout in milliseconds, after timeout thread would be interrupted
- private int timeout = 3000;
+ private int timeout = DEFAULT_TIMEOUT;
@NotNull
public String format(@NotNull Double value) {
@@ -118,15 +119,20 @@ public enum CalculatorEngine {
}
public static class Result {
+
+ @NotNull
+ private Generic genericResult;
+
@NotNull
private String result;
@NotNull
private JsclOperation userOperation;
- public Result(@NotNull String result, @NotNull JsclOperation userOperation) {
+ public Result(@NotNull String result, @NotNull JsclOperation userOperation, @NotNull Generic genericResult) {
this.result = result;
this.userOperation = userOperation;
+ this.genericResult = genericResult;
}
@NotNull
@@ -138,6 +144,11 @@ public enum CalculatorEngine {
public JsclOperation getUserOperation() {
return userOperation;
}
+
+ @NotNull
+ public Generic getGenericResult() {
+ return genericResult;
+ }
}
public Result evaluate(@NotNull JsclOperation operation,
@@ -174,7 +185,7 @@ public enum CalculatorEngine {
final JsclOperation finalOperation = operation;
final String result;
- final MutableObject calculationResult = new MutableObject(null);
+ final MutableObject calculationResult = new MutableObject(null);
final MutableObject exception = new MutableObject(null);
final MutableObject calculationThread = new MutableObject(null);
@@ -188,7 +199,7 @@ public enum CalculatorEngine {
//Log.d(CalculatorEngine.class.getName(), "Calculation thread started work: " + thread.getName());
//System.out.println(jsclExpression);
calculationThread.setObject(thread);
- calculationResult.setObject(finalOperation.evaluate(jsclExpression));
+ calculationResult.setObject(finalOperation.evaluateGeneric(jsclExpression));
} catch (ArithmeticException e) {
//System.out.println(e.getMessage());
exception.setObject(new ParseException(Messages.msg_1, jsclExpression, e.getMessage()));
@@ -239,9 +250,9 @@ public enum CalculatorEngine {
throw new ParseException(Messages.msg_4, jsclExpression);
}
- result = String.valueOf(calculationResult.getObject()).trim();
+ final Generic genericResult = calculationResult.getObject();
- return new Result(operation.getFromProcessor().process(result), operation);
+ return new Result(operation.getFromProcessor().process(genericResult.toString()), operation, genericResult);
}
}
diff --git a/src/main/java/org/solovyev/android/calculator/model/NumberBuilder.java b/src/main/java/org/solovyev/android/calculator/model/NumberBuilder.java
index 068902d8..1bf14e34 100644
--- a/src/main/java/org/solovyev/android/calculator/model/NumberBuilder.java
+++ b/src/main/java/org/solovyev/android/calculator/model/NumberBuilder.java
@@ -6,7 +6,6 @@
package org.solovyev.android.calculator.model;
-import jscl.NumeralBase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.math.MathType;
@@ -31,9 +30,9 @@ public class NumberBuilder {
private final boolean simpleFormat;
- @Nullable
+ /*@Nullable
private NumeralBase nb;
-
+*/
public NumberBuilder(boolean simpleFormat) {
this.simpleFormat = simpleFormat;
}
@@ -43,17 +42,17 @@ public class NumberBuilder {
number = null;
final MathType.Result possibleResult;
- if ((CollectionsUtils.contains(mathTypeResult.getMathType(), MathType.digit, MathType.numeral_base, MathType.dot, MathType.grouping_separator, MathType.power_10) ||
+ if ((CollectionsUtils.contains(mathTypeResult.getMathType(), MathType.digit, /*MathType.numeral_base,*/ MathType.dot, MathType.grouping_separator, MathType.power_10) ||
isSignAfterE(mathTypeResult)) && numeralBaseCheck(mathTypeResult)) {
if (numberBuilder == null) {
numberBuilder = new StringBuilder();
}
- if (mathTypeResult.getMathType() != MathType.numeral_base) {
+ /*if (mathTypeResult.getMathType() != MathType.numeral_base) {*/
numberBuilder.append(mathTypeResult.getMatch());
- } else {
+ /*} else {
nb = NumeralBase.getByPrefix(mathTypeResult.getMatch());
- }
+ }*/
possibleResult = null;
} else {
@@ -64,7 +63,7 @@ public class NumberBuilder {
}
private boolean numeralBaseCheck( @NotNull MathType.Result mathType ) {
- if ( mathType.getMathType() == MathType.digit ) {
+ /*if ( mathType.getMathType() == MathType.digit ) {
final Character ch = mathType.getMatch().charAt(0);
if ( NumeralBase.hex.getAcceptableCharacters().contains(ch) && !NumeralBase.dec.getAcceptableCharacters().contains(ch) ) {
if ( nb == NumeralBase.hex ) {
@@ -77,7 +76,8 @@ public class NumberBuilder {
}
} else {
return true;
- }
+ }*/
+ return true;
}
private boolean isSignAfterE(@NotNull MathType.Result mathTypeResult) {
@@ -113,7 +113,7 @@ public class NumberBuilder {
}
numberBuilder = null;
- nb = null;
+ /*nb = null;*/
} else {
number = null;
}
diff --git a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java
index f9023e2a..5ad51609 100644
--- a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java
+++ b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java
@@ -36,12 +36,12 @@ class ToJsclTextProcessor implements TextProcessor {
final StringBuilder result = new StringBuilder();
MathType.Result mathTypeResult = null;
- MathType mathTypeBefore;
+ MathType.Result mathTypeBefore = null;
for (int i = 0; i < s.length(); i++) {
startsWithFinder.setI(i);
- mathTypeBefore = mathTypeResult == null ? null : mathTypeResult.getMathType();
+ mathTypeBefore = mathTypeResult == null ? null : mathTypeResult;
mathTypeResult = MathType.getType(s, i);
@@ -49,13 +49,15 @@ class ToJsclTextProcessor implements TextProcessor {
final MathType current = mathTypeResult.getMathType();
- if (current.isNeedMultiplicationSignBefore(mathTypeBefore)) {
+ if (current.isNeedMultiplicationSignBefore(mathTypeBefore.getMathType())) {
result.append("*");
}
}
- if ((mathTypeBefore == MathType.function || mathTypeBefore == MathType.operator) && CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) {
- throw new ParseException(Messages.msg_5, i, s, mathTypeResult.getMatch());
+ if (mathTypeBefore != null &&
+ (mathTypeBefore.getMathType() == MathType.function || mathTypeBefore.getMathType() == MathType.operator) &&
+ CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) {
+ throw new ParseException(Messages.msg_5, i, s, mathTypeBefore.getMatch());
}
i = mathTypeResult.processToJscl(result, i);