diff --git a/calculatorpp-core/pom.xml b/calculatorpp-core/pom.xml
index 22f023e6..17ae2ad2 100644
--- a/calculatorpp-core/pom.xml
+++ b/calculatorpp-core/pom.xml
@@ -35,6 +35,11 @@
jscl
+
+ org.simpleframework
+ simple-xml
+
+
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/CalculatorParseException.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorParseException.java
similarity index 93%
rename from calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/CalculatorParseException.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorParseException.java
index 157a6c82..8ebfccf7 100644
--- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/CalculatorParseException.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorParseException.java
@@ -4,7 +4,7 @@
* or visit http://se.solovyev.org
*/
-package org.solovyev.android.calculator.model;
+package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/AbstractHistoryState.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/AbstractHistoryState.java
similarity index 94%
rename from calculatorpp/src/main/java/org/solovyev/android/calculator/history/AbstractHistoryState.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/AbstractHistoryState.java
index 39d942b9..633d8a7f 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/AbstractHistoryState.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/AbstractHistoryState.java
@@ -1,81 +1,80 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator.history;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.simpleframework.xml.Element;
-import org.simpleframework.xml.Transient;
-
-import java.util.Date;
-
-/**
- * User: serso
- * Date: 10/15/11
- * Time: 1:45 PM
- */
-public class AbstractHistoryState implements Cloneable{
-
- @Element
- private long time = new Date().getTime();
-
- @Element(required = false)
- @Nullable
- private String comment;
-
- @Transient
- private boolean saved;
-
- @Transient
- private int id = 0;
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = id;
- }
-
- public long getTime() {
- return time;
- }
-
- public void setTime(long time) {
- this.time = time;
- }
-
- @Nullable
- public String getComment() {
- return comment;
- }
-
- public void setComment(@Nullable String comment) {
- this.comment = comment;
- }
-
- public boolean isSaved() {
- return saved;
- }
-
- public void setSaved(boolean saved) {
- this.saved = saved;
- }
-
- @Override
- protected AbstractHistoryState clone() {
- AbstractHistoryState clone;
-
- try {
- clone = (AbstractHistoryState)super.clone();
- } catch (CloneNotSupportedException e) {
- throw new UnsupportedOperationException(e);
- }
-
- return clone;
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator.history;
+
+import org.jetbrains.annotations.Nullable;
+import org.simpleframework.xml.Element;
+import org.simpleframework.xml.Transient;
+
+import java.util.Date;
+
+/**
+ * User: serso
+ * Date: 10/15/11
+ * Time: 1:45 PM
+ */
+public class AbstractHistoryState implements Cloneable{
+
+ @Element
+ private long time = new Date().getTime();
+
+ @Element(required = false)
+ @Nullable
+ private String comment;
+
+ @Transient
+ private boolean saved;
+
+ @Transient
+ private int id = 0;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public long getTime() {
+ return time;
+ }
+
+ public void setTime(long time) {
+ this.time = time;
+ }
+
+ @Nullable
+ public String getComment() {
+ return comment;
+ }
+
+ public void setComment(@Nullable String comment) {
+ this.comment = comment;
+ }
+
+ public boolean isSaved() {
+ return saved;
+ }
+
+ public void setSaved(boolean saved) {
+ this.saved = saved;
+ }
+
+ @Override
+ protected AbstractHistoryState clone() {
+ AbstractHistoryState clone;
+
+ try {
+ clone = (AbstractHistoryState)super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new UnsupportedOperationException(e);
+ }
+
+ return clone;
+ }
+}
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java
similarity index 95%
rename from calculatorpp/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java
index af6713f5..b637e901 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java
@@ -1,138 +1,138 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- */
-
-package org.solovyev.android.calculator.history;
-
-import jscl.math.Generic;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.simpleframework.xml.Element;
-import org.simpleframework.xml.Root;
-import org.simpleframework.xml.Transient;
-import org.solovyev.android.calculator.ICalculatorDisplay;
-import org.solovyev.android.calculator.jscl.JsclOperation;
-
-/**
- * User: serso
- * Date: 9/17/11
- * Time: 11:05 PM
- */
-
-@Root
-public class CalculatorDisplayHistoryState implements Cloneable {
-
- @Transient
- private boolean valid = true;
-
- @Transient
- @Nullable
- private String errorMessage = null;
-
- @Element
- @NotNull
- private EditorHistoryState editorState;
-
- @Element
- @NotNull
- private JsclOperation jsclOperation;
-
- @Transient
- @Nullable
- private Generic genericResult;
-
- private CalculatorDisplayHistoryState() {
- // for xml
- }
-
- @NotNull
- public static CalculatorDisplayHistoryState newInstance(@NotNull ICalculatorDisplay display) {
- final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState();
-
- result.editorState = EditorHistoryState.newInstance(display);
- result.valid = display.isValid();
- result.jsclOperation = display.getJsclOperation();
- result.genericResult = display.getGenericResult();
- result.errorMessage = display.getErrorMessage();
-
- return result;
- }
-
- public void setValuesFromHistory(@NotNull ICalculatorDisplay display) {
- this.getEditorState().setValuesFromHistory(display);
- display.setValid(this.isValid());
- display.setErrorMessage(this.getErrorMessage());
- display.setJsclOperation(this.getJsclOperation());
- display.setGenericResult(this.getGenericResult());
- }
-
-
- public boolean isValid() {
- return valid;
- }
-
- @NotNull
- public EditorHistoryState getEditorState() {
- return editorState;
- }
-
- @NotNull
- public JsclOperation getJsclOperation() {
- return jsclOperation;
- }
-
- @Nullable
- public String getErrorMessage() {
- return errorMessage;
- }
-
- @Nullable
- public Generic getGenericResult() {
- return genericResult;
- }
-
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- CalculatorDisplayHistoryState that = (CalculatorDisplayHistoryState) o;
-
- if (!editorState.equals(that.editorState)) return false;
- if (jsclOperation != that.jsclOperation) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = editorState.hashCode();
- result = 31 * result + jsclOperation.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return "CalculatorDisplayHistoryState{" +
- "valid=" + valid +
- ", errorMessage='" + errorMessage + '\'' +
- ", editorHistoryState=" + editorState +
- ", jsclOperation=" + jsclOperation +
- '}';
- }
-
- @Override
- protected CalculatorDisplayHistoryState clone() {
- try {
- final CalculatorDisplayHistoryState clone = (CalculatorDisplayHistoryState) super.clone();
-
- clone.editorState = this.editorState.clone();
-
- return clone;
- } catch (CloneNotSupportedException e) {
- throw new RuntimeException(e);
- }
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ */
+
+package org.solovyev.android.calculator.history;
+
+import jscl.math.Generic;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.simpleframework.xml.Element;
+import org.simpleframework.xml.Root;
+import org.simpleframework.xml.Transient;
+import org.solovyev.android.calculator.ICalculatorDisplay;
+import org.solovyev.android.calculator.jscl.JsclOperation;
+
+/**
+ * User: serso
+ * Date: 9/17/11
+ * Time: 11:05 PM
+ */
+
+@Root
+public class CalculatorDisplayHistoryState implements Cloneable {
+
+ @Transient
+ private boolean valid = true;
+
+ @Transient
+ @Nullable
+ private String errorMessage = null;
+
+ @Element
+ @NotNull
+ private EditorHistoryState editorState;
+
+ @Element
+ @NotNull
+ private JsclOperation jsclOperation;
+
+ @Transient
+ @Nullable
+ private Generic genericResult;
+
+ private CalculatorDisplayHistoryState() {
+ // for xml
+ }
+
+ @NotNull
+ public static CalculatorDisplayHistoryState newInstance(@NotNull ICalculatorDisplay display) {
+ final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState();
+
+ result.editorState = EditorHistoryState.newInstance(display);
+ result.valid = display.isValid();
+ result.jsclOperation = display.getJsclOperation();
+ result.genericResult = display.getGenericResult();
+ result.errorMessage = display.getErrorMessage();
+
+ return result;
+ }
+
+ public void setValuesFromHistory(@NotNull ICalculatorDisplay display) {
+ this.getEditorState().setValuesFromHistory(display);
+ display.setValid(this.isValid());
+ display.setErrorMessage(this.getErrorMessage());
+ display.setJsclOperation(this.getJsclOperation());
+ display.setGenericResult(this.getGenericResult());
+ }
+
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ @NotNull
+ public EditorHistoryState getEditorState() {
+ return editorState;
+ }
+
+ @NotNull
+ public JsclOperation getJsclOperation() {
+ return jsclOperation;
+ }
+
+ @Nullable
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ @Nullable
+ public Generic getGenericResult() {
+ return genericResult;
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ CalculatorDisplayHistoryState that = (CalculatorDisplayHistoryState) o;
+
+ if (!editorState.equals(that.editorState)) return false;
+ if (jsclOperation != that.jsclOperation) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = editorState.hashCode();
+ result = 31 * result + jsclOperation.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "CalculatorDisplayHistoryState{" +
+ "valid=" + valid +
+ ", errorMessage='" + errorMessage + '\'' +
+ ", editorHistoryState=" + editorState +
+ ", jsclOperation=" + jsclOperation +
+ '}';
+ }
+
+ @Override
+ protected CalculatorDisplayHistoryState clone() {
+ try {
+ final CalculatorDisplayHistoryState clone = (CalculatorDisplayHistoryState) super.clone();
+
+ clone.editorState = this.editorState.clone();
+
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryState.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryState.java
similarity index 100%
rename from calculatorpp/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryState.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryState.java
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/EditorHistoryState.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/EditorHistoryState.java
similarity index 100%
rename from calculatorpp/src/main/java/org/solovyev/android/calculator/history/EditorHistoryState.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/EditorHistoryState.java
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/History.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/History.java
similarity index 95%
rename from calculatorpp/src/main/java/org/solovyev/android/calculator/history/History.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/History.java
index d8be7587..9c3973ad 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/History.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/History.java
@@ -1,33 +1,33 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator.history;
-
-import org.simpleframework.xml.ElementList;
-import org.simpleframework.xml.Root;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * User: serso
- * Date: 12/17/11
- * Time: 9:30 PM
- */
-
-@Root
-public class History {
-
- @ElementList
- private List historyItems = new ArrayList();
-
- public History() {
- }
-
- public List getHistoryItems() {
- return historyItems;
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator.history;
+
+import org.simpleframework.xml.ElementList;
+import org.simpleframework.xml.Root;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: serso
+ * Date: 12/17/11
+ * Time: 9:30 PM
+ */
+
+@Root
+public class History {
+
+ @ElementList
+ private List historyItems = new ArrayList();
+
+ public History() {
+ }
+
+ public List getHistoryItems() {
+ return historyItems;
+ }
+}
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/HistoryUtils.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/HistoryUtils.java
similarity index 96%
rename from calculatorpp/src/main/java/org/solovyev/android/calculator/history/HistoryUtils.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/HistoryUtils.java
index d2f50d36..bda4ca11 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/HistoryUtils.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/HistoryUtils.java
@@ -1,61 +1,61 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator.history;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.simpleframework.xml.Serializer;
-import org.simpleframework.xml.core.Persister;
-
-import java.io.StringWriter;
-import java.util.List;
-
-/**
- * User: serso
- * Date: 12/17/11
- * Time: 9:59 PM
- */
-class HistoryUtils {
-
- // not intended for instantiation
- private HistoryUtils() {
- throw new AssertionError();
- }
-
- public static void fromXml(@Nullable String xml, @NotNull List historyItems) {
- if (xml != null) {
- final Serializer serializer = new Persister();
- try {
- final History history = serializer.read(History.class, xml);
- for (CalculatorHistoryState historyItem : history.getHistoryItems()) {
- historyItems.add(historyItem);
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- @NotNull
- public static String toXml(@NotNull List historyItems) {
- final History history = new History();
- for (CalculatorHistoryState historyState : historyItems) {
- if (historyState.isSaved()) {
- history.getHistoryItems().add(historyState);
- }
- }
-
- final StringWriter xml = new StringWriter();
- final Serializer serializer = new Persister();
- try {
- serializer.write(history, xml);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- return xml.toString();
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator.history;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.simpleframework.xml.Serializer;
+import org.simpleframework.xml.core.Persister;
+
+import java.io.StringWriter;
+import java.util.List;
+
+/**
+ * User: serso
+ * Date: 12/17/11
+ * Time: 9:59 PM
+ */
+class HistoryUtils {
+
+ // not intended for instantiation
+ private HistoryUtils() {
+ throw new AssertionError();
+ }
+
+ public static void fromXml(@Nullable String xml, @NotNull List historyItems) {
+ if (xml != null) {
+ final Serializer serializer = new Persister();
+ try {
+ final History history = serializer.read(History.class, xml);
+ for (CalculatorHistoryState historyItem : history.getHistoryItems()) {
+ historyItems.add(historyItem);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @NotNull
+ public static String toXml(@NotNull List historyItems) {
+ final History history = new History();
+ for (CalculatorHistoryState historyState : historyItems) {
+ if (historyState.isSaved()) {
+ history.getHistoryItems().add(historyState);
+ }
+ }
+
+ final StringWriter xml = new StringWriter();
+ final Serializer serializer = new Persister();
+ try {
+ serializer.write(history, xml);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return xml.toString();
+ }
+}
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java
index b664c9ff..2251e5b8 100644
--- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/jscl/FromJsclNumericTextProcessor.java
@@ -8,8 +8,8 @@ package org.solovyev.android.calculator.jscl;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
-import org.solovyev.android.calculator.model.CalculatorParseException;
-import org.solovyev.android.calculator.model.TextProcessor;
+import org.solovyev.android.calculator.CalculatorParseException;
+import org.solovyev.android.calculator.text.TextProcessor;
/**
* User: serso
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/jscl/JsclOperation.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/jscl/JsclOperation.java
index f3a21199..978964b7 100644
--- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/jscl/JsclOperation.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/jscl/JsclOperation.java
@@ -10,9 +10,9 @@ import jscl.math.Generic;
import jscl.text.ParseException;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.CalculatorLocatorImpl;
-import org.solovyev.android.calculator.model.DummyTextProcessor;
-import org.solovyev.android.calculator.model.FromJsclSimplifyTextProcessor;
-import org.solovyev.android.calculator.model.TextProcessor;
+import org.solovyev.android.calculator.text.DummyTextProcessor;
+import org.solovyev.android.calculator.text.FromJsclSimplifyTextProcessor;
+import org.solovyev.android.calculator.text.TextProcessor;
public enum JsclOperation {
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/math/MathType.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/math/MathType.java
index 4aa60280..549ae9fd 100644
--- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/math/MathType.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/math/MathType.java
@@ -13,7 +13,7 @@ import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CalculatorLocatorImpl;
import org.solovyev.common.JPredicate;
import org.solovyev.common.StartsWithFinder;
-import org.solovyev.android.calculator.model.CalculatorParseException;
+import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.common.collections.CollectionsUtils;
import java.util.*;
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/DummyTextProcessor.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/text/DummyTextProcessor.java
similarity index 78%
rename from calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/DummyTextProcessor.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/text/DummyTextProcessor.java
index 779a1fe8..22a969c5 100644
--- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/DummyTextProcessor.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/text/DummyTextProcessor.java
@@ -4,10 +4,11 @@
* or visit http://se.solovyev.org
*/
-package org.solovyev.android.calculator.model;
+package org.solovyev.android.calculator.text;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
+import org.solovyev.android.calculator.CalculatorParseException;
/**
* User: serso
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/text/FromJsclSimplifyTextProcessor.java
similarity index 92%
rename from calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/text/FromJsclSimplifyTextProcessor.java
index d541edea..3fc4da64 100644
--- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/text/FromJsclSimplifyTextProcessor.java
@@ -1,11 +1,11 @@
-package org.solovyev.android.calculator.model;
+package org.solovyev.android.calculator.text;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.solovyev.android.calculator.CalculatorLocator;
import org.solovyev.android.calculator.CalculatorLocatorImpl;
import org.solovyev.android.calculator.math.MathType;
+import org.solovyev.android.calculator.CalculatorParseException;
import java.util.Arrays;
import java.util.List;
diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/TextProcessor.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/text/TextProcessor.java
similarity index 65%
rename from calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/TextProcessor.java
rename to calculatorpp-core/src/main/java/org/solovyev/android/calculator/text/TextProcessor.java
index a72672fe..b9e96935 100644
--- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/model/TextProcessor.java
+++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/text/TextProcessor.java
@@ -1,6 +1,7 @@
-package org.solovyev.android.calculator.model;
+package org.solovyev.android.calculator.text;
import org.jetbrains.annotations.NotNull;
+import org.solovyev.android.calculator.CalculatorParseException;
/**
* User: serso
diff --git a/calculatorpp/pom.xml b/calculatorpp/pom.xml
index a117fa62..82523499 100644
--- a/calculatorpp/pom.xml
+++ b/calculatorpp/pom.xml
@@ -102,17 +102,6 @@
org.simpleframework
simple-xml
- 2.6.1
-
-
- stax-api
- stax
-
-
- xpp3
- xpp3
-
-
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java
index 77b21101..54fc4e6f 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java
+++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplay.java
@@ -1,348 +1,347 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- */
-
-package org.solovyev.android.calculator;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.text.Html;
-import android.util.AttributeSet;
-import android.util.Log;
-import jscl.NumeralBase;
-import jscl.math.Generic;
-import jscl.math.function.Constant;
-import jscl.math.function.IConstant;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.solovyev.android.calculator.jscl.JsclOperation;
-import org.solovyev.android.calculator.model.CalculatorEngine;
-import org.solovyev.android.calculator.model.CalculatorParseException;
-import org.solovyev.android.calculator.model.TextProcessor;
-import org.solovyev.android.calculator.model.ToJsclTextProcessor;
-import org.solovyev.android.calculator.view.NumeralBaseConverterDialog;
-import org.solovyev.android.calculator.view.TextHighlighter;
-import org.solovyev.android.calculator.view.UnitConverterViewBuilder;
-import org.solovyev.android.menu.AMenuItem;
-import org.solovyev.android.menu.LabeledMenuItem;
-import org.solovyev.android.view.AutoResizeTextView;
-import org.solovyev.common.collections.CollectionsUtils;
-import org.solovyev.common.text.StringUtils;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * User: serso
- * Date: 9/17/11
- * Time: 10:58 PM
- */
-public class CalculatorDisplay extends AutoResizeTextView implements ICalculatorDisplay{
-
- private static enum ConversionMenuItem implements AMenuItem {
- convert_to_bin(NumeralBase.bin),
- convert_to_dec(NumeralBase.dec),
- convert_to_hex(NumeralBase.hex);
-
- @NotNull
- private final NumeralBase toNumeralBase;
-
- private ConversionMenuItem(@NotNull NumeralBase toNumeralBase) {
- this.toNumeralBase = toNumeralBase;
- }
-
- protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
- boolean result = false;
-
- if (operation == JsclOperation.numeric) {
- if (generic.getConstants().isEmpty()) {
- try {
- convert(generic);
-
- // conversion possible => return true
- result = true;
-
- } catch (UnitConverterViewBuilder.ConversionException e) {
- // conversion is not possible => return false
- }
- }
- }
-
- return result;
- }
-
- @Override
- public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
- final NumeralBase fromNumeralBase = CalculatorEngine.instance.getEngine().getNumeralBase();
-
- String to;
- try {
- to = convert(data.getGenericResult());
-
- // add prefix
- if (fromNumeralBase != toNumeralBase) {
- to = toNumeralBase.getJsclPrefix() + to;
- }
- } catch (UnitConverterViewBuilder.ConversionException e) {
- to = context.getString(R.string.c_error);
- }
-
- data.setText(to);
- data.redraw();
- }
-
- @NotNull
- private String convert(@NotNull Generic generic) throws UnitConverterViewBuilder.ConversionException {
- final NumeralBase fromNumeralBase = CalculatorEngine.instance.getEngine().getNumeralBase();
-
- if (fromNumeralBase != toNumeralBase) {
- String from = generic.toString();
- if (!StringUtils.isEmpty(from)) {
- try {
- from = ToJsclTextProcessor.getInstance().process(from).getExpression();
- } catch (CalculatorParseException e) {
- // ok, problems while processing occurred
- }
- }
-
- return UnitConverterViewBuilder.doConversion(AndroidNumeralBase.getConverter(), from, AndroidNumeralBase.valueOf(fromNumeralBase), AndroidNumeralBase.valueOf(toNumeralBase));
- } else {
- return generic.toString();
- }
- }
- }
-
- public static enum MenuItem implements LabeledMenuItem {
-
- copy(R.string.c_copy) {
- @Override
- public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
- CalculatorModel.copyResult(context, data);
- }
- },
-
- convert_to_bin(R.string.convert_to_bin) {
- @Override
- public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
- ConversionMenuItem.convert_to_bin.onClick(data, context);
- }
-
- @Override
- protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
- return ConversionMenuItem.convert_to_bin.isItemVisibleFor(generic, operation);
- }
- },
-
- convert_to_dec(R.string.convert_to_dec) {
- @Override
- public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
- ConversionMenuItem.convert_to_dec.onClick(data, context);
- }
-
- @Override
- protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
- return ConversionMenuItem.convert_to_dec.isItemVisibleFor(generic, operation);
- }
- },
-
- convert_to_hex(R.string.convert_to_hex) {
- @Override
- public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
- ConversionMenuItem.convert_to_hex.onClick(data, context);
- }
-
- @Override
- protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
- return ConversionMenuItem.convert_to_hex.isItemVisibleFor(generic, operation);
- }
- },
-
- convert(R.string.c_convert) {
- @Override
- public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
- new NumeralBaseConverterDialog(data.getGenericResult().toString()).show(context);
- }
-
- @Override
- protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
- return operation == JsclOperation.numeric && generic.getConstants().isEmpty();
- }
- },
-
- plot(R.string.c_plot) {
- @Override
- public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
- final Generic generic = data.getGenericResult();
- assert generic != null;
-
- final Constant constant = CollectionsUtils.getFirstCollectionElement(getNotSystemConstants(generic));
- assert constant != null;
- CalculatorActivityLauncher.plotGraph(context, generic, constant);
- }
-
- @Override
- protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
- boolean result = false;
-
- if (operation == JsclOperation.simplify) {
- if (getNotSystemConstants(generic).size() == 1) {
- result = true;
- }
- }
-
- return result;
- }
-
- @NotNull
- private Set getNotSystemConstants(@NotNull Generic generic) {
- final Set notSystemConstants = new HashSet();
-
- for (Constant constant : generic.getConstants()) {
- IConstant var = CalculatorEngine.instance.getVarsRegistry().get(constant.getName());
- if (var != null && !var.isSystem() && !var.isDefined()) {
- notSystemConstants.add(constant);
- }
- }
-
- return notSystemConstants;
- }
- };
-
- private final int captionId;
-
- MenuItem(int captionId) {
- this.captionId = captionId;
- }
-
- public final boolean isItemVisible(@NotNull CalculatorDisplay display) {
- //noinspection ConstantConditions
- return display.isValid() && display.getGenericResult() != null && isItemVisibleFor(display.getGenericResult(), display.getJsclOperation());
- }
-
- protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
- return true;
- }
-
- @NotNull
- @Override
- public String getCaption(@NotNull Context context) {
- return context.getString(captionId);
- }
- }
-
- private boolean valid = true;
-
- @Nullable
- private String errorMessage;
-
- @NotNull
- private JsclOperation jsclOperation = JsclOperation.numeric;
-
- @NotNull
- private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, false, CalculatorEngine.instance.getEngine());
-
- @Nullable
- private Generic genericResult;
-
- public CalculatorDisplay(Context context) {
- super(context);
- }
-
- public CalculatorDisplay(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public CalculatorDisplay(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- public boolean isValid() {
- return valid;
- }
-
- @Override
- public void setValid(boolean valid) {
- this.valid = valid;
- if (valid) {
- errorMessage = null;
- setTextColor(getResources().getColor(R.color.default_text_color));
- } else {
- setTextColor(getResources().getColor(R.color.display_error_text_color));
- }
- }
-
- @Override
- @Nullable
- public String getErrorMessage() {
- return errorMessage;
- }
-
- @Override
- public void setErrorMessage(@Nullable String errorMessage) {
- this.errorMessage = errorMessage;
- }
-
- @Override
- public void setJsclOperation(@NotNull JsclOperation jsclOperation) {
- this.jsclOperation = jsclOperation;
- }
-
- @Override
- @NotNull
- public JsclOperation getJsclOperation() {
- return jsclOperation;
- }
-
- @Override
- public void setText(CharSequence text, BufferType type) {
- super.setText(text, type);
-
- setValid(true);
- }
-
- public synchronized void redraw() {
- if (isValid()) {
- String text = getText().toString();
-
- Log.d(this.getClass().getName(), text);
-
- try {
- TextHighlighter.Result result = textHighlighter.process(text);
- text = result.toString();
- } catch (CalculatorParseException e) {
- Log.e(this.getClass().getName(), e.getMessage(), e);
- }
-
- Log.d(this.getClass().getName(), text);
- super.setText(Html.fromHtml(text), BufferType.EDITABLE);
- }
-
- // todo serso: think where to move it (keep in mind org.solovyev.android.view.AutoResizeTextView.resetTextSize())
- setAddEllipsis(false);
- setMinTextSize(10);
- resizeText();
- }
-
- @Override
- public void setGenericResult(@Nullable Generic genericResult) {
- this.genericResult = genericResult;
- }
-
- @Override
- @Nullable
- public Generic getGenericResult() {
- return genericResult;
- }
-
- @Override
- public int getSelection() {
- return this.getSelectionStart();
- }
-
- @Override
- public void setSelection(int selection) {
- // not supported by TextView
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ */
+
+package org.solovyev.android.calculator;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.text.Html;
+import android.util.AttributeSet;
+import android.util.Log;
+import jscl.NumeralBase;
+import jscl.math.Generic;
+import jscl.math.function.Constant;
+import jscl.math.function.IConstant;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.solovyev.android.calculator.jscl.JsclOperation;
+import org.solovyev.android.calculator.model.CalculatorEngine;
+import org.solovyev.android.calculator.text.TextProcessor;
+import org.solovyev.android.calculator.model.ToJsclTextProcessor;
+import org.solovyev.android.calculator.view.NumeralBaseConverterDialog;
+import org.solovyev.android.calculator.view.TextHighlighter;
+import org.solovyev.android.calculator.view.UnitConverterViewBuilder;
+import org.solovyev.android.menu.AMenuItem;
+import org.solovyev.android.menu.LabeledMenuItem;
+import org.solovyev.android.view.AutoResizeTextView;
+import org.solovyev.common.collections.CollectionsUtils;
+import org.solovyev.common.text.StringUtils;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * User: serso
+ * Date: 9/17/11
+ * Time: 10:58 PM
+ */
+public class CalculatorDisplay extends AutoResizeTextView implements ICalculatorDisplay{
+
+ private static enum ConversionMenuItem implements AMenuItem {
+ convert_to_bin(NumeralBase.bin),
+ convert_to_dec(NumeralBase.dec),
+ convert_to_hex(NumeralBase.hex);
+
+ @NotNull
+ private final NumeralBase toNumeralBase;
+
+ private ConversionMenuItem(@NotNull NumeralBase toNumeralBase) {
+ this.toNumeralBase = toNumeralBase;
+ }
+
+ protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
+ boolean result = false;
+
+ if (operation == JsclOperation.numeric) {
+ if (generic.getConstants().isEmpty()) {
+ try {
+ convert(generic);
+
+ // conversion possible => return true
+ result = true;
+
+ } catch (UnitConverterViewBuilder.ConversionException e) {
+ // conversion is not possible => return false
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
+ final NumeralBase fromNumeralBase = CalculatorEngine.instance.getEngine().getNumeralBase();
+
+ String to;
+ try {
+ to = convert(data.getGenericResult());
+
+ // add prefix
+ if (fromNumeralBase != toNumeralBase) {
+ to = toNumeralBase.getJsclPrefix() + to;
+ }
+ } catch (UnitConverterViewBuilder.ConversionException e) {
+ to = context.getString(R.string.c_error);
+ }
+
+ data.setText(to);
+ data.redraw();
+ }
+
+ @NotNull
+ private String convert(@NotNull Generic generic) throws UnitConverterViewBuilder.ConversionException {
+ final NumeralBase fromNumeralBase = CalculatorEngine.instance.getEngine().getNumeralBase();
+
+ if (fromNumeralBase != toNumeralBase) {
+ String from = generic.toString();
+ if (!StringUtils.isEmpty(from)) {
+ try {
+ from = ToJsclTextProcessor.getInstance().process(from).getExpression();
+ } catch (CalculatorParseException e) {
+ // ok, problems while processing occurred
+ }
+ }
+
+ return UnitConverterViewBuilder.doConversion(AndroidNumeralBase.getConverter(), from, AndroidNumeralBase.valueOf(fromNumeralBase), AndroidNumeralBase.valueOf(toNumeralBase));
+ } else {
+ return generic.toString();
+ }
+ }
+ }
+
+ public static enum MenuItem implements LabeledMenuItem {
+
+ copy(R.string.c_copy) {
+ @Override
+ public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
+ CalculatorModel.copyResult(context, data);
+ }
+ },
+
+ convert_to_bin(R.string.convert_to_bin) {
+ @Override
+ public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
+ ConversionMenuItem.convert_to_bin.onClick(data, context);
+ }
+
+ @Override
+ protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
+ return ConversionMenuItem.convert_to_bin.isItemVisibleFor(generic, operation);
+ }
+ },
+
+ convert_to_dec(R.string.convert_to_dec) {
+ @Override
+ public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
+ ConversionMenuItem.convert_to_dec.onClick(data, context);
+ }
+
+ @Override
+ protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
+ return ConversionMenuItem.convert_to_dec.isItemVisibleFor(generic, operation);
+ }
+ },
+
+ convert_to_hex(R.string.convert_to_hex) {
+ @Override
+ public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
+ ConversionMenuItem.convert_to_hex.onClick(data, context);
+ }
+
+ @Override
+ protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
+ return ConversionMenuItem.convert_to_hex.isItemVisibleFor(generic, operation);
+ }
+ },
+
+ convert(R.string.c_convert) {
+ @Override
+ public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
+ new NumeralBaseConverterDialog(data.getGenericResult().toString()).show(context);
+ }
+
+ @Override
+ protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
+ return operation == JsclOperation.numeric && generic.getConstants().isEmpty();
+ }
+ },
+
+ plot(R.string.c_plot) {
+ @Override
+ public void onClick(@NotNull CalculatorDisplay data, @NotNull Context context) {
+ final Generic generic = data.getGenericResult();
+ assert generic != null;
+
+ final Constant constant = CollectionsUtils.getFirstCollectionElement(getNotSystemConstants(generic));
+ assert constant != null;
+ CalculatorActivityLauncher.plotGraph(context, generic, constant);
+ }
+
+ @Override
+ protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
+ boolean result = false;
+
+ if (operation == JsclOperation.simplify) {
+ if (getNotSystemConstants(generic).size() == 1) {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+
+ @NotNull
+ private Set getNotSystemConstants(@NotNull Generic generic) {
+ final Set notSystemConstants = new HashSet();
+
+ for (Constant constant : generic.getConstants()) {
+ IConstant var = CalculatorEngine.instance.getVarsRegistry().get(constant.getName());
+ if (var != null && !var.isSystem() && !var.isDefined()) {
+ notSystemConstants.add(constant);
+ }
+ }
+
+ return notSystemConstants;
+ }
+ };
+
+ private final int captionId;
+
+ MenuItem(int captionId) {
+ this.captionId = captionId;
+ }
+
+ public final boolean isItemVisible(@NotNull CalculatorDisplay display) {
+ //noinspection ConstantConditions
+ return display.isValid() && display.getGenericResult() != null && isItemVisibleFor(display.getGenericResult(), display.getJsclOperation());
+ }
+
+ protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
+ return true;
+ }
+
+ @NotNull
+ @Override
+ public String getCaption(@NotNull Context context) {
+ return context.getString(captionId);
+ }
+ }
+
+ private boolean valid = true;
+
+ @Nullable
+ private String errorMessage;
+
+ @NotNull
+ private JsclOperation jsclOperation = JsclOperation.numeric;
+
+ @NotNull
+ private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, false, CalculatorEngine.instance.getEngine());
+
+ @Nullable
+ private Generic genericResult;
+
+ public CalculatorDisplay(Context context) {
+ super(context);
+ }
+
+ public CalculatorDisplay(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CalculatorDisplay(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean isValid() {
+ return valid;
+ }
+
+ @Override
+ public void setValid(boolean valid) {
+ this.valid = valid;
+ if (valid) {
+ errorMessage = null;
+ setTextColor(getResources().getColor(R.color.default_text_color));
+ } else {
+ setTextColor(getResources().getColor(R.color.display_error_text_color));
+ }
+ }
+
+ @Override
+ @Nullable
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ @Override
+ public void setErrorMessage(@Nullable String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ @Override
+ public void setJsclOperation(@NotNull JsclOperation jsclOperation) {
+ this.jsclOperation = jsclOperation;
+ }
+
+ @Override
+ @NotNull
+ public JsclOperation getJsclOperation() {
+ return jsclOperation;
+ }
+
+ @Override
+ public void setText(CharSequence text, BufferType type) {
+ super.setText(text, type);
+
+ setValid(true);
+ }
+
+ public synchronized void redraw() {
+ if (isValid()) {
+ String text = getText().toString();
+
+ Log.d(this.getClass().getName(), text);
+
+ try {
+ TextHighlighter.Result result = textHighlighter.process(text);
+ text = result.toString();
+ } catch (CalculatorParseException e) {
+ Log.e(this.getClass().getName(), e.getMessage(), e);
+ }
+
+ Log.d(this.getClass().getName(), text);
+ super.setText(Html.fromHtml(text), BufferType.EDITABLE);
+ }
+
+ // todo serso: think where to move it (keep in mind org.solovyev.android.view.AutoResizeTextView.resetTextSize())
+ setAddEllipsis(false);
+ setMinTextSize(10);
+ resizeText();
+ }
+
+ @Override
+ public void setGenericResult(@Nullable Generic genericResult) {
+ this.genericResult = genericResult;
+ }
+
+ @Override
+ @Nullable
+ public Generic getGenericResult() {
+ return genericResult;
+ }
+
+ @Override
+ public int getSelection() {
+ return this.getSelectionStart();
+ }
+
+ @Override
+ public void setSelection(int selection) {
+ // not supported by TextView
+ }
+}
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java
index 013b5a09..3f9b20c9 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java
+++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java
@@ -1,166 +1,165 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- */
-
-package org.solovyev.android.calculator;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.graphics.Color;
-import android.os.Build;
-import android.text.Html;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.widget.EditText;
-import org.jetbrains.annotations.NotNull;
-import org.solovyev.android.calculator.model.CalculatorEngine;
-import org.solovyev.android.calculator.model.CalculatorParseException;
-import org.solovyev.android.calculator.model.TextProcessor;
-import org.solovyev.android.calculator.view.TextHighlighter;
-import org.solovyev.common.collections.CollectionsUtils;
-
-/**
- * User: serso
- * Date: 9/17/11
- * Time: 12:25 AM
- */
-public class CalculatorEditor extends EditText implements SharedPreferences.OnSharedPreferenceChangeListener {
-
- private static final String CALC_COLOR_DISPLAY_KEY = "org.solovyev.android.calculator.CalculatorModel_color_display";
- private static final boolean CALC_COLOR_DISPLAY_DEFAULT = true;
-
- private boolean highlightText = true;
-
- @NotNull
- private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, true, CalculatorEngine.instance.getEngine());
-
- public CalculatorEditor(Context context) {
- super(context);
- init();
- }
-
- public CalculatorEditor(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- private void init() {
- // NOTE: in this solution cursor is missing
-
- /*this.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- final TextView textView = (TextView)v;
- // backup the input type
- int inputType = textView.getInputType();
-
- // disable soft input
- textView.setInputType(InputType.TYPE_NULL);
-
- // call native handler
- textView.onTouchEvent(event);
-
- // restore input type
- textView.setInputType(inputType);
-
- // consume touch even
- return true;
- }
- });*/
- }
-
-
- @Override
- public boolean onCheckIsTextEditor() {
- // NOTE: code below can be used carefully and should not be copied without special intention
- // The main purpose of code is to disable soft input (virtual keyboard) but leave all the TextEdit functionality, like cursor, scrolling, copy/paste menu etc
-
- if ( Build.VERSION.SDK_INT >= 11 ) {
- // fix for missing cursor in android 3 and higher
- try {
- // IDEA: return false always except if method was called from TextView.isCursorVisible() method
- for (StackTraceElement stackTraceElement : CollectionsUtils.asList(Thread.currentThread().getStackTrace())) {
- if ( "isCursorVisible".equals(stackTraceElement.getMethodName()) ) {
- return true;
- }
- }
- } catch (RuntimeException e) {
- // just in case...
- }
-
- return false;
- } else {
- return false;
- }
- }
-
- public CalculatorEditor(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init();
- }
-
- @Override
- protected void onCreateContextMenu(ContextMenu menu) {
- super.onCreateContextMenu(menu);
-
- menu.removeItem(android.R.id.selectAll);
- }
-
- @Override
- public void setText(CharSequence text, BufferType type) {
- super.setText(text, type);
- }
-
- public synchronized void redraw() {
- String text = getText().toString();
-
- int selectionStart = getSelectionStart();
- int selectionEnd = getSelectionEnd();
-
- if (highlightText) {
-
- Log.d(this.getClass().getName(), text);
-
- try {
- final TextHighlighter.Result result = textHighlighter.process(text);
- selectionStart += result.getOffset();
- selectionEnd += result.getOffset();
- text = result.toString();
- } catch (CalculatorParseException e) {
- Log.e(this.getClass().getName(), e.getMessage(), e);
- }
-
- Log.d(this.getClass().getName(), text);
- super.setText(Html.fromHtml(text), BufferType.EDITABLE);
- } else {
- super.setText(text, BufferType.EDITABLE);
- }
-
- Log.d(this.getClass().getName(), getText().toString());
-
- int length = getText().length();
- setSelection(Math.max(Math.min(length, selectionStart), 0), Math.max(Math.min(length, selectionEnd), 0));
- }
-
- public boolean isHighlightText() {
- return highlightText;
- }
-
- public void setHighlightText(boolean highlightText) {
- this.highlightText = highlightText;
- redraw();
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
- if (CALC_COLOR_DISPLAY_KEY.equals(key)) {
- this.setHighlightText(preferences.getBoolean(CALC_COLOR_DISPLAY_KEY, CALC_COLOR_DISPLAY_DEFAULT));
- }
- }
-
- public void init(@NotNull SharedPreferences preferences) {
- onSharedPreferenceChanged(preferences, CALC_COLOR_DISPLAY_KEY);
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ */
+
+package org.solovyev.android.calculator;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.os.Build;
+import android.text.Html;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.widget.EditText;
+import org.jetbrains.annotations.NotNull;
+import org.solovyev.android.calculator.model.CalculatorEngine;
+import org.solovyev.android.calculator.text.TextProcessor;
+import org.solovyev.android.calculator.view.TextHighlighter;
+import org.solovyev.common.collections.CollectionsUtils;
+
+/**
+ * User: serso
+ * Date: 9/17/11
+ * Time: 12:25 AM
+ */
+public class CalculatorEditor extends EditText implements SharedPreferences.OnSharedPreferenceChangeListener {
+
+ private static final String CALC_COLOR_DISPLAY_KEY = "org.solovyev.android.calculator.CalculatorModel_color_display";
+ private static final boolean CALC_COLOR_DISPLAY_DEFAULT = true;
+
+ private boolean highlightText = true;
+
+ @NotNull
+ private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, true, CalculatorEngine.instance.getEngine());
+
+ public CalculatorEditor(Context context) {
+ super(context);
+ init();
+ }
+
+ public CalculatorEditor(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ // NOTE: in this solution cursor is missing
+
+ /*this.setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ final TextView textView = (TextView)v;
+ // backup the input type
+ int inputType = textView.getInputType();
+
+ // disable soft input
+ textView.setInputType(InputType.TYPE_NULL);
+
+ // call native handler
+ textView.onTouchEvent(event);
+
+ // restore input type
+ textView.setInputType(inputType);
+
+ // consume touch even
+ return true;
+ }
+ });*/
+ }
+
+
+ @Override
+ public boolean onCheckIsTextEditor() {
+ // NOTE: code below can be used carefully and should not be copied without special intention
+ // The main purpose of code is to disable soft input (virtual keyboard) but leave all the TextEdit functionality, like cursor, scrolling, copy/paste menu etc
+
+ if ( Build.VERSION.SDK_INT >= 11 ) {
+ // fix for missing cursor in android 3 and higher
+ try {
+ // IDEA: return false always except if method was called from TextView.isCursorVisible() method
+ for (StackTraceElement stackTraceElement : CollectionsUtils.asList(Thread.currentThread().getStackTrace())) {
+ if ( "isCursorVisible".equals(stackTraceElement.getMethodName()) ) {
+ return true;
+ }
+ }
+ } catch (RuntimeException e) {
+ // just in case...
+ }
+
+ return false;
+ } else {
+ return false;
+ }
+ }
+
+ public CalculatorEditor(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ @Override
+ protected void onCreateContextMenu(ContextMenu menu) {
+ super.onCreateContextMenu(menu);
+
+ menu.removeItem(android.R.id.selectAll);
+ }
+
+ @Override
+ public void setText(CharSequence text, BufferType type) {
+ super.setText(text, type);
+ }
+
+ public synchronized void redraw() {
+ String text = getText().toString();
+
+ int selectionStart = getSelectionStart();
+ int selectionEnd = getSelectionEnd();
+
+ if (highlightText) {
+
+ Log.d(this.getClass().getName(), text);
+
+ try {
+ final TextHighlighter.Result result = textHighlighter.process(text);
+ selectionStart += result.getOffset();
+ selectionEnd += result.getOffset();
+ text = result.toString();
+ } catch (CalculatorParseException e) {
+ Log.e(this.getClass().getName(), e.getMessage(), e);
+ }
+
+ Log.d(this.getClass().getName(), text);
+ super.setText(Html.fromHtml(text), BufferType.EDITABLE);
+ } else {
+ super.setText(text, BufferType.EDITABLE);
+ }
+
+ Log.d(this.getClass().getName(), getText().toString());
+
+ int length = getText().length();
+ setSelection(Math.max(Math.min(length, selectionStart), 0), Math.max(Math.min(length, selectionEnd), 0));
+ }
+
+ public boolean isHighlightText() {
+ return highlightText;
+ }
+
+ public void setHighlightText(boolean highlightText) {
+ this.highlightText = highlightText;
+ redraw();
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
+ if (CALC_COLOR_DISPLAY_KEY.equals(key)) {
+ this.setHighlightText(preferences.getBoolean(CALC_COLOR_DISPLAY_KEY, CALC_COLOR_DISPLAY_DEFAULT));
+ }
+ }
+
+ public void init(@NotNull SharedPreferences preferences) {
+ onSharedPreferenceChanged(preferences, CALC_COLOR_DISPLAY_KEY);
+ }
+}
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorModel.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorModel.java
index bc78f737..6d544a8f 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorModel.java
+++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorModel.java
@@ -1,411 +1,410 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- */
-
-package org.solovyev.android.calculator;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-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 org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.solovyev.android.CursorControl;
-import org.solovyev.android.calculator.history.CalculatorHistory;
-import org.solovyev.android.calculator.history.CalculatorHistoryState;
-import org.solovyev.android.calculator.history.TextViewEditorAdapter;
-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.CalculatorEvalException;
-import org.solovyev.android.calculator.model.CalculatorParseException;
-import org.solovyev.android.history.HistoryControl;
-import org.solovyev.android.menu.AMenuBuilder;
-import org.solovyev.android.menu.MenuImpl;
-import org.solovyev.common.MutableObject;
-import org.solovyev.common.history.HistoryAction;
-import org.solovyev.common.msg.Message;
-import org.solovyev.common.text.StringUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * User: serso
- * Date: 9/12/11
- * Time: 11:15 PM
- */
-public enum CalculatorModel implements CursorControl, HistoryControl, CalculatorEngineControl {
-
- instance;
-
- // millis to wait before evaluation after user edit action
- public static final int EVAL_DELAY_MILLIS = 0;
-
- @NotNull
- private CalculatorEditor editor;
-
- @NotNull
- private CalculatorDisplay display;
-
- @NotNull
- private CalculatorEngine calculatorEngine;
-
- public CalculatorModel init(@NotNull final Activity activity, @NotNull SharedPreferences preferences, @NotNull CalculatorEngine calculator) {
- Log.d(this.getClass().getName(), "CalculatorModel initialization with activity: " + activity);
- this.calculatorEngine = calculator;
-
- this.editor = (CalculatorEditor) activity.findViewById(R.id.calculatorEditor);
- this.editor.init(preferences);
- preferences.registerOnSharedPreferenceChangeListener(editor);
-
- this.display = (CalculatorDisplay) activity.findViewById(R.id.calculatorDisplay);
- this.display.setOnClickListener(new CalculatorDisplayOnClickListener(activity));
-
- final CalculatorHistoryState lastState = CalculatorHistory.instance.getLastHistoryState();
- if (lastState == null) {
- saveHistoryState();
- } else {
- setCurrentHistoryState(lastState);
- }
-
-
- return this;
- }
-
- private static void showEvaluationError(@NotNull Activity activity, @NotNull final String errorMessage) {
- final LayoutInflater layoutInflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
-
- final View errorMessageView = layoutInflater.inflate(R.layout.display_error_message, null);
- ((TextView) errorMessageView.findViewById(R.id.error_message_text_view)).setText(errorMessage);
-
- final AlertDialog.Builder builder = new AlertDialog.Builder(activity)
- .setPositiveButton(R.string.c_cancel, null)
- .setView(errorMessageView);
-
- builder.create().show();
- }
-
- public void copyResult(@NotNull Context context) {
- copyResult(context, display);
- }
-
- public static void copyResult(@NotNull Context context, @NotNull final CalculatorDisplay display) {
- if (display.isValid()) {
- final CharSequence text = display.getText();
- if (!StringUtils.isEmpty(text)) {
- final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
- clipboard.setText(text.toString());
- Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show();
- }
- }
- }
-
- private void saveHistoryState() {
- CalculatorHistory.instance.addState(getCurrentHistoryState());
- }
-
- public void setCursorOnStart() {
- editor.setSelection(0);
- }
-
- public void setCursorOnEnd() {
- editor.setSelection(editor.getText().length());
- }
-
- public void moveCursorLeft() {
- if (editor.getSelectionStart() > 0) {
- editor.setSelection(editor.getSelectionStart() - 1);
- }
- }
-
- public void moveCursorRight() {
- if (editor.getSelectionStart() < editor.getText().length()) {
- editor.setSelection(editor.getSelectionStart() + 1);
- }
- }
-
- public void doTextOperation(@NotNull TextOperation operation) {
- doTextOperation(operation, true);
- }
-
- public void doTextOperation(@NotNull TextOperation operation, boolean delayEvaluate) {
- doTextOperation(operation, delayEvaluate, JsclOperation.numeric, false);
- }
-
- public void doTextOperation(@NotNull TextOperation operation, boolean delayEvaluate, @NotNull JsclOperation jsclOperation, boolean forceEval) {
- final String editorStateBefore = this.editor.getText().toString();
-
- Log.d(CalculatorModel.class.getName(), "Editor state changed before '" + editorStateBefore + "'");
- operation.doOperation(this.editor);
- //Log.d(CalculatorModel.class.getName(), "Doing text operation" + StringUtils.fromStackTrace(Thread.currentThread().getStackTrace()));
-
- final String editorStateAfter = this.editor.getText().toString();
- if (forceEval ||!editorStateBefore.equals(editorStateAfter)) {
-
- editor.redraw();
-
- evaluate(delayEvaluate, editorStateAfter, jsclOperation, null);
- }
- }
-
- @NotNull
- private final static MutableObject pendingOperation = new MutableObject();
-
- private void evaluate(boolean delayEvaluate,
- @NotNull final String expression,
- @NotNull final JsclOperation operation,
- @Nullable CalculatorHistoryState historyState) {
-
- final CalculatorHistoryState localHistoryState;
- if (historyState == null) {
- //this.display.setText("");
- localHistoryState = getCurrentHistoryState();
- } else {
- this.display.setText(historyState.getDisplayState().getEditorState().getText());
- localHistoryState = historyState;
- }
-
- pendingOperation.setObject(new Runnable() {
- @Override
- public void run() {
- // allow only one runner at one time
- synchronized (pendingOperation) {
- //lock all operations with history
- if (pendingOperation.getObject() == this) {
- // actually nothing shall be logged while text operations are done
- evaluate(expression, operation, this);
-
- if (pendingOperation.getObject() == this) {
- // todo serso: of course there is small probability that someone will set pendingOperation after if statement but before .setObject(null)
- pendingOperation.setObject(null);
- localHistoryState.setDisplayState(getCurrentHistoryState().getDisplayState());
- }
- }
- }
- }
- });
-
- if (delayEvaluate) {
- if (historyState == null) {
- CalculatorHistory.instance.addState(localHistoryState);
- }
- // todo serso: this is not correct - operation is processing still in the same thread
- new Handler().postDelayed(pendingOperation.getObject(), EVAL_DELAY_MILLIS);
- } else {
- pendingOperation.getObject().run();
- if (historyState == null) {
- CalculatorHistory.instance.addState(localHistoryState);
- }
- }
- }
-
- @Override
- public void evaluate() {
- evaluate(false, this.editor.getText().toString(), JsclOperation.numeric, null);
- }
-
- public void evaluate(@NotNull JsclOperation operation) {
- evaluate(false, this.editor.getText().toString(), operation, null);
- }
-
- @Override
- public void simplify() {
- evaluate(false, this.editor.getText().toString(), JsclOperation.simplify, null);
- }
-
- private void evaluate(@Nullable final String expression,
- @NotNull JsclOperation operation,
- @NotNull Runnable currentRunner) {
-
- if (!StringUtils.isEmpty(expression)) {
- try {
- Log.d(CalculatorModel.class.getName(), "Trying to evaluate '" + operation + "': " + expression /*+ StringUtils.fromStackTrace(Thread.currentThread().getStackTrace())*/);
- final CalculatorEngine.Result result = calculatorEngine.evaluate(operation, expression);
-
- // todo serso: second condition might replaced with expression.equals(this.editor.getText().toString()) ONLY if expression will be formatted with text highlighter
- if (currentRunner == pendingOperation.getObject() && this.editor.getText().length() > 0) {
- display.setText(result.getResult());
- } else {
- display.setText("");
- }
- display.setJsclOperation(result.getUserOperation());
- display.setGenericResult(result.getGenericResult());
- } catch (CalculatorParseException e) {
- handleEvaluationException(expression, display, operation, e);
- } catch (CalculatorEvalException e) {
- handleEvaluationException(expression, display, operation, e);
- }
- } else {
- this.display.setText("");
- this.display.setJsclOperation(operation);
- this.display.setGenericResult(null);
- }
-
-
-
- this.display.redraw();
- }
-
- private void handleEvaluationException(@NotNull String expression,
- @NotNull CalculatorDisplay localDisplay,
- @NotNull JsclOperation operation,
- @NotNull Message e) {
- Log.d(CalculatorModel.class.getName(), "Evaluation failed for : " + expression + ". Error message: " + e);
- if ( StringUtils.isEmpty(localDisplay.getText()) ) {
- // if previous display state was empty -> show error
- localDisplay.setText(R.string.c_syntax_error);
- } else {
- // show previous result instead of error caption (actually previous result will be greyed)
- }
- localDisplay.setJsclOperation(operation);
- localDisplay.setGenericResult(null);
- localDisplay.setValid(false);
- localDisplay.setErrorMessage(e.getLocalizedMessage());
- }
-
- public void clear() {
- if (!StringUtils.isEmpty(editor.getText()) || !StringUtils.isEmpty(display.getText())) {
- editor.getText().clear();
- display.setText("");
- saveHistoryState();
- }
- }
-
- public void processDigitButtonAction(@Nullable final String text) {
- processDigitButtonAction(text, true);
- }
-
- public void processDigitButtonAction(@Nullable final String text, boolean delayEvaluate) {
-
- if (!StringUtils.isEmpty(text)) {
- doTextOperation(new CalculatorModel.TextOperation() {
-
- @Override
- public void doOperation(@NotNull EditText editor) {
- int cursorPositionOffset = 0;
- final StringBuilder textToBeInserted = new StringBuilder(text);
-
- final MathType.Result mathType = MathType.getType(text, 0, false);
- switch (mathType.getMathType()) {
- case function:
- textToBeInserted.append("()");
- cursorPositionOffset = -1;
- break;
- case operator:
- textToBeInserted.append("()");
- cursorPositionOffset = -1;
- break;
- case comma:
- textToBeInserted.append(" ");
- break;
- }
-
- if (cursorPositionOffset == 0) {
- if (MathType.openGroupSymbols.contains(text)) {
- cursorPositionOffset = -1;
- }
- }
-
- editor.getText().insert(editor.getSelectionStart(), textToBeInserted.toString());
- editor.setSelection(editor.getSelectionStart() + cursorPositionOffset, editor.getSelectionEnd() + cursorPositionOffset);
- }
- }, delayEvaluate);
- }
- }
-
- public static interface TextOperation {
-
- void doOperation(@NotNull EditText editor);
-
- }
-
- @Override
- public void doHistoryAction(@NotNull HistoryAction historyAction) {
- synchronized (CalculatorHistory.instance) {
- if (CalculatorHistory.instance.isActionAvailable(historyAction)) {
- final CalculatorHistoryState newState = CalculatorHistory.instance.doAction(historyAction, getCurrentHistoryState());
- if (newState != null) {
- setCurrentHistoryState(newState);
- }
- }
- }
- }
-
- @Override
- public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
- synchronized (CalculatorHistory.instance) {
- Log.d(this.getClass().getName(), "Saved history found: " + editorHistoryState);
-
- editorHistoryState.setValuesFromHistory(new TextViewEditorAdapter(this.editor), this.display);
-
- final String expression = this.editor.getText().toString();
- if ( !StringUtils.isEmpty(expression) ) {
- if ( StringUtils.isEmpty(this.display.getText().toString()) ) {
- evaluate(false, expression, this.display.getJsclOperation(), editorHistoryState);
- }
- }
-
- editor.redraw();
- display.redraw();
- }
- }
-
- @Override
- @NotNull
- public CalculatorHistoryState getCurrentHistoryState() {
- synchronized (CalculatorHistory.instance) {
- return CalculatorHistoryState.newInstance(new TextViewEditorAdapter(this.editor), this.display);
- }
- }
-
- @NotNull
- public CalculatorDisplay getDisplay() {
- return display;
- }
-
- private static class CalculatorDisplayOnClickListener implements View.OnClickListener {
-
- @NotNull
- private final Activity activity;
-
- public CalculatorDisplayOnClickListener(@NotNull Activity activity) {
- this.activity = activity;
- }
-
- @Override
- public void onClick(View v) {
- if (v instanceof CalculatorDisplay) {
- final CalculatorDisplay cd = (CalculatorDisplay) v;
-
- if (cd.isValid()) {
- final List filteredMenuItems = new ArrayList(CalculatorDisplay.MenuItem.values().length);
- for (CalculatorDisplay.MenuItem menuItem : CalculatorDisplay.MenuItem.values()) {
- if (menuItem.isItemVisible(cd)) {
- filteredMenuItems.add(menuItem);
- }
- }
-
- if (!filteredMenuItems.isEmpty()) {
- AMenuBuilder.newInstance(activity, MenuImpl.newInstance(filteredMenuItems)).create(cd).show();
- }
-
- } else {
- final String errorMessage = cd.getErrorMessage();
- if (errorMessage != null) {
- showEvaluationError(activity, errorMessage);
- }
- }
- }
- }
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ */
+
+package org.solovyev.android.calculator;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+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 org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.solovyev.android.CursorControl;
+import org.solovyev.android.calculator.history.CalculatorHistory;
+import org.solovyev.android.calculator.history.CalculatorHistoryState;
+import org.solovyev.android.calculator.history.TextViewEditorAdapter;
+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.CalculatorEvalException;
+import org.solovyev.android.history.HistoryControl;
+import org.solovyev.android.menu.AMenuBuilder;
+import org.solovyev.android.menu.MenuImpl;
+import org.solovyev.common.MutableObject;
+import org.solovyev.common.history.HistoryAction;
+import org.solovyev.common.msg.Message;
+import org.solovyev.common.text.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: serso
+ * Date: 9/12/11
+ * Time: 11:15 PM
+ */
+public enum CalculatorModel implements CursorControl, HistoryControl, CalculatorEngineControl {
+
+ instance;
+
+ // millis to wait before evaluation after user edit action
+ public static final int EVAL_DELAY_MILLIS = 0;
+
+ @NotNull
+ private CalculatorEditor editor;
+
+ @NotNull
+ private CalculatorDisplay display;
+
+ @NotNull
+ private CalculatorEngine calculatorEngine;
+
+ public CalculatorModel init(@NotNull final Activity activity, @NotNull SharedPreferences preferences, @NotNull CalculatorEngine calculator) {
+ Log.d(this.getClass().getName(), "CalculatorModel initialization with activity: " + activity);
+ this.calculatorEngine = calculator;
+
+ this.editor = (CalculatorEditor) activity.findViewById(R.id.calculatorEditor);
+ this.editor.init(preferences);
+ preferences.registerOnSharedPreferenceChangeListener(editor);
+
+ this.display = (CalculatorDisplay) activity.findViewById(R.id.calculatorDisplay);
+ this.display.setOnClickListener(new CalculatorDisplayOnClickListener(activity));
+
+ final CalculatorHistoryState lastState = CalculatorHistory.instance.getLastHistoryState();
+ if (lastState == null) {
+ saveHistoryState();
+ } else {
+ setCurrentHistoryState(lastState);
+ }
+
+
+ return this;
+ }
+
+ private static void showEvaluationError(@NotNull Activity activity, @NotNull final String errorMessage) {
+ final LayoutInflater layoutInflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
+
+ final View errorMessageView = layoutInflater.inflate(R.layout.display_error_message, null);
+ ((TextView) errorMessageView.findViewById(R.id.error_message_text_view)).setText(errorMessage);
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(activity)
+ .setPositiveButton(R.string.c_cancel, null)
+ .setView(errorMessageView);
+
+ builder.create().show();
+ }
+
+ public void copyResult(@NotNull Context context) {
+ copyResult(context, display);
+ }
+
+ public static void copyResult(@NotNull Context context, @NotNull final CalculatorDisplay display) {
+ if (display.isValid()) {
+ final CharSequence text = display.getText();
+ if (!StringUtils.isEmpty(text)) {
+ final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
+ clipboard.setText(text.toString());
+ Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ private void saveHistoryState() {
+ CalculatorHistory.instance.addState(getCurrentHistoryState());
+ }
+
+ public void setCursorOnStart() {
+ editor.setSelection(0);
+ }
+
+ public void setCursorOnEnd() {
+ editor.setSelection(editor.getText().length());
+ }
+
+ public void moveCursorLeft() {
+ if (editor.getSelectionStart() > 0) {
+ editor.setSelection(editor.getSelectionStart() - 1);
+ }
+ }
+
+ public void moveCursorRight() {
+ if (editor.getSelectionStart() < editor.getText().length()) {
+ editor.setSelection(editor.getSelectionStart() + 1);
+ }
+ }
+
+ public void doTextOperation(@NotNull TextOperation operation) {
+ doTextOperation(operation, true);
+ }
+
+ public void doTextOperation(@NotNull TextOperation operation, boolean delayEvaluate) {
+ doTextOperation(operation, delayEvaluate, JsclOperation.numeric, false);
+ }
+
+ public void doTextOperation(@NotNull TextOperation operation, boolean delayEvaluate, @NotNull JsclOperation jsclOperation, boolean forceEval) {
+ final String editorStateBefore = this.editor.getText().toString();
+
+ Log.d(CalculatorModel.class.getName(), "Editor state changed before '" + editorStateBefore + "'");
+ operation.doOperation(this.editor);
+ //Log.d(CalculatorModel.class.getName(), "Doing text operation" + StringUtils.fromStackTrace(Thread.currentThread().getStackTrace()));
+
+ final String editorStateAfter = this.editor.getText().toString();
+ if (forceEval ||!editorStateBefore.equals(editorStateAfter)) {
+
+ editor.redraw();
+
+ evaluate(delayEvaluate, editorStateAfter, jsclOperation, null);
+ }
+ }
+
+ @NotNull
+ private final static MutableObject pendingOperation = new MutableObject();
+
+ private void evaluate(boolean delayEvaluate,
+ @NotNull final String expression,
+ @NotNull final JsclOperation operation,
+ @Nullable CalculatorHistoryState historyState) {
+
+ final CalculatorHistoryState localHistoryState;
+ if (historyState == null) {
+ //this.display.setText("");
+ localHistoryState = getCurrentHistoryState();
+ } else {
+ this.display.setText(historyState.getDisplayState().getEditorState().getText());
+ localHistoryState = historyState;
+ }
+
+ pendingOperation.setObject(new Runnable() {
+ @Override
+ public void run() {
+ // allow only one runner at one time
+ synchronized (pendingOperation) {
+ //lock all operations with history
+ if (pendingOperation.getObject() == this) {
+ // actually nothing shall be logged while text operations are done
+ evaluate(expression, operation, this);
+
+ if (pendingOperation.getObject() == this) {
+ // todo serso: of course there is small probability that someone will set pendingOperation after if statement but before .setObject(null)
+ pendingOperation.setObject(null);
+ localHistoryState.setDisplayState(getCurrentHistoryState().getDisplayState());
+ }
+ }
+ }
+ }
+ });
+
+ if (delayEvaluate) {
+ if (historyState == null) {
+ CalculatorHistory.instance.addState(localHistoryState);
+ }
+ // todo serso: this is not correct - operation is processing still in the same thread
+ new Handler().postDelayed(pendingOperation.getObject(), EVAL_DELAY_MILLIS);
+ } else {
+ pendingOperation.getObject().run();
+ if (historyState == null) {
+ CalculatorHistory.instance.addState(localHistoryState);
+ }
+ }
+ }
+
+ @Override
+ public void evaluate() {
+ evaluate(false, this.editor.getText().toString(), JsclOperation.numeric, null);
+ }
+
+ public void evaluate(@NotNull JsclOperation operation) {
+ evaluate(false, this.editor.getText().toString(), operation, null);
+ }
+
+ @Override
+ public void simplify() {
+ evaluate(false, this.editor.getText().toString(), JsclOperation.simplify, null);
+ }
+
+ private void evaluate(@Nullable final String expression,
+ @NotNull JsclOperation operation,
+ @NotNull Runnable currentRunner) {
+
+ if (!StringUtils.isEmpty(expression)) {
+ try {
+ Log.d(CalculatorModel.class.getName(), "Trying to evaluate '" + operation + "': " + expression /*+ StringUtils.fromStackTrace(Thread.currentThread().getStackTrace())*/);
+ final CalculatorEngine.Result result = calculatorEngine.evaluate(operation, expression);
+
+ // todo serso: second condition might replaced with expression.equals(this.editor.getText().toString()) ONLY if expression will be formatted with text highlighter
+ if (currentRunner == pendingOperation.getObject() && this.editor.getText().length() > 0) {
+ display.setText(result.getResult());
+ } else {
+ display.setText("");
+ }
+ display.setJsclOperation(result.getUserOperation());
+ display.setGenericResult(result.getGenericResult());
+ } catch (CalculatorParseException e) {
+ handleEvaluationException(expression, display, operation, e);
+ } catch (CalculatorEvalException e) {
+ handleEvaluationException(expression, display, operation, e);
+ }
+ } else {
+ this.display.setText("");
+ this.display.setJsclOperation(operation);
+ this.display.setGenericResult(null);
+ }
+
+
+
+ this.display.redraw();
+ }
+
+ private void handleEvaluationException(@NotNull String expression,
+ @NotNull CalculatorDisplay localDisplay,
+ @NotNull JsclOperation operation,
+ @NotNull Message e) {
+ Log.d(CalculatorModel.class.getName(), "Evaluation failed for : " + expression + ". Error message: " + e);
+ if ( StringUtils.isEmpty(localDisplay.getText()) ) {
+ // if previous display state was empty -> show error
+ localDisplay.setText(R.string.c_syntax_error);
+ } else {
+ // show previous result instead of error caption (actually previous result will be greyed)
+ }
+ localDisplay.setJsclOperation(operation);
+ localDisplay.setGenericResult(null);
+ localDisplay.setValid(false);
+ localDisplay.setErrorMessage(e.getLocalizedMessage());
+ }
+
+ public void clear() {
+ if (!StringUtils.isEmpty(editor.getText()) || !StringUtils.isEmpty(display.getText())) {
+ editor.getText().clear();
+ display.setText("");
+ saveHistoryState();
+ }
+ }
+
+ public void processDigitButtonAction(@Nullable final String text) {
+ processDigitButtonAction(text, true);
+ }
+
+ public void processDigitButtonAction(@Nullable final String text, boolean delayEvaluate) {
+
+ if (!StringUtils.isEmpty(text)) {
+ doTextOperation(new CalculatorModel.TextOperation() {
+
+ @Override
+ public void doOperation(@NotNull EditText editor) {
+ int cursorPositionOffset = 0;
+ final StringBuilder textToBeInserted = new StringBuilder(text);
+
+ final MathType.Result mathType = MathType.getType(text, 0, false);
+ switch (mathType.getMathType()) {
+ case function:
+ textToBeInserted.append("()");
+ cursorPositionOffset = -1;
+ break;
+ case operator:
+ textToBeInserted.append("()");
+ cursorPositionOffset = -1;
+ break;
+ case comma:
+ textToBeInserted.append(" ");
+ break;
+ }
+
+ if (cursorPositionOffset == 0) {
+ if (MathType.openGroupSymbols.contains(text)) {
+ cursorPositionOffset = -1;
+ }
+ }
+
+ editor.getText().insert(editor.getSelectionStart(), textToBeInserted.toString());
+ editor.setSelection(editor.getSelectionStart() + cursorPositionOffset, editor.getSelectionEnd() + cursorPositionOffset);
+ }
+ }, delayEvaluate);
+ }
+ }
+
+ public static interface TextOperation {
+
+ void doOperation(@NotNull EditText editor);
+
+ }
+
+ @Override
+ public void doHistoryAction(@NotNull HistoryAction historyAction) {
+ synchronized (CalculatorHistory.instance) {
+ if (CalculatorHistory.instance.isActionAvailable(historyAction)) {
+ final CalculatorHistoryState newState = CalculatorHistory.instance.doAction(historyAction, getCurrentHistoryState());
+ if (newState != null) {
+ setCurrentHistoryState(newState);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
+ synchronized (CalculatorHistory.instance) {
+ Log.d(this.getClass().getName(), "Saved history found: " + editorHistoryState);
+
+ editorHistoryState.setValuesFromHistory(new TextViewEditorAdapter(this.editor), this.display);
+
+ final String expression = this.editor.getText().toString();
+ if ( !StringUtils.isEmpty(expression) ) {
+ if ( StringUtils.isEmpty(this.display.getText().toString()) ) {
+ evaluate(false, expression, this.display.getJsclOperation(), editorHistoryState);
+ }
+ }
+
+ editor.redraw();
+ display.redraw();
+ }
+ }
+
+ @Override
+ @NotNull
+ public CalculatorHistoryState getCurrentHistoryState() {
+ synchronized (CalculatorHistory.instance) {
+ return CalculatorHistoryState.newInstance(new TextViewEditorAdapter(this.editor), this.display);
+ }
+ }
+
+ @NotNull
+ public CalculatorDisplay getDisplay() {
+ return display;
+ }
+
+ private static class CalculatorDisplayOnClickListener implements View.OnClickListener {
+
+ @NotNull
+ private final Activity activity;
+
+ public CalculatorDisplayOnClickListener(@NotNull Activity activity) {
+ this.activity = activity;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v instanceof CalculatorDisplay) {
+ final CalculatorDisplay cd = (CalculatorDisplay) v;
+
+ if (cd.isValid()) {
+ final List filteredMenuItems = new ArrayList(CalculatorDisplay.MenuItem.values().length);
+ for (CalculatorDisplay.MenuItem menuItem : CalculatorDisplay.MenuItem.values()) {
+ if (menuItem.isItemVisible(cd)) {
+ filteredMenuItems.add(menuItem);
+ }
+ }
+
+ if (!filteredMenuItems.isEmpty()) {
+ AMenuBuilder.newInstance(activity, MenuImpl.newInstance(filteredMenuItems)).create(cd).show();
+ }
+
+ } else {
+ final String errorMessage = cd.getErrorMessage();
+ if (errorMessage != null) {
+ showEvaluationError(activity, errorMessage);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java
index 3448880e..fb385c9a 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java
+++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java
@@ -16,9 +16,11 @@ import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CalculatorApplication;
+import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.JCalculatorEngine;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.jscl.JsclOperation;
+import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.android.prefs.BooleanPreference;
import org.solovyev.android.prefs.Preference;
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java
index 12067da4..630ad312 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java
+++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java
@@ -9,7 +9,9 @@ package org.solovyev.android.calculator.model;
import jscl.math.function.IConstant;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.CalculatorApplication;
+import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.R;
+import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.StartsWithFinder;
import org.solovyev.android.calculator.math.MathType;
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotActivity.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotActivity.java
index 33411a3c..0e2040eb 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotActivity.java
+++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/plot/CalculatorPlotActivity.java
@@ -1,360 +1,360 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator.plot;
-
-import android.app.Activity;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.Toast;
-import jscl.math.Expression;
-import jscl.math.Generic;
-import jscl.math.function.Constant;
-import jscl.text.ParseException;
-import org.achartengine.ChartFactory;
-import org.achartengine.GraphicalView;
-import org.achartengine.chart.CubicLineChart;
-import org.achartengine.chart.PointStyle;
-import org.achartengine.chart.XYChart;
-import org.achartengine.model.XYMultipleSeriesDataset;
-import org.achartengine.model.XYSeries;
-import org.achartengine.renderer.BasicStroke;
-import org.achartengine.renderer.XYMultipleSeriesRenderer;
-import org.achartengine.renderer.XYSeriesRenderer;
-import org.achartengine.tools.PanListener;
-import org.achartengine.tools.ZoomEvent;
-import org.achartengine.tools.ZoomListener;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.solovyev.android.calculator.R;
-import org.solovyev.android.calculator.model.CalculatorParseException;
-import org.solovyev.android.calculator.model.PreparedExpression;
-import org.solovyev.android.calculator.model.ToJsclTextProcessor;
-import org.solovyev.common.MutableObject;
-
-import java.io.Serializable;
-
-/**
- * User: serso
- * Date: 12/1/11
- * Time: 12:40 AM
- */
-public class CalculatorPlotActivity extends Activity {
-
- private static final String TAG = CalculatorPlotActivity.class.getSimpleName();
-
- private static final int DEFAULT_NUMBER_OF_STEPS = 100;
-
- private static final int DEFAULT_MIN_NUMBER = -10;
-
- private static final int DEFAULT_MAX_NUMBER = 10;
-
- public static final String INPUT = "org.solovyev.android.calculator.CalculatorPlotActivity_input";
-
- public static final long EVAL_DELAY_MILLIS = 200;
-
- private XYChart chart;
-
- /**
- * The encapsulated graphical view.
- */
- private GraphicalView graphicalView;
-
- @NotNull
- private Generic expression;
-
- @NotNull
- private Constant variable;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Bundle extras = getIntent().getExtras();
-
- final Input input = (Input) extras.getSerializable(INPUT);
-
- try {
- final PreparedExpression preparedExpression = ToJsclTextProcessor.getInstance().process(input.getExpression());
- this.expression = Expression.valueOf(preparedExpression.getExpression());
- this.variable = new Constant(input.getVariableName());
-
- String title = extras.getString(ChartFactory.TITLE);
- if (title == null) {
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- } else if (title.length() > 0) {
- setTitle(title);
- }
-
- setContentView(R.layout.calc_plot_view);
-
- final Object lastNonConfigurationInstance = getLastNonConfigurationInstance();
- setGraphicalView(lastNonConfigurationInstance instanceof PlotBoundaries ? (PlotBoundaries)lastNonConfigurationInstance : null);
-
- } catch (ParseException e) {
- Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
- finish();
- } catch (ArithmeticException e) {
- Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
- finish();
- } catch (CalculatorParseException e) {
- Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
- finish();
- }
- }
-
- private void setGraphicalView(@Nullable PlotBoundaries plotBoundaries) {
- double minValue = plotBoundaries == null ? DEFAULT_MIN_NUMBER : plotBoundaries.xMin;
- double maxValue = plotBoundaries == null ? DEFAULT_MAX_NUMBER : plotBoundaries.xMax;
-
- final ViewGroup graphContainer = (ViewGroup) findViewById(R.id.plot_view_container);
-
- if (graphicalView != null) {
- graphContainer.removeView(graphicalView);
- }
-
- chart = prepareChart(minValue, maxValue, expression, variable);
-
- // reverting boundaries (as in prepareChart() we add some cached values )
- double minX = Double.MAX_VALUE;
- double minY = Double.MAX_VALUE;
-
- double maxX = Double.MIN_VALUE;
- double maxY = Double.MIN_VALUE;
-
- for (XYSeries series : chart.getDataset().getSeries()) {
- minX = Math.min(minX, series.getMinX());
- minY = Math.min(minY, series.getMinY());
- maxX = Math.max(maxX, series.getMaxX());
- maxY = Math.max(maxY, series.getMaxY());
- }
-
- Log.d(CalculatorPlotActivity.class.getName(), "min x: " + minX + ", min y: " + minY + ", max x: " + maxX + ", max y: " + maxY);
- Log.d(CalculatorPlotActivity.class.getName(), "Plot boundaries are " + plotBoundaries);
-
-
- if (plotBoundaries == null) {
- chart.getRenderer().setXAxisMin(Math.max(minX, minValue));
- chart.getRenderer().setYAxisMin(Math.max(minY, minValue));
- chart.getRenderer().setXAxisMax(Math.min(maxX, maxValue));
- chart.getRenderer().setYAxisMax(Math.min(maxY, maxValue));
- } else {
- chart.getRenderer().setXAxisMin(plotBoundaries.xMin);
- chart.getRenderer().setYAxisMin(plotBoundaries.yMin);
- chart.getRenderer().setXAxisMax(plotBoundaries.xMax);
- chart.getRenderer().setYAxisMax(plotBoundaries.yMax);
- }
-
- graphicalView = new GraphicalView(this, chart);
-
- graphicalView.addZoomListener(new ZoomListener() {
- @Override
- public void zoomApplied(ZoomEvent e) {
- updateDataSets(chart);
- }
-
- @Override
- public void zoomReset() {
- updateDataSets(chart);
- }
- }, true, true);
-
- graphicalView.addPanListener(new PanListener() {
- @Override
- public void panApplied() {
- Log.d(TAG, "org.achartengine.tools.PanListener.panApplied");
- updateDataSets(chart);
- }
-
- });
- graphContainer.addView(graphicalView);
-
- updateDataSets(chart, 50);
- }
-
-
- private void updateDataSets(@NotNull final XYChart chart) {
- updateDataSets(chart, EVAL_DELAY_MILLIS);
- }
-
- private void updateDataSets(@NotNull final XYChart chart, long millisToWait) {
- pendingOperation.setObject(new Runnable() {
- @Override
- public void run() {
- // allow only one runner at one time
- synchronized (pendingOperation) {
- //lock all operations with history
- if (pendingOperation.getObject() == this) {
-
- Log.d(TAG, "org.solovyev.android.calculator.plot.CalculatorPlotActivity.updateDataSets");
-
- final XYMultipleSeriesRenderer dr = chart.getRenderer();
-
- //Log.d(CalculatorPlotActivity.class.getName(), "x = [" + dr.getXAxisMin() + ", " + dr.getXAxisMax() + "], y = [" + dr.getYAxisMin() + ", " + dr.getYAxisMax() + "]");
-
- final MyXYSeries realSeries = (MyXYSeries)chart.getDataset().getSeriesAt(0);
-
- final MyXYSeries imagSeries;
- if (chart.getDataset().getSeriesCount() > 1) {
- imagSeries = (MyXYSeries)chart.getDataset().getSeriesAt(1);
- } else {
- imagSeries = new MyXYSeries(getImagFunctionName(CalculatorPlotActivity.this.variable), DEFAULT_NUMBER_OF_STEPS * 2);
- }
-
- try {
- if (PlotUtils.addXY(dr.getXAxisMin(), dr.getXAxisMax(), expression, variable, realSeries, imagSeries, true, DEFAULT_NUMBER_OF_STEPS)) {
- if (chart.getDataset().getSeriesCount() <= 1) {
- chart.getDataset().addSeries(imagSeries);
- chart.getRenderer().addSeriesRenderer(createImagRenderer());
- }
- }
- } catch (ArithmeticException e) {
- // todo serso: translate
- Toast.makeText(CalculatorPlotActivity.this, "Arithmetic error: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
- CalculatorPlotActivity.this.finish();
- }
-
- if (pendingOperation.getObject() == this) {
- graphicalView.repaint();
- }
- }
- }
- }
- });
-
-
- new Handler().postDelayed(pendingOperation.getObject(), millisToWait);
- }
-
- @NotNull
- private static String getImagFunctionName(@NotNull Constant variable) {
- return "g(" + variable.getName() +")" + " = " + "Im(ƒ(" + variable.getName() +"))";
- }
-
- @NotNull
- private static String getRealFunctionName(@NotNull Generic expression, @NotNull Constant variable) {
- return "ƒ(" + variable.getName() +")" + " = " + expression.toString();
- }
-
- @NotNull
- private final static MutableObject pendingOperation = new MutableObject();
-
- private static XYChart prepareChart(final double minValue, final double maxValue, @NotNull final Generic expression, @NotNull final Constant variable) {
- final MyXYSeries realSeries = new MyXYSeries(getRealFunctionName(expression, variable), DEFAULT_NUMBER_OF_STEPS * 2);
- final MyXYSeries imagSeries = new MyXYSeries(getImagFunctionName(variable), DEFAULT_NUMBER_OF_STEPS * 2);
-
- boolean imagExists = PlotUtils.addXY(minValue, maxValue, expression, variable, realSeries, imagSeries, false, DEFAULT_NUMBER_OF_STEPS);
-
- final XYMultipleSeriesDataset data = new XYMultipleSeriesDataset();
- data.addSeries(realSeries);
- if (imagExists) {
- data.addSeries(imagSeries);
- }
-
- final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
- renderer.setShowGrid(true);
- renderer.setXTitle(variable.getName());
- renderer.setYTitle("f(" + variable.getName() + ")");
- renderer.setChartTitleTextSize(20);
-
- renderer.setZoomEnabled(true);
- renderer.setZoomButtonsVisible(true);
-
- renderer.addSeriesRenderer(createCommonRenderer());
- if (imagExists) {
- renderer.addSeriesRenderer(createImagRenderer());
- }
-
- return new CubicLineChart(data, renderer, 0.1f);
- }
-
- private static XYSeriesRenderer createImagRenderer() {
- final XYSeriesRenderer imagRenderer = createCommonRenderer();
- imagRenderer.setStroke(BasicStroke.DASHED);
- imagRenderer.setColor(Color.LTGRAY);
- return imagRenderer;
- }
-
- @Override
- public Object onRetainNonConfigurationInstance() {
- return new PlotBoundaries(chart.getRenderer());
- }
-
- private static final class PlotBoundaries implements Serializable {
-
- private final double xMin;
- private final double xMax;
- private final double yMin;
- private final double yMax;
-
- public PlotBoundaries(@NotNull XYMultipleSeriesRenderer renderer) {
- this.xMin = renderer.getXAxisMin();
- this.yMin = renderer.getYAxisMin();
- this.xMax = renderer.getXAxisMax();
- this.yMax = renderer.getYAxisMax();
- }
-
- @Override
- public String toString() {
- return "PlotBoundaries{" +
- "yMax=" + yMax +
- ", yMin=" + yMin +
- ", xMax=" + xMax +
- ", xMin=" + xMin +
- '}';
- }
- }
-
-
- @NotNull
- private static XYSeriesRenderer createCommonRenderer() {
- final XYSeriesRenderer renderer = new XYSeriesRenderer();
- renderer.setFillPoints(true);
- renderer.setPointStyle(PointStyle.POINT);
- renderer.setLineWidth(3);
- renderer.setColor(Color.WHITE);
- renderer.setStroke(BasicStroke.SOLID);
- return renderer;
- }
-
- public void zoomInClickHandler(@NotNull View v) {
- this.graphicalView.zoomIn();
- }
-
- public void zoomOutClickHandler(@NotNull View v) {
- this.graphicalView.zoomOut();
- }
-
-
-
- public static class Input implements Serializable {
-
- @NotNull
- private String expression;
-
- @NotNull
- private String variableName;
-
- public Input(@NotNull String expression, @NotNull String variableName) {
- this.expression = expression;
- this.variableName = variableName;
- }
-
- @NotNull
- public String getExpression() {
- return expression;
- }
-
- @NotNull
- public String getVariableName() {
- return variableName;
- }
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator.plot;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.Toast;
+import jscl.math.Expression;
+import jscl.math.Generic;
+import jscl.math.function.Constant;
+import jscl.text.ParseException;
+import org.achartengine.ChartFactory;
+import org.achartengine.GraphicalView;
+import org.achartengine.chart.CubicLineChart;
+import org.achartengine.chart.PointStyle;
+import org.achartengine.chart.XYChart;
+import org.achartengine.model.XYMultipleSeriesDataset;
+import org.achartengine.model.XYSeries;
+import org.achartengine.renderer.BasicStroke;
+import org.achartengine.renderer.XYMultipleSeriesRenderer;
+import org.achartengine.renderer.XYSeriesRenderer;
+import org.achartengine.tools.PanListener;
+import org.achartengine.tools.ZoomEvent;
+import org.achartengine.tools.ZoomListener;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.solovyev.android.calculator.R;
+import org.solovyev.android.calculator.CalculatorParseException;
+import org.solovyev.android.calculator.model.PreparedExpression;
+import org.solovyev.android.calculator.model.ToJsclTextProcessor;
+import org.solovyev.common.MutableObject;
+
+import java.io.Serializable;
+
+/**
+ * User: serso
+ * Date: 12/1/11
+ * Time: 12:40 AM
+ */
+public class CalculatorPlotActivity extends Activity {
+
+ private static final String TAG = CalculatorPlotActivity.class.getSimpleName();
+
+ private static final int DEFAULT_NUMBER_OF_STEPS = 100;
+
+ private static final int DEFAULT_MIN_NUMBER = -10;
+
+ private static final int DEFAULT_MAX_NUMBER = 10;
+
+ public static final String INPUT = "org.solovyev.android.calculator.CalculatorPlotActivity_input";
+
+ public static final long EVAL_DELAY_MILLIS = 200;
+
+ private XYChart chart;
+
+ /**
+ * The encapsulated graphical view.
+ */
+ private GraphicalView graphicalView;
+
+ @NotNull
+ private Generic expression;
+
+ @NotNull
+ private Constant variable;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Bundle extras = getIntent().getExtras();
+
+ final Input input = (Input) extras.getSerializable(INPUT);
+
+ try {
+ final PreparedExpression preparedExpression = ToJsclTextProcessor.getInstance().process(input.getExpression());
+ this.expression = Expression.valueOf(preparedExpression.getExpression());
+ this.variable = new Constant(input.getVariableName());
+
+ String title = extras.getString(ChartFactory.TITLE);
+ if (title == null) {
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ } else if (title.length() > 0) {
+ setTitle(title);
+ }
+
+ setContentView(R.layout.calc_plot_view);
+
+ final Object lastNonConfigurationInstance = getLastNonConfigurationInstance();
+ setGraphicalView(lastNonConfigurationInstance instanceof PlotBoundaries ? (PlotBoundaries)lastNonConfigurationInstance : null);
+
+ } catch (ParseException e) {
+ Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
+ finish();
+ } catch (ArithmeticException e) {
+ Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
+ finish();
+ } catch (CalculatorParseException e) {
+ Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
+ finish();
+ }
+ }
+
+ private void setGraphicalView(@Nullable PlotBoundaries plotBoundaries) {
+ double minValue = plotBoundaries == null ? DEFAULT_MIN_NUMBER : plotBoundaries.xMin;
+ double maxValue = plotBoundaries == null ? DEFAULT_MAX_NUMBER : plotBoundaries.xMax;
+
+ final ViewGroup graphContainer = (ViewGroup) findViewById(R.id.plot_view_container);
+
+ if (graphicalView != null) {
+ graphContainer.removeView(graphicalView);
+ }
+
+ chart = prepareChart(minValue, maxValue, expression, variable);
+
+ // reverting boundaries (as in prepareChart() we add some cached values )
+ double minX = Double.MAX_VALUE;
+ double minY = Double.MAX_VALUE;
+
+ double maxX = Double.MIN_VALUE;
+ double maxY = Double.MIN_VALUE;
+
+ for (XYSeries series : chart.getDataset().getSeries()) {
+ minX = Math.min(minX, series.getMinX());
+ minY = Math.min(minY, series.getMinY());
+ maxX = Math.max(maxX, series.getMaxX());
+ maxY = Math.max(maxY, series.getMaxY());
+ }
+
+ Log.d(CalculatorPlotActivity.class.getName(), "min x: " + minX + ", min y: " + minY + ", max x: " + maxX + ", max y: " + maxY);
+ Log.d(CalculatorPlotActivity.class.getName(), "Plot boundaries are " + plotBoundaries);
+
+
+ if (plotBoundaries == null) {
+ chart.getRenderer().setXAxisMin(Math.max(minX, minValue));
+ chart.getRenderer().setYAxisMin(Math.max(minY, minValue));
+ chart.getRenderer().setXAxisMax(Math.min(maxX, maxValue));
+ chart.getRenderer().setYAxisMax(Math.min(maxY, maxValue));
+ } else {
+ chart.getRenderer().setXAxisMin(plotBoundaries.xMin);
+ chart.getRenderer().setYAxisMin(plotBoundaries.yMin);
+ chart.getRenderer().setXAxisMax(plotBoundaries.xMax);
+ chart.getRenderer().setYAxisMax(plotBoundaries.yMax);
+ }
+
+ graphicalView = new GraphicalView(this, chart);
+
+ graphicalView.addZoomListener(new ZoomListener() {
+ @Override
+ public void zoomApplied(ZoomEvent e) {
+ updateDataSets(chart);
+ }
+
+ @Override
+ public void zoomReset() {
+ updateDataSets(chart);
+ }
+ }, true, true);
+
+ graphicalView.addPanListener(new PanListener() {
+ @Override
+ public void panApplied() {
+ Log.d(TAG, "org.achartengine.tools.PanListener.panApplied");
+ updateDataSets(chart);
+ }
+
+ });
+ graphContainer.addView(graphicalView);
+
+ updateDataSets(chart, 50);
+ }
+
+
+ private void updateDataSets(@NotNull final XYChart chart) {
+ updateDataSets(chart, EVAL_DELAY_MILLIS);
+ }
+
+ private void updateDataSets(@NotNull final XYChart chart, long millisToWait) {
+ pendingOperation.setObject(new Runnable() {
+ @Override
+ public void run() {
+ // allow only one runner at one time
+ synchronized (pendingOperation) {
+ //lock all operations with history
+ if (pendingOperation.getObject() == this) {
+
+ Log.d(TAG, "org.solovyev.android.calculator.plot.CalculatorPlotActivity.updateDataSets");
+
+ final XYMultipleSeriesRenderer dr = chart.getRenderer();
+
+ //Log.d(CalculatorPlotActivity.class.getName(), "x = [" + dr.getXAxisMin() + ", " + dr.getXAxisMax() + "], y = [" + dr.getYAxisMin() + ", " + dr.getYAxisMax() + "]");
+
+ final MyXYSeries realSeries = (MyXYSeries)chart.getDataset().getSeriesAt(0);
+
+ final MyXYSeries imagSeries;
+ if (chart.getDataset().getSeriesCount() > 1) {
+ imagSeries = (MyXYSeries)chart.getDataset().getSeriesAt(1);
+ } else {
+ imagSeries = new MyXYSeries(getImagFunctionName(CalculatorPlotActivity.this.variable), DEFAULT_NUMBER_OF_STEPS * 2);
+ }
+
+ try {
+ if (PlotUtils.addXY(dr.getXAxisMin(), dr.getXAxisMax(), expression, variable, realSeries, imagSeries, true, DEFAULT_NUMBER_OF_STEPS)) {
+ if (chart.getDataset().getSeriesCount() <= 1) {
+ chart.getDataset().addSeries(imagSeries);
+ chart.getRenderer().addSeriesRenderer(createImagRenderer());
+ }
+ }
+ } catch (ArithmeticException e) {
+ // todo serso: translate
+ Toast.makeText(CalculatorPlotActivity.this, "Arithmetic error: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
+ CalculatorPlotActivity.this.finish();
+ }
+
+ if (pendingOperation.getObject() == this) {
+ graphicalView.repaint();
+ }
+ }
+ }
+ }
+ });
+
+
+ new Handler().postDelayed(pendingOperation.getObject(), millisToWait);
+ }
+
+ @NotNull
+ private static String getImagFunctionName(@NotNull Constant variable) {
+ return "g(" + variable.getName() +")" + " = " + "Im(ƒ(" + variable.getName() +"))";
+ }
+
+ @NotNull
+ private static String getRealFunctionName(@NotNull Generic expression, @NotNull Constant variable) {
+ return "ƒ(" + variable.getName() +")" + " = " + expression.toString();
+ }
+
+ @NotNull
+ private final static MutableObject pendingOperation = new MutableObject();
+
+ private static XYChart prepareChart(final double minValue, final double maxValue, @NotNull final Generic expression, @NotNull final Constant variable) {
+ final MyXYSeries realSeries = new MyXYSeries(getRealFunctionName(expression, variable), DEFAULT_NUMBER_OF_STEPS * 2);
+ final MyXYSeries imagSeries = new MyXYSeries(getImagFunctionName(variable), DEFAULT_NUMBER_OF_STEPS * 2);
+
+ boolean imagExists = PlotUtils.addXY(minValue, maxValue, expression, variable, realSeries, imagSeries, false, DEFAULT_NUMBER_OF_STEPS);
+
+ final XYMultipleSeriesDataset data = new XYMultipleSeriesDataset();
+ data.addSeries(realSeries);
+ if (imagExists) {
+ data.addSeries(imagSeries);
+ }
+
+ final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
+ renderer.setShowGrid(true);
+ renderer.setXTitle(variable.getName());
+ renderer.setYTitle("f(" + variable.getName() + ")");
+ renderer.setChartTitleTextSize(20);
+
+ renderer.setZoomEnabled(true);
+ renderer.setZoomButtonsVisible(true);
+
+ renderer.addSeriesRenderer(createCommonRenderer());
+ if (imagExists) {
+ renderer.addSeriesRenderer(createImagRenderer());
+ }
+
+ return new CubicLineChart(data, renderer, 0.1f);
+ }
+
+ private static XYSeriesRenderer createImagRenderer() {
+ final XYSeriesRenderer imagRenderer = createCommonRenderer();
+ imagRenderer.setStroke(BasicStroke.DASHED);
+ imagRenderer.setColor(Color.LTGRAY);
+ return imagRenderer;
+ }
+
+ @Override
+ public Object onRetainNonConfigurationInstance() {
+ return new PlotBoundaries(chart.getRenderer());
+ }
+
+ private static final class PlotBoundaries implements Serializable {
+
+ private final double xMin;
+ private final double xMax;
+ private final double yMin;
+ private final double yMax;
+
+ public PlotBoundaries(@NotNull XYMultipleSeriesRenderer renderer) {
+ this.xMin = renderer.getXAxisMin();
+ this.yMin = renderer.getYAxisMin();
+ this.xMax = renderer.getXAxisMax();
+ this.yMax = renderer.getYAxisMax();
+ }
+
+ @Override
+ public String toString() {
+ return "PlotBoundaries{" +
+ "yMax=" + yMax +
+ ", yMin=" + yMin +
+ ", xMax=" + xMax +
+ ", xMin=" + xMin +
+ '}';
+ }
+ }
+
+
+ @NotNull
+ private static XYSeriesRenderer createCommonRenderer() {
+ final XYSeriesRenderer renderer = new XYSeriesRenderer();
+ renderer.setFillPoints(true);
+ renderer.setPointStyle(PointStyle.POINT);
+ renderer.setLineWidth(3);
+ renderer.setColor(Color.WHITE);
+ renderer.setStroke(BasicStroke.SOLID);
+ return renderer;
+ }
+
+ public void zoomInClickHandler(@NotNull View v) {
+ this.graphicalView.zoomIn();
+ }
+
+ public void zoomOutClickHandler(@NotNull View v) {
+ this.graphicalView.zoomOut();
+ }
+
+
+
+ public static class Input implements Serializable {
+
+ @NotNull
+ private String expression;
+
+ @NotNull
+ private String variableName;
+
+ public Input(@NotNull String expression, @NotNull String variableName) {
+ this.expression = expression;
+ this.variableName = variableName;
+ }
+
+ @NotNull
+ public String getExpression() {
+ return expression;
+ }
+
+ @NotNull
+ public String getVariableName() {
+ return variableName;
+ }
+ }
+}
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/view/NumeralBaseConverterDialog.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/view/NumeralBaseConverterDialog.java
index a8fa7a46..4c94fe06 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/view/NumeralBaseConverterDialog.java
+++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/view/NumeralBaseConverterDialog.java
@@ -12,7 +12,7 @@ import org.solovyev.android.calculator.AndroidNumeralBase;
import org.solovyev.android.calculator.CalculatorModel;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.model.CalculatorEngine;
-import org.solovyev.android.calculator.model.CalculatorParseException;
+import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.model.ToJsclTextProcessor;
import org.solovyev.common.MutableObject;
import org.solovyev.common.text.StringUtils;
diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/view/TextHighlighter.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/view/TextHighlighter.java
index 0c658a97..2ebf22da 100644
--- a/calculatorpp/src/main/java/org/solovyev/android/calculator/view/TextHighlighter.java
+++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/view/TextHighlighter.java
@@ -1,238 +1,240 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator.view;
-
-import jscl.MathContext;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.solovyev.android.calculator.math.MathType;
-import org.solovyev.android.calculator.model.*;
-import org.solovyev.common.MutableObject;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * User: serso
- * Date: 10/12/11
- * Time: 9:47 PM
- */
-public class TextHighlighter implements TextProcessor {
-
- private static final Map nbFontAttributes = new HashMap();
-
- static {
- nbFontAttributes.put("color", "#008000");
- }
-
- @NotNull
- public final MathContext mathContext;
-
- public static class Result implements CharSequence {
-
- @NotNull
- private final String string;
-
- private final int offset;
-
- public Result(@NotNull String string, int offset) {
- this.string = string;
- this.offset = offset;
- }
-
- @Override
- public int length() {
- return string.length();
- }
-
- @Override
- public char charAt(int i) {
- return string.charAt(i);
- }
-
- @Override
- public CharSequence subSequence(int i, int i1) {
- return string.subSequence(i, i1);
- }
-
- @Override
- public String toString() {
- return string;
- }
-
- public int getOffset() {
- return offset;
- }
- }
-
- private final int color;
- private final int colorRed;
- private final int colorGreen;
- private final int colorBlue;
- private final boolean formatNumber;
-
- public TextHighlighter(int baseColor, boolean formatNumber, @NotNull MathContext mathContext) {
- this.color = baseColor;
- this.formatNumber = formatNumber;
- this.mathContext = mathContext;
- //this.colorRed = Color.red(baseColor);
- this.colorRed = (baseColor >> 16) & 0xFF;
- //this.colorGreen = Color.green(baseColor);
- this.colorGreen = (color >> 8) & 0xFF;
- //this.colorBlue = Color.blue(baseColor);
- this.colorBlue = color & 0xFF;
- }
-
- @NotNull
- @Override
- public Result process(@NotNull String text) throws CalculatorParseException {
- final String result;
-
- int maxNumberOfOpenGroupSymbols = 0;
- int numberOfOpenGroupSymbols = 0;
-
- final StringBuilder text1 = new StringBuilder();
-
- int resultOffset = 0;
-
- final AbstractNumberBuilder numberBuilder;
- if (!formatNumber) {
- numberBuilder = new LiteNumberBuilder(CalculatorEngine.instance.getEngine());
- } else {
- numberBuilder = new NumberBuilder(CalculatorEngine.instance.getEngine());
- }
- for (int i = 0; i < text.length(); i++) {
- MathType.Result mathType = MathType.getType(text, i, numberBuilder.isHexMode());
-
- if (numberBuilder instanceof NumberBuilder) {
- final MutableObject numberOffset = new MutableObject(0);
- ((NumberBuilder) numberBuilder).process(text1, mathType, numberOffset);
- resultOffset += numberOffset.getObject();
- } else {
- ((LiteNumberBuilder) numberBuilder).process(mathType);
- }
-
- final String match = mathType.getMatch();
- switch (mathType.getMathType()) {
- case open_group_symbol:
- numberOfOpenGroupSymbols++;
- maxNumberOfOpenGroupSymbols = Math.max(maxNumberOfOpenGroupSymbols, numberOfOpenGroupSymbols);
- text1.append(text.charAt(i));
- break;
- case close_group_symbol:
- numberOfOpenGroupSymbols--;
- text1.append(text.charAt(i));
- break;
- case operator:
- text1.append(match);
- if (match.length() > 1) {
- i += match.length() - 1;
- }
- break;
- case function:
- i = processHighlightedText(text1, i, match, "i", null);
- break;
- case constant:
- i = processHighlightedText(text1, i, match, "b", null);
- break;
- case numeral_base:
- i = processHighlightedText(text1, i, match, "b", null);
- break;
- default:
- if (mathType.getMathType() == MathType.text || match.length() <= 1) {
- text1.append(text.charAt(i));
- } else {
- text1.append(match);
- i += match.length() - 1;
- }
- }
- }
-
- if (numberBuilder instanceof NumberBuilder) {
- final MutableObject numberOffset = new MutableObject(0);
- ((NumberBuilder) numberBuilder).processNumber(text1, numberOffset);
- resultOffset += numberOffset.getObject();
- }
-
- if (maxNumberOfOpenGroupSymbols > 0) {
-
- final StringBuilder text2 = new StringBuilder();
-
- String s = text1.toString();
- int i = processBracketGroup(text2, s, 0, 0, maxNumberOfOpenGroupSymbols);
- for (; i < s.length(); i++) {
- text2.append(s.charAt(i));
- }
-
- //Log.d(CalculatorEditor.class.getName(), text2.toString());
-
- result = text2.toString();
- } else {
- result = text1.toString();
- }
-
- return new Result(result, resultOffset);
- }
-
- private int processHighlightedText(@NotNull StringBuilder result, int i, @NotNull String match, @NotNull String tag, @Nullable Map tagAttributes) {
- result.append("<").append(tag);
-
- if (tagAttributes != null) {
- for (Map.Entry entry : tagAttributes.entrySet()) {
- // attr1="attr1_value" attr2="attr2_value"
- result.append(" ").append(entry.getKey()).append("=\"").append(entry.getValue()).append("\"");
- }
- }
-
- result.append(">").append(match).append("").append(tag).append(">");
- if (match.length() > 1) {
- return i + match.length() - 1;
- } else {
- return i;
- }
- }
-
- private int processBracketGroup(@NotNull StringBuilder result, @NotNull String s, int i, int numberOfOpenings, int maxNumberOfGroups) {
-
- result.append("");
-
- for (; i < s.length(); i++) {
- char ch = s.charAt(i);
-
- if (MathType.open_group_symbol.getTokens().contains(String.valueOf(ch))) {
- result.append(ch);
- result.append("");
- i = processBracketGroup(result, s, i + 1, numberOfOpenings + 1, maxNumberOfGroups);
- result.append("");
- if (i < s.length() && MathType.close_group_symbol.getTokens().contains(String.valueOf(s.charAt(i)))) {
- result.append(s.charAt(i));
- }
- } else if (MathType.close_group_symbol.getTokens().contains(String.valueOf(ch))) {
- break;
- } else {
- result.append(ch);
- }
- }
-
- result.append("");
-
-
- return i;
- }
-
- private String getColor(int totalNumberOfOpenings, int numberOfOpenings) {
- double c = 0.8;
-
- int offset = ((int) (255 * c)) * numberOfOpenings / (totalNumberOfOpenings + 1);
-
- // for tests:
- // innt result = Color.rgb(BASE_COLOUR_RED_COMPONENT - offset, BASE_COLOUR_GREEN_COMPONENT - offset, BASE_COLOUR_BLUE_COMPONENT - offset);
- int result = (0xFF << 24) | ((colorRed - offset) << 16) | ((colorGreen - offset) << 8) | (colorBlue - offset);
-
- return "#" + Integer.toHexString(result).substring(2);
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator.view;
+
+import jscl.MathContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.solovyev.android.calculator.CalculatorParseException;
+import org.solovyev.android.calculator.math.MathType;
+import org.solovyev.android.calculator.model.*;
+import org.solovyev.android.calculator.text.TextProcessor;
+import org.solovyev.common.MutableObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: serso
+ * Date: 10/12/11
+ * Time: 9:47 PM
+ */
+public class TextHighlighter implements TextProcessor {
+
+ private static final Map nbFontAttributes = new HashMap();
+
+ static {
+ nbFontAttributes.put("color", "#008000");
+ }
+
+ @NotNull
+ public final MathContext mathContext;
+
+ public static class Result implements CharSequence {
+
+ @NotNull
+ private final String string;
+
+ private final int offset;
+
+ public Result(@NotNull String string, int offset) {
+ this.string = string;
+ this.offset = offset;
+ }
+
+ @Override
+ public int length() {
+ return string.length();
+ }
+
+ @Override
+ public char charAt(int i) {
+ return string.charAt(i);
+ }
+
+ @Override
+ public CharSequence subSequence(int i, int i1) {
+ return string.subSequence(i, i1);
+ }
+
+ @Override
+ public String toString() {
+ return string;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+ }
+
+ private final int color;
+ private final int colorRed;
+ private final int colorGreen;
+ private final int colorBlue;
+ private final boolean formatNumber;
+
+ public TextHighlighter(int baseColor, boolean formatNumber, @NotNull MathContext mathContext) {
+ this.color = baseColor;
+ this.formatNumber = formatNumber;
+ this.mathContext = mathContext;
+ //this.colorRed = Color.red(baseColor);
+ this.colorRed = (baseColor >> 16) & 0xFF;
+ //this.colorGreen = Color.green(baseColor);
+ this.colorGreen = (color >> 8) & 0xFF;
+ //this.colorBlue = Color.blue(baseColor);
+ this.colorBlue = color & 0xFF;
+ }
+
+ @NotNull
+ @Override
+ public Result process(@NotNull String text) throws CalculatorParseException {
+ final String result;
+
+ int maxNumberOfOpenGroupSymbols = 0;
+ int numberOfOpenGroupSymbols = 0;
+
+ final StringBuilder text1 = new StringBuilder();
+
+ int resultOffset = 0;
+
+ final AbstractNumberBuilder numberBuilder;
+ if (!formatNumber) {
+ numberBuilder = new LiteNumberBuilder(CalculatorEngine.instance.getEngine());
+ } else {
+ numberBuilder = new NumberBuilder(CalculatorEngine.instance.getEngine());
+ }
+ for (int i = 0; i < text.length(); i++) {
+ MathType.Result mathType = MathType.getType(text, i, numberBuilder.isHexMode());
+
+ if (numberBuilder instanceof NumberBuilder) {
+ final MutableObject numberOffset = new MutableObject(0);
+ ((NumberBuilder) numberBuilder).process(text1, mathType, numberOffset);
+ resultOffset += numberOffset.getObject();
+ } else {
+ ((LiteNumberBuilder) numberBuilder).process(mathType);
+ }
+
+ final String match = mathType.getMatch();
+ switch (mathType.getMathType()) {
+ case open_group_symbol:
+ numberOfOpenGroupSymbols++;
+ maxNumberOfOpenGroupSymbols = Math.max(maxNumberOfOpenGroupSymbols, numberOfOpenGroupSymbols);
+ text1.append(text.charAt(i));
+ break;
+ case close_group_symbol:
+ numberOfOpenGroupSymbols--;
+ text1.append(text.charAt(i));
+ break;
+ case operator:
+ text1.append(match);
+ if (match.length() > 1) {
+ i += match.length() - 1;
+ }
+ break;
+ case function:
+ i = processHighlightedText(text1, i, match, "i", null);
+ break;
+ case constant:
+ i = processHighlightedText(text1, i, match, "b", null);
+ break;
+ case numeral_base:
+ i = processHighlightedText(text1, i, match, "b", null);
+ break;
+ default:
+ if (mathType.getMathType() == MathType.text || match.length() <= 1) {
+ text1.append(text.charAt(i));
+ } else {
+ text1.append(match);
+ i += match.length() - 1;
+ }
+ }
+ }
+
+ if (numberBuilder instanceof NumberBuilder) {
+ final MutableObject numberOffset = new MutableObject(0);
+ ((NumberBuilder) numberBuilder).processNumber(text1, numberOffset);
+ resultOffset += numberOffset.getObject();
+ }
+
+ if (maxNumberOfOpenGroupSymbols > 0) {
+
+ final StringBuilder text2 = new StringBuilder();
+
+ String s = text1.toString();
+ int i = processBracketGroup(text2, s, 0, 0, maxNumberOfOpenGroupSymbols);
+ for (; i < s.length(); i++) {
+ text2.append(s.charAt(i));
+ }
+
+ //Log.d(CalculatorEditor.class.getName(), text2.toString());
+
+ result = text2.toString();
+ } else {
+ result = text1.toString();
+ }
+
+ return new Result(result, resultOffset);
+ }
+
+ private int processHighlightedText(@NotNull StringBuilder result, int i, @NotNull String match, @NotNull String tag, @Nullable Map tagAttributes) {
+ result.append("<").append(tag);
+
+ if (tagAttributes != null) {
+ for (Map.Entry entry : tagAttributes.entrySet()) {
+ // attr1="attr1_value" attr2="attr2_value"
+ result.append(" ").append(entry.getKey()).append("=\"").append(entry.getValue()).append("\"");
+ }
+ }
+
+ result.append(">").append(match).append("").append(tag).append(">");
+ if (match.length() > 1) {
+ return i + match.length() - 1;
+ } else {
+ return i;
+ }
+ }
+
+ private int processBracketGroup(@NotNull StringBuilder result, @NotNull String s, int i, int numberOfOpenings, int maxNumberOfGroups) {
+
+ result.append("");
+
+ for (; i < s.length(); i++) {
+ char ch = s.charAt(i);
+
+ if (MathType.open_group_symbol.getTokens().contains(String.valueOf(ch))) {
+ result.append(ch);
+ result.append("");
+ i = processBracketGroup(result, s, i + 1, numberOfOpenings + 1, maxNumberOfGroups);
+ result.append("");
+ if (i < s.length() && MathType.close_group_symbol.getTokens().contains(String.valueOf(s.charAt(i)))) {
+ result.append(s.charAt(i));
+ }
+ } else if (MathType.close_group_symbol.getTokens().contains(String.valueOf(ch))) {
+ break;
+ } else {
+ result.append(ch);
+ }
+ }
+
+ result.append("");
+
+
+ return i;
+ }
+
+ private String getColor(int totalNumberOfOpenings, int numberOfOpenings) {
+ double c = 0.8;
+
+ int offset = ((int) (255 * c)) * numberOfOpenings / (totalNumberOfOpenings + 1);
+
+ // for tests:
+ // innt result = Color.rgb(BASE_COLOUR_RED_COMPONENT - offset, BASE_COLOUR_GREEN_COMPONENT - offset, BASE_COLOUR_BLUE_COMPONENT - offset);
+ int result = (0xFF << 24) | ((colorRed - offset) << 16) | ((colorGreen - offset) << 8) | (colorBlue - offset);
+
+ return "#" + Integer.toHexString(result).substring(2);
+ }
+}
diff --git a/calculatorpp/src/test/java/org/solovyev/android/calculator/TextHighlighterTest.java b/calculatorpp/src/test/java/org/solovyev/android/calculator/TextHighlighterTest.java
index bc8950a9..af984177 100644
--- a/calculatorpp/src/test/java/org/solovyev/android/calculator/TextHighlighterTest.java
+++ b/calculatorpp/src/test/java/org/solovyev/android/calculator/TextHighlighterTest.java
@@ -1,137 +1,137 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator;
-
-import jscl.JsclMathEngine;
-import jscl.MathEngine;
-import jscl.NumeralBase;
-import junit.framework.Assert;
-import org.junit.Test;
-import org.solovyev.android.calculator.model.CalculatorEngine;
-import org.solovyev.android.calculator.model.TextProcessor;
-import org.solovyev.android.calculator.view.TextHighlighter;
-
-import java.util.Date;
-import java.util.Random;
-
-/**
- * User: serso
- * Date: 10/12/11
- * Time: 10:07 PM
- */
-public class TextHighlighterTest {
-
- @Test
- public void testProcess() throws Exception {
- TextProcessor, String> textHighlighter = new TextHighlighter(0, false, JsclMathEngine.instance);
-
- final Random random = new Random(new Date().getTime());
- for (int i = 0; i < 1000; i++) {
- final StringBuilder sb = new StringBuilder();
- for (int j = 0; j < 1000; j++) {
- sb.append(random.nextBoolean() ? "(" : ")");
- }
- try {
- textHighlighter.process(sb.toString());
- } catch (Exception e) {
- System.out.println(sb.toString());
- throw e;
- }
- }
-
- Assert.assertEquals(")(((())())", textHighlighter.process(")(((())())").toString());
- Assert.assertEquals(")", textHighlighter.process(")").toString());
- Assert.assertEquals(")()(", textHighlighter.process(")()(").toString());
-
- textHighlighter = new TextHighlighter(0, true, JsclMathEngine.instance);
- 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("1E3", textHighlighter.process("1E3").toString());
- Assert.assertEquals("20x:", textHighlighter.process("20x:").toString());
- Assert.assertEquals("20g", textHighlighter.process("20g").toString());
- Assert.assertEquals("22g", textHighlighter.process("22g").toString());
- Assert.assertEquals("20ю", textHighlighter.process("20ю").toString());
- Assert.assertEquals("20ъ", textHighlighter.process("20ъ").toString());
- Assert.assertEquals("3!!", textHighlighter.process("3!!").toString());
- Assert.assertEquals("2", textHighlighter.process("2").toString());
- Assert.assertEquals("21", textHighlighter.process("21").toString());
- Assert.assertEquals("214", textHighlighter.process("214").toString());
- Assert.assertEquals("2 145", textHighlighter.process("2 145").toString());
- 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-30000", textHighlighter.process("-1000000E-30000").toString());
- textHighlighter = new TextHighlighter(0, false, JsclMathEngine.instance);
-
- textHighlighter.process("cannot calculate 3^10^10 !!!\n" +
- " unable to enter 0. FIXED\n" +
- " empty display in Xperia Rayo\n" +
- " check привиденная FIXED\n" +
- " set display result only if text in editor was not changed FIXED\n" +
- " shift M text to the left\n" +
- " do not show SYNTAX ERROR always (may be show send clock?q) FIXED\n" +
- " ln(8)*log(8) => ln(8)*og(8) FIXED\n" +
- " copy/paste ln(8)*log(8)\n" +
- " 6!^2 ERROR");
-
- Assert.assertEquals("sin(2)", textHighlighter.process("sin(2)").toString());
- Assert.assertEquals("atanh(2)", textHighlighter.process("atanh(2)").toString());
-
-
- Assert.assertEquals("0x:E", textHighlighter.process("0x:E").toString());
- Assert.assertEquals("0x:6F", textHighlighter.process("0x:6F").toString());
- Assert.assertEquals("0x:6F.", textHighlighter.process("0x:6F.").toString());
- Assert.assertEquals("0x:6F.2", textHighlighter.process("0x:6F.2").toString());
- Assert.assertEquals("0x:6F.B", textHighlighter.process("0x:6F.B").toString());
- Assert.assertEquals("0x:006F.B", textHighlighter.process("0x:006F.B").toString());
- Assert.assertEquals("0x:0", textHighlighter.process("0x:0").toString());
- Assert.assertEquals("0x:FF33233FFE", textHighlighter.process("0x:FF33233FFE").toString());
- Assert.assertEquals("0x:FF33 233 FFE", textHighlighter.process("0x:FF33 233 FFE").toString());
-
- final MathEngine me = CalculatorEngine.instance.getEngine();
- try {
- me.setNumeralBase(NumeralBase.hex);
- Assert.assertEquals("E", textHighlighter.process("E").toString());
- Assert.assertEquals(".E", textHighlighter.process(".E").toString());
- Assert.assertEquals("E+", textHighlighter.process("E+").toString());
- Assert.assertEquals("E.", textHighlighter.process("E.").toString());
- Assert.assertEquals(".E.", textHighlighter.process(".E.").toString());
- Assert.assertEquals("6F", textHighlighter.process("6F").toString());
- Assert.assertEquals("6F", textHighlighter.process("6F").toString());
- Assert.assertEquals("6F.", textHighlighter.process("6F.").toString());
- Assert.assertEquals("6F.2", textHighlighter.process("6F.2").toString());
- Assert.assertEquals("6F.B", textHighlighter.process("6F.B").toString());
- Assert.assertEquals("006F.B", textHighlighter.process("006F.B").toString());
- } finally {
- me.setNumeralBase(NumeralBase.dec);
- }
-
- Assert.assertEquals("0b:110101", textHighlighter.process("0b:110101").toString());
- Assert.assertEquals("0b:110101.", textHighlighter.process("0b:110101.").toString());
- Assert.assertEquals("0b:110101.101", textHighlighter.process("0b:110101.101").toString());
- Assert.assertEquals("0b:11010100.1", textHighlighter.process("0b:11010100.1").toString());
- Assert.assertEquals("0b:110101.0", textHighlighter.process("0b:110101.0").toString());
- Assert.assertEquals("0b:0", textHighlighter.process("0b:0").toString());
- Assert.assertEquals("0b:1010100101111010101001", textHighlighter.process("0b:1010100101111010101001").toString());
- Assert.assertEquals("0b:101 010 01 0 111 1 0 10101001", textHighlighter.process("0b:101 010 01 0 111 1 0 10101001").toString());
-
- try {
- me.setNumeralBase(NumeralBase.bin);
- Assert.assertEquals("110101", textHighlighter.process("110101").toString());
- Assert.assertEquals("110101.", textHighlighter.process("110101.").toString());
- Assert.assertEquals("110101.101", textHighlighter.process("110101.101").toString());
- Assert.assertEquals("11010100.1", textHighlighter.process("11010100.1").toString());
- Assert.assertEquals("110101.0", textHighlighter.process("110101.0").toString());
- Assert.assertEquals("0", textHighlighter.process("0").toString());
- Assert.assertEquals("1010100101111010101001", textHighlighter.process("1010100101111010101001").toString());
- Assert.assertEquals("101 010 01 0 111 1 0 10101001", textHighlighter.process("101 010 01 0 111 1 0 10101001").toString());
- } finally {
- me.setNumeralBase(NumeralBase.dec);
- }
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator;
+
+import jscl.JsclMathEngine;
+import jscl.MathEngine;
+import jscl.NumeralBase;
+import junit.framework.Assert;
+import org.junit.Test;
+import org.solovyev.android.calculator.model.CalculatorEngine;
+import org.solovyev.android.calculator.text.TextProcessor;
+import org.solovyev.android.calculator.view.TextHighlighter;
+
+import java.util.Date;
+import java.util.Random;
+
+/**
+ * User: serso
+ * Date: 10/12/11
+ * Time: 10:07 PM
+ */
+public class TextHighlighterTest {
+
+ @Test
+ public void testProcess() throws Exception {
+ TextProcessor, String> textHighlighter = new TextHighlighter(0, false, JsclMathEngine.instance);
+
+ final Random random = new Random(new Date().getTime());
+ for (int i = 0; i < 1000; i++) {
+ final StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < 1000; j++) {
+ sb.append(random.nextBoolean() ? "(" : ")");
+ }
+ try {
+ textHighlighter.process(sb.toString());
+ } catch (Exception e) {
+ System.out.println(sb.toString());
+ throw e;
+ }
+ }
+
+ Assert.assertEquals(")(((())())", textHighlighter.process(")(((())())").toString());
+ Assert.assertEquals(")", textHighlighter.process(")").toString());
+ Assert.assertEquals(")()(", textHighlighter.process(")()(").toString());
+
+ textHighlighter = new TextHighlighter(0, true, JsclMathEngine.instance);
+ 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("1E3", textHighlighter.process("1E3").toString());
+ Assert.assertEquals("20x:", textHighlighter.process("20x:").toString());
+ Assert.assertEquals("20g", textHighlighter.process("20g").toString());
+ Assert.assertEquals("22g", textHighlighter.process("22g").toString());
+ Assert.assertEquals("20ю", textHighlighter.process("20ю").toString());
+ Assert.assertEquals("20ъ", textHighlighter.process("20ъ").toString());
+ Assert.assertEquals("3!!", textHighlighter.process("3!!").toString());
+ Assert.assertEquals("2", textHighlighter.process("2").toString());
+ Assert.assertEquals("21", textHighlighter.process("21").toString());
+ Assert.assertEquals("214", textHighlighter.process("214").toString());
+ Assert.assertEquals("2 145", textHighlighter.process("2 145").toString());
+ 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-30000", textHighlighter.process("-1000000E-30000").toString());
+ textHighlighter = new TextHighlighter(0, false, JsclMathEngine.instance);
+
+ textHighlighter.process("cannot calculate 3^10^10 !!!\n" +
+ " unable to enter 0. FIXED\n" +
+ " empty display in Xperia Rayo\n" +
+ " check привиденная FIXED\n" +
+ " set display result only if text in editor was not changed FIXED\n" +
+ " shift M text to the left\n" +
+ " do not show SYNTAX ERROR always (may be show send clock?q) FIXED\n" +
+ " ln(8)*log(8) => ln(8)*og(8) FIXED\n" +
+ " copy/paste ln(8)*log(8)\n" +
+ " 6!^2 ERROR");
+
+ Assert.assertEquals("sin(2)", textHighlighter.process("sin(2)").toString());
+ Assert.assertEquals("atanh(2)", textHighlighter.process("atanh(2)").toString());
+
+
+ Assert.assertEquals("0x:E", textHighlighter.process("0x:E").toString());
+ Assert.assertEquals("0x:6F", textHighlighter.process("0x:6F").toString());
+ Assert.assertEquals("0x:6F.", textHighlighter.process("0x:6F.").toString());
+ Assert.assertEquals("0x:6F.2", textHighlighter.process("0x:6F.2").toString());
+ Assert.assertEquals("0x:6F.B", textHighlighter.process("0x:6F.B").toString());
+ Assert.assertEquals("0x:006F.B", textHighlighter.process("0x:006F.B").toString());
+ Assert.assertEquals("0x:0", textHighlighter.process("0x:0").toString());
+ Assert.assertEquals("0x:FF33233FFE", textHighlighter.process("0x:FF33233FFE").toString());
+ Assert.assertEquals("0x:FF33 233 FFE", textHighlighter.process("0x:FF33 233 FFE").toString());
+
+ final MathEngine me = CalculatorEngine.instance.getEngine();
+ try {
+ me.setNumeralBase(NumeralBase.hex);
+ Assert.assertEquals("E", textHighlighter.process("E").toString());
+ Assert.assertEquals(".E", textHighlighter.process(".E").toString());
+ Assert.assertEquals("E+", textHighlighter.process("E+").toString());
+ Assert.assertEquals("E.", textHighlighter.process("E.").toString());
+ Assert.assertEquals(".E.", textHighlighter.process(".E.").toString());
+ Assert.assertEquals("6F", textHighlighter.process("6F").toString());
+ Assert.assertEquals("6F", textHighlighter.process("6F").toString());
+ Assert.assertEquals("6F.", textHighlighter.process("6F.").toString());
+ Assert.assertEquals("6F.2", textHighlighter.process("6F.2").toString());
+ Assert.assertEquals("6F.B", textHighlighter.process("6F.B").toString());
+ Assert.assertEquals("006F.B", textHighlighter.process("006F.B").toString());
+ } finally {
+ me.setNumeralBase(NumeralBase.dec);
+ }
+
+ Assert.assertEquals("0b:110101", textHighlighter.process("0b:110101").toString());
+ Assert.assertEquals("0b:110101.", textHighlighter.process("0b:110101.").toString());
+ Assert.assertEquals("0b:110101.101", textHighlighter.process("0b:110101.101").toString());
+ Assert.assertEquals("0b:11010100.1", textHighlighter.process("0b:11010100.1").toString());
+ Assert.assertEquals("0b:110101.0", textHighlighter.process("0b:110101.0").toString());
+ Assert.assertEquals("0b:0", textHighlighter.process("0b:0").toString());
+ Assert.assertEquals("0b:1010100101111010101001", textHighlighter.process("0b:1010100101111010101001").toString());
+ Assert.assertEquals("0b:101 010 01 0 111 1 0 10101001", textHighlighter.process("0b:101 010 01 0 111 1 0 10101001").toString());
+
+ try {
+ me.setNumeralBase(NumeralBase.bin);
+ Assert.assertEquals("110101", textHighlighter.process("110101").toString());
+ Assert.assertEquals("110101.", textHighlighter.process("110101.").toString());
+ Assert.assertEquals("110101.101", textHighlighter.process("110101.101").toString());
+ Assert.assertEquals("11010100.1", textHighlighter.process("11010100.1").toString());
+ Assert.assertEquals("110101.0", textHighlighter.process("110101.0").toString());
+ Assert.assertEquals("0", textHighlighter.process("0").toString());
+ Assert.assertEquals("1010100101111010101001", textHighlighter.process("1010100101111010101001").toString());
+ Assert.assertEquals("101 010 01 0 111 1 0 10101001", textHighlighter.process("101 010 01 0 111 1 0 10101001").toString());
+ } finally {
+ me.setNumeralBase(NumeralBase.dec);
+ }
+ }
+}
diff --git a/calculatorpp/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java b/calculatorpp/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java
index 449ed9e2..187c504d 100644
--- a/calculatorpp/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java
+++ b/calculatorpp/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java
@@ -1,443 +1,444 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- */
-
-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.Test;
-import org.solovyev.android.calculator.jscl.JsclOperation;
-
-import java.text.DecimalFormatSymbols;
-import java.util.Locale;
-
-import static junit.framework.Assert.fail;
-
-/**
- * User: serso
- * Date: 9/17/11
- * Time: 9:47 PM
- */
-
-public class CalculatorEngineTest {
-
- @BeforeClass
- public static void setUp() throws Exception {
- CalculatorEngine.instance.init(null, null);
- CalculatorEngine.instance.setPrecision(3);
- CalculatorEngine.instance.setThreadKiller(new CalculatorEngine.ThreadKillerImpl());
- }
-
- @Test
- public void testDegrees() throws Exception {
- final CalculatorEngine cm = CalculatorEngine.instance;
-
- final AngleUnit defaultAngleUnit = cm.getEngine().getAngleUnits();
- try {
- cm.getEngine().setAngleUnits(AngleUnit.rad);
- cm.setPrecision(3);
- try {
- Assert.assertEquals("0.017", cm.evaluate(JsclOperation.numeric, "°"));
- fail();
- } catch (CalculatorParseException e) {
-
- }
-
- Assert.assertEquals("0.017", cm.evaluate(JsclOperation.numeric, "1°").getResult());
- Assert.assertEquals("0.349", cm.evaluate(JsclOperation.numeric, "20.0°").getResult());
- Assert.assertEquals("0.5", cm.evaluate(JsclOperation.numeric, "sin(30°)").getResult());
- Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "asin(sin(30°))").getResult());
- Assert.assertEquals("∂(cos(t), t, t, 1°)", cm.evaluate(JsclOperation.numeric, "∂(cos(t),t,t,1°)").getResult());
-
- Assert.assertEquals("∂(cos(t), t, t, 1°)", cm.evaluate(JsclOperation.simplify, "∂(cos(t),t,t,1°)").getResult());
- } finally {
- cm.getEngine().setAngleUnits(defaultAngleUnit);
- }
- }
-
- @Test
- public void testLongExecution() throws Exception {
- final CalculatorEngine cm = CalculatorEngine.instance;
-
- try {
- cm.evaluate(JsclOperation.numeric, "3^10^10^10");
- Assert.fail();
- } catch (CalculatorParseException e) {
- if (e.getMessageCode().equals(Messages.msg_3)) {
-
- } else {
- System.out.print(e.getCause().getMessage());
- Assert.fail();
- }
- }
-
- try {
- cm.evaluate(JsclOperation.numeric, "9999999!");
- Assert.fail();
- } catch (CalculatorParseException e) {
- if (e.getMessageCode().equals(Messages.msg_3)) {
-
- } else {
- System.out.print(e.getCause().getMessage());
- Assert.fail();
- }
- }
-
- /*final long start = System.currentTimeMillis();
- try {
- cm.evaluate(JsclOperation.numeric, "3^10^10^10");
- Assert.fail();
- } catch (ParseException e) {
- if (e.getMessage().startsWith("Too long calculation")) {
- final long end = System.currentTimeMillis();
- Assert.assertTrue(end - start < 1000);
- } else {
- Assert.fail();
- }
- }*/
-
- }
-
- @Test
- public void testEvaluate() throws Exception {
- final CalculatorEngine cm = CalculatorEngine.instance;
-
- Assert.assertEquals("cos(t)+10%", cm.evaluate(JsclOperation.simplify, "cos(t)+10%").getResult());
-
- final Generic expression = cm.getEngine().simplifyGeneric("cos(t)+10%");
- expression.substitute(new Constant("t"), Expression.valueOf(100d));
-
- Assert.assertEquals("it", cm.evaluate(JsclOperation.simplify, "it").getResult());
- Assert.assertEquals("10%", cm.evaluate(JsclOperation.simplify, "10%").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "eq(0, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq(1, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq( 1, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.simplify, "eq( 1, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "lg(10)").getResult());
- Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "2+2").getResult());
- final AngleUnit defaultAngleUnit = cm.getEngine().getAngleUnits();
- try {
- cm.getEngine().setAngleUnits(AngleUnit.rad);
- Assert.assertEquals("-0.757", cm.evaluate(JsclOperation.numeric, "sin(4)").getResult());
- Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "asin(0.5)").getResult());
- Assert.assertEquals("-0.396", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)").getResult());
- Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)").getResult());
- Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)").getResult());
- } finally {
- cm.getEngine().setAngleUnits(defaultAngleUnit);
- }
- Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "e^2").getResult());
- Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(1)^2").getResult());
- Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(2)").getResult());
- Assert.assertEquals("2+i", cm.evaluate(JsclOperation.numeric, "2*1+√(-1)").getResult());
- try {
- cm.getEngine().setAngleUnits(AngleUnit.rad);
- Assert.assertEquals("0.921+Πi", cm.evaluate(JsclOperation.numeric, "ln(5cosh(38π√(2cos(2))))").getResult());
- Assert.assertEquals("-3.41+3.41i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)").getResult());
- } finally {
- cm.getEngine().setAngleUnits(defaultAngleUnit);
- }
- Assert.assertEquals("7.389i", cm.evaluate(JsclOperation.numeric, "iexp(2)").getResult());
- Assert.assertEquals("2+7.389i", cm.evaluate(JsclOperation.numeric, "2+iexp(2)").getResult());
- Assert.assertEquals("2+7.389i", cm.evaluate(JsclOperation.numeric, "2+√(-1)exp(2)").getResult());
- Assert.assertEquals("2-2.5i", cm.evaluate(JsclOperation.numeric, "2-2.5i").getResult());
- Assert.assertEquals("-2-2.5i", cm.evaluate(JsclOperation.numeric, "-2-2.5i").getResult());
- Assert.assertEquals("-2+2.5i", cm.evaluate(JsclOperation.numeric, "-2+2.5i").getResult());
- Assert.assertEquals("-2+2.1i", cm.evaluate(JsclOperation.numeric, "-2+2.1i").getResult());
- Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)").getResult());
-
- junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "4!").getResult());
- junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "(2+2)!").getResult());
- junit.framework.Assert.assertEquals("120", cm.evaluate(JsclOperation.numeric, "(2+2+1)!").getResult());
- junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "(2.0+2.0)!").getResult());
- junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "4.0!").getResult());
- junit.framework.Assert.assertEquals("720", cm.evaluate(JsclOperation.numeric, "(3!)!").getResult());
- junit.framework.Assert.assertEquals("36", Expression.valueOf("3!^2").numeric().toString());
- junit.framework.Assert.assertEquals("3", Expression.valueOf("cubic(27)").numeric().toString());
- try {
- junit.framework.Assert.assertEquals("√(-1)!", cm.evaluate(JsclOperation.numeric, "i!").getResult());
- fail();
- } catch (CalculatorParseException e) {
- }
-
- junit.framework.Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "(π/π)!").getResult());
-
- try {
- junit.framework.Assert.assertEquals("i", cm.evaluate(JsclOperation.numeric, "(-1)i!").getResult());
- fail();
- } catch (CalculatorParseException e) {
-
- }
- junit.framework.Assert.assertEquals("24i", cm.evaluate(JsclOperation.numeric, "4!i").getResult());
-
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("si", 5d));
-
- try {
- cm.getEngine().setAngleUnits(AngleUnit.rad);
- Assert.assertEquals("0.451", cm.evaluate(JsclOperation.numeric, "acos(0.8999999999999811)").getResult());
- Assert.assertEquals("-0.959", cm.evaluate(JsclOperation.numeric, "sin(5)").getResult());
- Assert.assertEquals("-4.795", cm.evaluate(JsclOperation.numeric, "sin(5)si").getResult());
- Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "sisin(5)si").getResult());
- Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "si*sin(5)si").getResult());
- Assert.assertEquals("-3.309", cm.evaluate(JsclOperation.numeric, "sisin(5si)si").getResult());
- } finally {
- cm.getEngine().setAngleUnits(defaultAngleUnit);
- }
-
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("s", 1d));
- Assert.assertEquals("5", cm.evaluate(JsclOperation.numeric, "si").getResult());
-
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("k", 3.5d));
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("k1", 4d));
- Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "k11").getResult());
-
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", (String) null));
- Assert.assertEquals("11t", cm.evaluate(JsclOperation.numeric, "t11").getResult());
- Assert.assertEquals("11et", cm.evaluate(JsclOperation.numeric, "t11e").getResult());
- Assert.assertEquals("∞", cm.evaluate(JsclOperation.numeric, "∞").getResult());
- Assert.assertEquals("∞", cm.evaluate(JsclOperation.numeric, "Infinity").getResult());
- Assert.assertEquals("11∞t", cm.evaluate(JsclOperation.numeric, "t11∞").getResult());
- Assert.assertEquals("-t+t^3", cm.evaluate(JsclOperation.numeric, "t(t-1)(t+1)").getResult());
-
- Assert.assertEquals("100", cm.evaluate(JsclOperation.numeric, "0.1E3").getResult());
- Assert.assertEquals("3.957", cm.evaluate(JsclOperation.numeric, "ln(8)lg(8)+ln(8)").getResult());
-
- Assert.assertEquals("0.933", cm.evaluate(JsclOperation.numeric, "0x:E/0x:F").getResult());
-
- try {
- cm.getEngine().setNumeralBase(NumeralBase.hex);
- Assert.assertEquals("E/F", cm.evaluate(JsclOperation.numeric, "0x:E/0x:F").getResult());
- Assert.assertEquals("E/F", cm.evaluate(JsclOperation.simplify, "0x:E/0x:F").getResult());
- Assert.assertEquals("E/F", cm.evaluate(JsclOperation.numeric, "E/F").getResult());
- Assert.assertEquals("E/F", cm.evaluate(JsclOperation.simplify, "E/F").getResult());
- } finally {
- cm.getEngine().setNumeralBase(NumeralBase.dec);
- }
-
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "((((((0))))))").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))").getResult());
-
-
- /* Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "30°").getResult());
- Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "(10+20)°").getResult());
- Assert.assertEquals("1.047", cm.evaluate(JsclOperation.numeric, "(10+20)°*2").getResult());
- try {
- Assert.assertEquals("0.278", cm.evaluate(JsclOperation.numeric, "30°^2").getResult());
- junit.framework.Assert.fail();
- } catch (ParseException e) {
- if ( !e.getMessage().equals("Power operation after postfix function is currently unsupported!") ) {
- junit.framework.Assert.fail();
- }
- }*/
-
-/* try {
- cm.setTimeout(5000);
- Assert.assertEquals("2", cm.evaluate(JsclOperation.numeric, "2!").getResult());
- } finally {
- cm.setTimeout(3000);
- }*/
-
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", (String) null));
- Assert.assertEquals("2t", cm.evaluate(JsclOperation.simplify, "∂(t^2,t)").getResult());
- Assert.assertEquals("2t", cm.evaluate(JsclOperation.numeric, "∂(t^2,t)").getResult());
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", "2"));
- Assert.assertEquals("2t", cm.evaluate(JsclOperation.simplify, "∂(t^2,t)").getResult());
- Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "∂(t^2,t)").getResult());
-
- Assert.assertEquals("-x+x*ln(x)", cm.getEngine().simplify("∫(ln(x), x)"));
- Assert.assertEquals("-(x-x*ln(x))/(ln(2)+ln(5))", cm.getEngine().simplify("∫(log(10, x), x)"));
-
- Assert.assertEquals("∫((ln(2)+ln(5))/ln(x), x)", cm.getEngine().simplify("∫(ln(10)/ln(x), x)"));
- Assert.assertEquals("∫(ln(10)/ln(x), x)", Expression.valueOf("∫(log(x, 10), x)").expand().toString());
- Assert.assertEquals("∫((ln(2)+ln(5))/ln(x), x)", cm.getEngine().simplify("∫(log(x, 10), x)"));
- }
-
- @Test
- public void testFormatting() throws Exception {
- final CalculatorEngine ce = CalculatorEngine.instance;
-
- Assert.assertEquals("12 345", ce.evaluate(JsclOperation.simplify, "12345").getResult());
-
- }
-
- @Test
- public void testI() throws CalculatorParseException, CalculatorEvalException {
- final CalculatorEngine cm = CalculatorEngine.instance;
-
- Assert.assertEquals("-i", cm.evaluate(JsclOperation.numeric, "i^3").getResult());
- for (int i = 0; i < 1000; i++) {
- double real = (Math.random()-0.5) * 1000;
- double imag = (Math.random()-0.5) * 1000;
- int exp = (int)(Math.random() * 10);
-
- final StringBuilder sb = new StringBuilder();
- sb.append(real);
- if ( imag > 0 ) {
- sb.append("+");
- }
- sb.append(imag);
- sb.append("^").append(exp);
- try {
- cm.evaluate(JsclOperation.numeric, sb.toString()).getResult();
- } catch (Throwable e) {
- fail(sb.toString());
- }
- }
- }
-
- @Test
- public void testEmptyFunction() throws Exception {
- final CalculatorEngine cm = CalculatorEngine.instance;
- try {
- cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos(cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos())))))))))))))))))))))))))))))))))))))");
- Assert.fail();
- } catch (CalculatorParseException e) {
- }
- Assert.assertEquals("0.34+1.382i", cm.evaluate(JsclOperation.numeric, "ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(100)))))))))))))))").getResult());
- try {
- cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos())))))))))))))))))))))))))))))))))))");
- Assert.fail();
- } catch (CalculatorParseException e) {
- }
-
- final AngleUnit defaultAngleUnit = cm.getEngine().getAngleUnits();
- try {
- cm.getEngine().setAngleUnits(AngleUnit.rad);
- Assert.assertEquals("0.739", cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(1))))))))))))))))))))))))))))))))))))").getResult());
- } finally {
- cm.getEngine().setAngleUnits(defaultAngleUnit);
- }
-
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("si", 5d));
- Assert.assertEquals("5", cm.evaluate(JsclOperation.numeric, "si").getResult());
-
- try {
- cm.evaluate(JsclOperation.numeric, "sin");
- Assert.fail();
- } catch (CalculatorParseException e) {
- }
- }
-
- @Test
- public void testRounding() throws Exception {
- final CalculatorEngine cm = CalculatorEngine.instance;
-
- try {
- DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(Locale.getDefault());
- decimalGroupSymbols.setDecimalSeparator('.');
- decimalGroupSymbols.setGroupingSeparator('\'');
- cm.setDecimalGroupSymbols(decimalGroupSymbols);
- cm.setPrecision(2);
- Assert.assertEquals("12'345'678.9", cm.evaluate(JsclOperation.numeric, "1.23456789E7").getResult());
- cm.setPrecision(10);
- Assert.assertEquals("12'345'678.9", cm.evaluate(JsclOperation.numeric, "1.23456789E7").getResult());
- Assert.assertEquals("123'456'789", cm.evaluate(JsclOperation.numeric, "1.234567890E8").getResult());
- Assert.assertEquals("1'234'567'890.1", cm.evaluate(JsclOperation.numeric, "1.2345678901E9").getResult());
- } finally {
- cm.setPrecision(3);
- DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(Locale.getDefault());
- decimalGroupSymbols.setDecimalSeparator('.');
- decimalGroupSymbols.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT.charAt(0));
- cm.setDecimalGroupSymbols(decimalGroupSymbols);
- }
- }
-
- @Test
- public void testComparisonFunction() throws Exception {
- final CalculatorEngine cm = CalculatorEngine.instance;
-
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "eq(0, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq(1, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq(1, 1.0)").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "eq(1, 1.000000000000001)").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "eq(1, 0)").getResult());
-
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "lt(0, 1)").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "lt(1, 1)").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "lt(1, 0)").getResult());
-
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "gt(0, 1)").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "gt(1, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "gt(1, 0)").getResult());
-
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ne(0, 1)").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "ne(1, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ne(1, 0)").getResult());
-
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "le(0, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "le(1, 1)").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "le(1, 0)").getResult());
-
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "ge(0, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ge(1, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ge(1, 0)").getResult());
-
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "ap(0, 1)").getResult());
- Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ap(1, 1)").getResult());
- //Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ap(1, 1.000000000000001)").getResult());
- Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "ap(1, 0)").getResult());
-
- }
-
-
- @Test
- public void testNumeralSystems() throws Exception {
- final CalculatorEngine cm = CalculatorEngine.instance;
-
- Assert.assertEquals("11 259 375", cm.evaluate(JsclOperation.numeric, "0x:ABCDEF").getResult());
- Assert.assertEquals("30 606 154.462", cm.evaluate(JsclOperation.numeric, "0x:ABCDEF*e").getResult());
- Assert.assertEquals("30 606 154.462", cm.evaluate(JsclOperation.numeric, "e*0x:ABCDEF").getResult());
- Assert.assertEquals("e", cm.evaluate(JsclOperation.numeric, "e*0x:ABCDEF/0x:ABCDEF").getResult());
- Assert.assertEquals("30 606 154.462", cm.evaluate(JsclOperation.numeric, "0x:ABCDEF*e*0x:ABCDEF/0x:ABCDEF").getResult());
- Assert.assertEquals("30 606 154.462", cm.evaluate(JsclOperation.numeric, "c+0x:ABCDEF*e*0x:ABCDEF/0x:ABCDEF-c+0x:C-0x:C").getResult());
- Assert.assertEquals("1 446 257 064 651.832", cm.evaluate(JsclOperation.numeric, "28*28 * sin(28) - 0b:1101 + √(28) + exp ( 28) ").getResult());
- Assert.assertEquals("13", cm.evaluate(JsclOperation.numeric, "0b:1101").getResult());
-
- try {
- cm.evaluate(JsclOperation.numeric, "0b:π").getResult();
- Assert.fail();
- } catch (CalculatorParseException e) {
- // ok
- }
-
- final NumeralBase defaultNumeralBase = cm.getEngine().getNumeralBase();
- try{
- cm.getEngine().setNumeralBase(NumeralBase.bin);
- Assert.assertEquals("101", cm.evaluate(JsclOperation.numeric, "10+11").getResult());
- Assert.assertEquals("10/11", cm.evaluate(JsclOperation.numeric, "10/11").getResult());
-
- cm.getEngine().setNumeralBase(NumeralBase.hex);
- Assert.assertEquals("63 7B", cm.evaluate(JsclOperation.numeric, "56CE+CAD").getResult());
- Assert.assertEquals("E", cm.evaluate(JsclOperation.numeric, "E").getResult());
- } finally {
- cm.setNumeralBase(defaultNumeralBase);
- }
- }
-
- @Test
- public void testLog() throws Exception {
- final CalculatorEngine cm = CalculatorEngine.instance;
-
- Assert.assertEquals("∞", Expression.valueOf("1/0").numeric().toString());
- Assert.assertEquals("∞", Expression.valueOf("ln(10)/ln(1)").numeric().toString());
-
- // logarithm
- Assert.assertEquals("ln(x)/ln(base)", ((CustomFunction) cm.getFunctionsRegistry().get("log")).getContent());
- Assert.assertEquals("∞", cm.evaluate(JsclOperation.numeric, "log(1, 10)").getResult());
- Assert.assertEquals("3.322", cm.evaluate(JsclOperation.numeric, "log(2, 10)").getResult());
- Assert.assertEquals("1.431", cm.evaluate(JsclOperation.numeric, "log(5, 10)").getResult());
- Assert.assertEquals("0.96", cm.evaluate(JsclOperation.numeric, "log(11, 10)").getResult());
- Assert.assertEquals("1/(bln(a))", cm.evaluate(JsclOperation.simplify, "∂(log(a, b), b)").getResult());
- Assert.assertEquals("-ln(b)/(aln(a)^2)", cm.evaluate(JsclOperation.simplify, "∂(log(a, b), a)").getResult());
-
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ */
+
+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.Test;
+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
+ * Date: 9/17/11
+ * Time: 9:47 PM
+ */
+
+public class CalculatorEngineTest {
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ CalculatorEngine.instance.init(null, null);
+ CalculatorEngine.instance.setPrecision(3);
+ CalculatorEngine.instance.setThreadKiller(new CalculatorEngine.ThreadKillerImpl());
+ }
+
+ @Test
+ public void testDegrees() throws Exception {
+ final CalculatorEngine cm = CalculatorEngine.instance;
+
+ final AngleUnit defaultAngleUnit = cm.getEngine().getAngleUnits();
+ try {
+ cm.getEngine().setAngleUnits(AngleUnit.rad);
+ cm.setPrecision(3);
+ try {
+ Assert.assertEquals("0.017", cm.evaluate(JsclOperation.numeric, "°"));
+ fail();
+ } catch (CalculatorParseException e) {
+
+ }
+
+ Assert.assertEquals("0.017", cm.evaluate(JsclOperation.numeric, "1°").getResult());
+ Assert.assertEquals("0.349", cm.evaluate(JsclOperation.numeric, "20.0°").getResult());
+ Assert.assertEquals("0.5", cm.evaluate(JsclOperation.numeric, "sin(30°)").getResult());
+ Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "asin(sin(30°))").getResult());
+ Assert.assertEquals("∂(cos(t), t, t, 1°)", cm.evaluate(JsclOperation.numeric, "∂(cos(t),t,t,1°)").getResult());
+
+ Assert.assertEquals("∂(cos(t), t, t, 1°)", cm.evaluate(JsclOperation.simplify, "∂(cos(t),t,t,1°)").getResult());
+ } finally {
+ cm.getEngine().setAngleUnits(defaultAngleUnit);
+ }
+ }
+
+ @Test
+ public void testLongExecution() throws Exception {
+ final CalculatorEngine cm = CalculatorEngine.instance;
+
+ try {
+ cm.evaluate(JsclOperation.numeric, "3^10^10^10");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ if (e.getMessageCode().equals(Messages.msg_3)) {
+
+ } else {
+ System.out.print(e.getCause().getMessage());
+ Assert.fail();
+ }
+ }
+
+ try {
+ cm.evaluate(JsclOperation.numeric, "9999999!");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ if (e.getMessageCode().equals(Messages.msg_3)) {
+
+ } else {
+ System.out.print(e.getCause().getMessage());
+ Assert.fail();
+ }
+ }
+
+ /*final long start = System.currentTimeMillis();
+ try {
+ cm.evaluate(JsclOperation.numeric, "3^10^10^10");
+ Assert.fail();
+ } catch (ParseException e) {
+ if (e.getMessage().startsWith("Too long calculation")) {
+ final long end = System.currentTimeMillis();
+ Assert.assertTrue(end - start < 1000);
+ } else {
+ Assert.fail();
+ }
+ }*/
+
+ }
+
+ @Test
+ public void testEvaluate() throws Exception {
+ final CalculatorEngine cm = CalculatorEngine.instance;
+
+ Assert.assertEquals("cos(t)+10%", cm.evaluate(JsclOperation.simplify, "cos(t)+10%").getResult());
+
+ final Generic expression = cm.getEngine().simplifyGeneric("cos(t)+10%");
+ expression.substitute(new Constant("t"), Expression.valueOf(100d));
+
+ Assert.assertEquals("it", cm.evaluate(JsclOperation.simplify, "it").getResult());
+ Assert.assertEquals("10%", cm.evaluate(JsclOperation.simplify, "10%").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "eq(0, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq(1, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq( 1, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.simplify, "eq( 1, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "lg(10)").getResult());
+ Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "2+2").getResult());
+ final AngleUnit defaultAngleUnit = cm.getEngine().getAngleUnits();
+ try {
+ cm.getEngine().setAngleUnits(AngleUnit.rad);
+ Assert.assertEquals("-0.757", cm.evaluate(JsclOperation.numeric, "sin(4)").getResult());
+ Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "asin(0.5)").getResult());
+ Assert.assertEquals("-0.396", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)").getResult());
+ Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)").getResult());
+ Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)").getResult());
+ } finally {
+ cm.getEngine().setAngleUnits(defaultAngleUnit);
+ }
+ Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "e^2").getResult());
+ Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(1)^2").getResult());
+ Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(2)").getResult());
+ Assert.assertEquals("2+i", cm.evaluate(JsclOperation.numeric, "2*1+√(-1)").getResult());
+ try {
+ cm.getEngine().setAngleUnits(AngleUnit.rad);
+ Assert.assertEquals("0.921+Πi", cm.evaluate(JsclOperation.numeric, "ln(5cosh(38π√(2cos(2))))").getResult());
+ Assert.assertEquals("-3.41+3.41i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)").getResult());
+ } finally {
+ cm.getEngine().setAngleUnits(defaultAngleUnit);
+ }
+ Assert.assertEquals("7.389i", cm.evaluate(JsclOperation.numeric, "iexp(2)").getResult());
+ Assert.assertEquals("2+7.389i", cm.evaluate(JsclOperation.numeric, "2+iexp(2)").getResult());
+ Assert.assertEquals("2+7.389i", cm.evaluate(JsclOperation.numeric, "2+√(-1)exp(2)").getResult());
+ Assert.assertEquals("2-2.5i", cm.evaluate(JsclOperation.numeric, "2-2.5i").getResult());
+ Assert.assertEquals("-2-2.5i", cm.evaluate(JsclOperation.numeric, "-2-2.5i").getResult());
+ Assert.assertEquals("-2+2.5i", cm.evaluate(JsclOperation.numeric, "-2+2.5i").getResult());
+ Assert.assertEquals("-2+2.1i", cm.evaluate(JsclOperation.numeric, "-2+2.1i").getResult());
+ Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)").getResult());
+
+ junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "4!").getResult());
+ junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "(2+2)!").getResult());
+ junit.framework.Assert.assertEquals("120", cm.evaluate(JsclOperation.numeric, "(2+2+1)!").getResult());
+ junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "(2.0+2.0)!").getResult());
+ junit.framework.Assert.assertEquals("24", cm.evaluate(JsclOperation.numeric, "4.0!").getResult());
+ junit.framework.Assert.assertEquals("720", cm.evaluate(JsclOperation.numeric, "(3!)!").getResult());
+ junit.framework.Assert.assertEquals("36", Expression.valueOf("3!^2").numeric().toString());
+ junit.framework.Assert.assertEquals("3", Expression.valueOf("cubic(27)").numeric().toString());
+ try {
+ junit.framework.Assert.assertEquals("√(-1)!", cm.evaluate(JsclOperation.numeric, "i!").getResult());
+ fail();
+ } catch (CalculatorParseException e) {
+ }
+
+ junit.framework.Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "(π/π)!").getResult());
+
+ try {
+ junit.framework.Assert.assertEquals("i", cm.evaluate(JsclOperation.numeric, "(-1)i!").getResult());
+ fail();
+ } catch (CalculatorParseException e) {
+
+ }
+ junit.framework.Assert.assertEquals("24i", cm.evaluate(JsclOperation.numeric, "4!i").getResult());
+
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("si", 5d));
+
+ try {
+ cm.getEngine().setAngleUnits(AngleUnit.rad);
+ Assert.assertEquals("0.451", cm.evaluate(JsclOperation.numeric, "acos(0.8999999999999811)").getResult());
+ Assert.assertEquals("-0.959", cm.evaluate(JsclOperation.numeric, "sin(5)").getResult());
+ Assert.assertEquals("-4.795", cm.evaluate(JsclOperation.numeric, "sin(5)si").getResult());
+ Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "sisin(5)si").getResult());
+ Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "si*sin(5)si").getResult());
+ Assert.assertEquals("-3.309", cm.evaluate(JsclOperation.numeric, "sisin(5si)si").getResult());
+ } finally {
+ cm.getEngine().setAngleUnits(defaultAngleUnit);
+ }
+
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("s", 1d));
+ Assert.assertEquals("5", cm.evaluate(JsclOperation.numeric, "si").getResult());
+
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("k", 3.5d));
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("k1", 4d));
+ Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "k11").getResult());
+
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", (String) null));
+ Assert.assertEquals("11t", cm.evaluate(JsclOperation.numeric, "t11").getResult());
+ Assert.assertEquals("11et", cm.evaluate(JsclOperation.numeric, "t11e").getResult());
+ Assert.assertEquals("∞", cm.evaluate(JsclOperation.numeric, "∞").getResult());
+ Assert.assertEquals("∞", cm.evaluate(JsclOperation.numeric, "Infinity").getResult());
+ Assert.assertEquals("11∞t", cm.evaluate(JsclOperation.numeric, "t11∞").getResult());
+ Assert.assertEquals("-t+t^3", cm.evaluate(JsclOperation.numeric, "t(t-1)(t+1)").getResult());
+
+ Assert.assertEquals("100", cm.evaluate(JsclOperation.numeric, "0.1E3").getResult());
+ Assert.assertEquals("3.957", cm.evaluate(JsclOperation.numeric, "ln(8)lg(8)+ln(8)").getResult());
+
+ Assert.assertEquals("0.933", cm.evaluate(JsclOperation.numeric, "0x:E/0x:F").getResult());
+
+ try {
+ cm.getEngine().setNumeralBase(NumeralBase.hex);
+ Assert.assertEquals("E/F", cm.evaluate(JsclOperation.numeric, "0x:E/0x:F").getResult());
+ Assert.assertEquals("E/F", cm.evaluate(JsclOperation.simplify, "0x:E/0x:F").getResult());
+ Assert.assertEquals("E/F", cm.evaluate(JsclOperation.numeric, "E/F").getResult());
+ Assert.assertEquals("E/F", cm.evaluate(JsclOperation.simplify, "E/F").getResult());
+ } finally {
+ cm.getEngine().setNumeralBase(NumeralBase.dec);
+ }
+
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "((((((0))))))").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))").getResult());
+
+
+ /* Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "30°").getResult());
+ Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "(10+20)°").getResult());
+ Assert.assertEquals("1.047", cm.evaluate(JsclOperation.numeric, "(10+20)°*2").getResult());
+ try {
+ Assert.assertEquals("0.278", cm.evaluate(JsclOperation.numeric, "30°^2").getResult());
+ junit.framework.Assert.fail();
+ } catch (ParseException e) {
+ if ( !e.getMessage().equals("Power operation after postfix function is currently unsupported!") ) {
+ junit.framework.Assert.fail();
+ }
+ }*/
+
+/* try {
+ cm.setTimeout(5000);
+ Assert.assertEquals("2", cm.evaluate(JsclOperation.numeric, "2!").getResult());
+ } finally {
+ cm.setTimeout(3000);
+ }*/
+
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", (String) null));
+ Assert.assertEquals("2t", cm.evaluate(JsclOperation.simplify, "∂(t^2,t)").getResult());
+ Assert.assertEquals("2t", cm.evaluate(JsclOperation.numeric, "∂(t^2,t)").getResult());
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", "2"));
+ Assert.assertEquals("2t", cm.evaluate(JsclOperation.simplify, "∂(t^2,t)").getResult());
+ Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "∂(t^2,t)").getResult());
+
+ Assert.assertEquals("-x+x*ln(x)", cm.getEngine().simplify("∫(ln(x), x)"));
+ Assert.assertEquals("-(x-x*ln(x))/(ln(2)+ln(5))", cm.getEngine().simplify("∫(log(10, x), x)"));
+
+ Assert.assertEquals("∫((ln(2)+ln(5))/ln(x), x)", cm.getEngine().simplify("∫(ln(10)/ln(x), x)"));
+ Assert.assertEquals("∫(ln(10)/ln(x), x)", Expression.valueOf("∫(log(x, 10), x)").expand().toString());
+ Assert.assertEquals("∫((ln(2)+ln(5))/ln(x), x)", cm.getEngine().simplify("∫(log(x, 10), x)"));
+ }
+
+ @Test
+ public void testFormatting() throws Exception {
+ final CalculatorEngine ce = CalculatorEngine.instance;
+
+ Assert.assertEquals("12 345", ce.evaluate(JsclOperation.simplify, "12345").getResult());
+
+ }
+
+ @Test
+ public void testI() throws CalculatorParseException, CalculatorEvalException {
+ final CalculatorEngine cm = CalculatorEngine.instance;
+
+ Assert.assertEquals("-i", cm.evaluate(JsclOperation.numeric, "i^3").getResult());
+ for (int i = 0; i < 1000; i++) {
+ double real = (Math.random()-0.5) * 1000;
+ double imag = (Math.random()-0.5) * 1000;
+ int exp = (int)(Math.random() * 10);
+
+ final StringBuilder sb = new StringBuilder();
+ sb.append(real);
+ if ( imag > 0 ) {
+ sb.append("+");
+ }
+ sb.append(imag);
+ sb.append("^").append(exp);
+ try {
+ cm.evaluate(JsclOperation.numeric, sb.toString()).getResult();
+ } catch (Throwable e) {
+ fail(sb.toString());
+ }
+ }
+ }
+
+ @Test
+ public void testEmptyFunction() throws Exception {
+ final CalculatorEngine cm = CalculatorEngine.instance;
+ try {
+ cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos(cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos())))))))))))))))))))))))))))))))))))))");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ }
+ Assert.assertEquals("0.34+1.382i", cm.evaluate(JsclOperation.numeric, "ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(100)))))))))))))))").getResult());
+ try {
+ cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos())))))))))))))))))))))))))))))))))))");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ }
+
+ final AngleUnit defaultAngleUnit = cm.getEngine().getAngleUnits();
+ try {
+ cm.getEngine().setAngleUnits(AngleUnit.rad);
+ Assert.assertEquals("0.739", cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(1))))))))))))))))))))))))))))))))))))").getResult());
+ } finally {
+ cm.getEngine().setAngleUnits(defaultAngleUnit);
+ }
+
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("si", 5d));
+ Assert.assertEquals("5", cm.evaluate(JsclOperation.numeric, "si").getResult());
+
+ try {
+ cm.evaluate(JsclOperation.numeric, "sin");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ }
+ }
+
+ @Test
+ public void testRounding() throws Exception {
+ final CalculatorEngine cm = CalculatorEngine.instance;
+
+ try {
+ DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(Locale.getDefault());
+ decimalGroupSymbols.setDecimalSeparator('.');
+ decimalGroupSymbols.setGroupingSeparator('\'');
+ cm.setDecimalGroupSymbols(decimalGroupSymbols);
+ cm.setPrecision(2);
+ Assert.assertEquals("12'345'678.9", cm.evaluate(JsclOperation.numeric, "1.23456789E7").getResult());
+ cm.setPrecision(10);
+ Assert.assertEquals("12'345'678.9", cm.evaluate(JsclOperation.numeric, "1.23456789E7").getResult());
+ Assert.assertEquals("123'456'789", cm.evaluate(JsclOperation.numeric, "1.234567890E8").getResult());
+ Assert.assertEquals("1'234'567'890.1", cm.evaluate(JsclOperation.numeric, "1.2345678901E9").getResult());
+ } finally {
+ cm.setPrecision(3);
+ DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols(Locale.getDefault());
+ decimalGroupSymbols.setDecimalSeparator('.');
+ decimalGroupSymbols.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT.charAt(0));
+ cm.setDecimalGroupSymbols(decimalGroupSymbols);
+ }
+ }
+
+ @Test
+ public void testComparisonFunction() throws Exception {
+ final CalculatorEngine cm = CalculatorEngine.instance;
+
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "eq(0, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq(1, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq(1, 1.0)").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "eq(1, 1.000000000000001)").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "eq(1, 0)").getResult());
+
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "lt(0, 1)").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "lt(1, 1)").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "lt(1, 0)").getResult());
+
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "gt(0, 1)").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "gt(1, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "gt(1, 0)").getResult());
+
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ne(0, 1)").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "ne(1, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ne(1, 0)").getResult());
+
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "le(0, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "le(1, 1)").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "le(1, 0)").getResult());
+
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "ge(0, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ge(1, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ge(1, 0)").getResult());
+
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "ap(0, 1)").getResult());
+ Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ap(1, 1)").getResult());
+ //Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "ap(1, 1.000000000000001)").getResult());
+ Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "ap(1, 0)").getResult());
+
+ }
+
+
+ @Test
+ public void testNumeralSystems() throws Exception {
+ final CalculatorEngine cm = CalculatorEngine.instance;
+
+ Assert.assertEquals("11 259 375", cm.evaluate(JsclOperation.numeric, "0x:ABCDEF").getResult());
+ Assert.assertEquals("30 606 154.462", cm.evaluate(JsclOperation.numeric, "0x:ABCDEF*e").getResult());
+ Assert.assertEquals("30 606 154.462", cm.evaluate(JsclOperation.numeric, "e*0x:ABCDEF").getResult());
+ Assert.assertEquals("e", cm.evaluate(JsclOperation.numeric, "e*0x:ABCDEF/0x:ABCDEF").getResult());
+ Assert.assertEquals("30 606 154.462", cm.evaluate(JsclOperation.numeric, "0x:ABCDEF*e*0x:ABCDEF/0x:ABCDEF").getResult());
+ Assert.assertEquals("30 606 154.462", cm.evaluate(JsclOperation.numeric, "c+0x:ABCDEF*e*0x:ABCDEF/0x:ABCDEF-c+0x:C-0x:C").getResult());
+ Assert.assertEquals("1 446 257 064 651.832", cm.evaluate(JsclOperation.numeric, "28*28 * sin(28) - 0b:1101 + √(28) + exp ( 28) ").getResult());
+ Assert.assertEquals("13", cm.evaluate(JsclOperation.numeric, "0b:1101").getResult());
+
+ try {
+ cm.evaluate(JsclOperation.numeric, "0b:π").getResult();
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ // ok
+ }
+
+ final NumeralBase defaultNumeralBase = cm.getEngine().getNumeralBase();
+ try{
+ cm.getEngine().setNumeralBase(NumeralBase.bin);
+ Assert.assertEquals("101", cm.evaluate(JsclOperation.numeric, "10+11").getResult());
+ Assert.assertEquals("10/11", cm.evaluate(JsclOperation.numeric, "10/11").getResult());
+
+ cm.getEngine().setNumeralBase(NumeralBase.hex);
+ Assert.assertEquals("63 7B", cm.evaluate(JsclOperation.numeric, "56CE+CAD").getResult());
+ Assert.assertEquals("E", cm.evaluate(JsclOperation.numeric, "E").getResult());
+ } finally {
+ cm.setNumeralBase(defaultNumeralBase);
+ }
+ }
+
+ @Test
+ public void testLog() throws Exception {
+ final CalculatorEngine cm = CalculatorEngine.instance;
+
+ Assert.assertEquals("∞", Expression.valueOf("1/0").numeric().toString());
+ Assert.assertEquals("∞", Expression.valueOf("ln(10)/ln(1)").numeric().toString());
+
+ // logarithm
+ Assert.assertEquals("ln(x)/ln(base)", ((CustomFunction) cm.getFunctionsRegistry().get("log")).getContent());
+ Assert.assertEquals("∞", cm.evaluate(JsclOperation.numeric, "log(1, 10)").getResult());
+ Assert.assertEquals("3.322", cm.evaluate(JsclOperation.numeric, "log(2, 10)").getResult());
+ Assert.assertEquals("1.431", cm.evaluate(JsclOperation.numeric, "log(5, 10)").getResult());
+ Assert.assertEquals("0.96", cm.evaluate(JsclOperation.numeric, "log(11, 10)").getResult());
+ Assert.assertEquals("1/(bln(a))", cm.evaluate(JsclOperation.simplify, "∂(log(a, b), b)").getResult());
+ Assert.assertEquals("-ln(b)/(aln(a)^2)", cm.evaluate(JsclOperation.simplify, "∂(log(a, b), a)").getResult());
+
+ }
+}
diff --git a/calculatorpp/src/test/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessorTest.java b/calculatorpp/src/test/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessorTest.java
index ad630885..a52ee3af 100644
--- a/calculatorpp/src/test/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessorTest.java
+++ b/calculatorpp/src/test/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessorTest.java
@@ -1,69 +1,70 @@
-package org.solovyev.android.calculator.model;
-
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.text.DecimalFormatSymbols;
-
-/**
- * User: serso
- * Date: 10/20/11
- * Time: 3:43 PM
- */
-public class FromJsclSimplifyTextProcessorTest {
-
- @BeforeClass
- public static void setUp() throws Exception {
- CalculatorEngine.instance.init(null, null);
- }
-
- @Test
- public void testProcess() throws Exception {
- FromJsclSimplifyTextProcessor tp = new FromJsclSimplifyTextProcessor();
- //Assert.assertEquals("(e)", tp.process("(2.718281828459045)"));
- //Assert.assertEquals("ee", tp.process("2.718281828459045*2.718281828459045"));
- //Assert.assertEquals("((e)(e))", tp.process("((2.718281828459045)*(2.718281828459045))"));
- DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols();
- decimalGroupSymbols.setGroupingSeparator(' ');
- CalculatorEngine.instance.setDecimalGroupSymbols(decimalGroupSymbols);
- //Assert.assertEquals("123 456 789e", tp.process("123456789*2.718281828459045"));
- //Assert.assertEquals("123 456 789e", tp.process("123 456 789 * 2.718281828459045"));
- //Assert.assertEquals("t11e", tp.process("t11*2.718281828459045"));
- //Assert.assertEquals("e", tp.process("2.718281828459045"));
- //Assert.assertEquals("tee", tp.process("t2.718281828459045*2.718281828459045"));
-
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t2.718281828459045", "2"));
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", (String)null));
- //Assert.assertEquals("t2.718281828459045e", tp.process("t2.718281828459045*2.718281828459045"));
- //Assert.assertEquals("ee", tp.process("2.718281828459045*2.718281828459045"));
- Assert.assertEquals("t×", tp.process("t*"));
- Assert.assertEquals("×t", tp.process("*t"));
- Assert.assertEquals("t2", tp.process("t*2"));
- Assert.assertEquals("2t", tp.process("2*t"));
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", (String) null));
- Assert.assertEquals("t×", tp.process("t*"));
- Assert.assertEquals("×t", tp.process("*t"));
-
- Assert.assertEquals("t2", tp.process("t*2"));
- Assert.assertEquals("2t", tp.process("2*t"));
-
- Assert.assertEquals("t^2×2", tp.process("t^2*2"));
- Assert.assertEquals("2t^2", tp.process("2*t^2"));
-
- Assert.assertEquals("t^[2×2t]", tp.process("t^[2*2*t]"));
- Assert.assertEquals("2t^2[2t]", tp.process("2*t^2[2*t]"));
-
- CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("k", (String) null));
- Assert.assertEquals("(t+2k)[k+2t]", tp.process("(t+2*k)*[k+2*t]"));
- Assert.assertEquals("(te+2k)e[k+2te]", tp.process("(t*e+2*k)*e*[k+2*t*e]"));
-
-
- Assert.assertEquals("tlog(3)", tp.process("t*log(3)"));
- Assert.assertEquals("t√(3)", tp.process("t*√(3)"));
- Assert.assertEquals("20x", tp.process("20*x"));
- Assert.assertEquals("20x", tp.process("20x"));
- Assert.assertEquals("2×0x3", tp.process("2*0x3"));
- Assert.assertEquals("2×0x:3", tp.process("2*0x:3"));
- }
-}
+package org.solovyev.android.calculator.model;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.solovyev.android.calculator.text.FromJsclSimplifyTextProcessor;
+
+import java.text.DecimalFormatSymbols;
+
+/**
+ * User: serso
+ * Date: 10/20/11
+ * Time: 3:43 PM
+ */
+public class FromJsclSimplifyTextProcessorTest {
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ CalculatorEngine.instance.init(null, null);
+ }
+
+ @Test
+ public void testProcess() throws Exception {
+ FromJsclSimplifyTextProcessor tp = new FromJsclSimplifyTextProcessor();
+ //Assert.assertEquals("(e)", tp.process("(2.718281828459045)"));
+ //Assert.assertEquals("ee", tp.process("2.718281828459045*2.718281828459045"));
+ //Assert.assertEquals("((e)(e))", tp.process("((2.718281828459045)*(2.718281828459045))"));
+ DecimalFormatSymbols decimalGroupSymbols = new DecimalFormatSymbols();
+ decimalGroupSymbols.setGroupingSeparator(' ');
+ CalculatorEngine.instance.setDecimalGroupSymbols(decimalGroupSymbols);
+ //Assert.assertEquals("123 456 789e", tp.process("123456789*2.718281828459045"));
+ //Assert.assertEquals("123 456 789e", tp.process("123 456 789 * 2.718281828459045"));
+ //Assert.assertEquals("t11e", tp.process("t11*2.718281828459045"));
+ //Assert.assertEquals("e", tp.process("2.718281828459045"));
+ //Assert.assertEquals("tee", tp.process("t2.718281828459045*2.718281828459045"));
+
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t2.718281828459045", "2"));
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", (String)null));
+ //Assert.assertEquals("t2.718281828459045e", tp.process("t2.718281828459045*2.718281828459045"));
+ //Assert.assertEquals("ee", tp.process("2.718281828459045*2.718281828459045"));
+ Assert.assertEquals("t×", tp.process("t*"));
+ Assert.assertEquals("×t", tp.process("*t"));
+ Assert.assertEquals("t2", tp.process("t*2"));
+ Assert.assertEquals("2t", tp.process("2*t"));
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("t", (String) null));
+ Assert.assertEquals("t×", tp.process("t*"));
+ Assert.assertEquals("×t", tp.process("*t"));
+
+ Assert.assertEquals("t2", tp.process("t*2"));
+ Assert.assertEquals("2t", tp.process("2*t"));
+
+ Assert.assertEquals("t^2×2", tp.process("t^2*2"));
+ Assert.assertEquals("2t^2", tp.process("2*t^2"));
+
+ Assert.assertEquals("t^[2×2t]", tp.process("t^[2*2*t]"));
+ Assert.assertEquals("2t^2[2t]", tp.process("2*t^2[2*t]"));
+
+ CalculatorEngine.instance.getVarsRegistry().add(new Var.Builder("k", (String) null));
+ Assert.assertEquals("(t+2k)[k+2t]", tp.process("(t+2*k)*[k+2*t]"));
+ Assert.assertEquals("(te+2k)e[k+2te]", tp.process("(t*e+2*k)*e*[k+2*t*e]"));
+
+
+ Assert.assertEquals("tlog(3)", tp.process("t*log(3)"));
+ Assert.assertEquals("t√(3)", tp.process("t*√(3)"));
+ Assert.assertEquals("20x", tp.process("20*x"));
+ Assert.assertEquals("20x", tp.process("20x"));
+ Assert.assertEquals("2×0x3", tp.process("2*0x3"));
+ Assert.assertEquals("2×0x:3", tp.process("2*0x:3"));
+ }
+}
diff --git a/calculatorpp/src/test/java/org/solovyev/android/calculator/model/NumeralBaseTest.java b/calculatorpp/src/test/java/org/solovyev/android/calculator/model/NumeralBaseTest.java
index 6eb893c1..b7046569 100644
--- a/calculatorpp/src/test/java/org/solovyev/android/calculator/model/NumeralBaseTest.java
+++ b/calculatorpp/src/test/java/org/solovyev/android/calculator/model/NumeralBaseTest.java
@@ -1,146 +1,147 @@
-package org.solovyev.android.calculator.model;
-
-import au.com.bytecode.opencsv.CSVReader;
-import jscl.JsclMathEngine;
-import jscl.MathEngine;
-import jscl.math.Expression;
-import jscl.text.ParseException;
-import jscl.util.ExpressionGeneratorWithInput;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.solovyev.android.calculator.jscl.JsclOperation;
-import org.solovyev.common.Converter;
-
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * User: serso
- * Date: 12/14/11
- * Time: 4:16 PM
- */
-public class NumeralBaseTest {
-
- @BeforeClass
- public static void setUp() throws Exception {
- CalculatorEngine.instance.init(null, null);
- CalculatorEngine.instance.setPrecision(3);
- CalculatorEngine.instance.setThreadKiller(new CalculatorEngine.ThreadKillerImpl());
- }
-
- @Test
- public void testConversion() throws Exception {
- CSVReader reader = null;
- try {
- final MathEngine me = JsclMathEngine.instance;
-
- reader = new CSVReader(new InputStreamReader(NumeralBaseTest.class.getResourceAsStream("/org/solovyev/android/calculator/model/nb_table.csv")), '\t');
-
- // skip first line
- reader.readNext();
-
- String[] line = reader.readNext();
- for (; line != null; line = reader.readNext()) {
- testExpression(line, new DummyExpression());
- testExpression(line, new Expression1());
- testExpression(line, new Expression2());
- testExpression(line, new Expression3());
-
- final String dec = line[0].toUpperCase();
- final String hex = "0x:" + line[1].toUpperCase();
- final String bin = "0b:" + line[2].toUpperCase();
-
- final List input = new ArrayList();
- input.add(dec);
- input.add(hex);
- input.add(bin);
-
- //System.out.println("Dec: " + dec);
- //System.out.println("Hex: " + hex);
- //System.out.println("Bin: " + bin);
-
- final ExpressionGeneratorWithInput eg = new ExpressionGeneratorWithInput(input, 20);
- final List expressions = eg.generate();
-
- final String decExpression = expressions.get(0);
- final String hexExpression = expressions.get(1);
- final String binExpression = expressions.get(2);
-
- //System.out.println("Dec expression: " + decExpression);
- //System.out.println("Hex expression: " + hexExpression);
- //System.out.println("Bin expression: " + binExpression);
-
- final String decResult = Expression.valueOf(decExpression).numeric().toString();
- //System.out.println("Dec result: " + decResult);
-
- final String hexResult = Expression.valueOf(hexExpression).numeric().toString();
- //System.out.println("Hex result: " + hexResult);
-
- final String binResult = Expression.valueOf(binExpression).numeric().toString();
- //System.out.println("Bin result: " + binResult);
-
- Assert.assertEquals("dec-hex: " + decExpression + " : " + hexExpression, decResult, hexResult);
- Assert.assertEquals("dec-bin: " + decExpression + " : " + binExpression, decResult, binResult);
- }
- } finally {
- if (reader != null) {
- reader.close();
- }
- }
- }
-
- public static void testExpression(@NotNull String[] line, @NotNull Converter converter) throws ParseException, CalculatorEvalException, CalculatorParseException {
- final String dec = line[0].toUpperCase();
- final String hex = "0x:" + line[1].toUpperCase();
- final String bin = "0b:" + line[2].toUpperCase();
-
- final String decExpression = converter.convert(dec);
- final String decResult = CalculatorEngine.instance.evaluate(JsclOperation.numeric, decExpression).getResult();
- final String hexExpression = converter.convert(hex);
- final String hexResult = CalculatorEngine.instance.evaluate(JsclOperation.numeric, hexExpression).getResult();
- final String binExpression = converter.convert(bin);
- final String binResult = CalculatorEngine.instance.evaluate(JsclOperation.numeric, binExpression).getResult();
-
- Assert.assertEquals("dec-hex: " + decExpression + " : " + hexExpression, decResult, hexResult);
- Assert.assertEquals("dec-bin: " + decExpression + " : " + binExpression, decResult, binResult);
- }
-
- private static class DummyExpression implements Converter {
-
- @NotNull
- @Override
- public String convert(@NotNull String s) {
- return s;
- }
- }
-
- private static class Expression1 implements Converter {
-
- @NotNull
- @Override
- public String convert(@NotNull String s) {
- return s + "*" + s;
- }
- }
-
- private static class Expression2 implements Converter {
-
- @NotNull
- @Override
- public String convert(@NotNull String s) {
- return s + "*" + s + " * sin(" + s + ") - 0b:1101";
- }
- }
-
- private static class Expression3 implements Converter {
-
- @NotNull
- @Override
- public String convert(@NotNull String s) {
- return s + "*" + s + " * sin(" + s + ") - 0b:1101 + √(" + s + ") + exp ( " + s + ")";
- }
- }
-}
+package org.solovyev.android.calculator.model;
+
+import au.com.bytecode.opencsv.CSVReader;
+import jscl.JsclMathEngine;
+import jscl.MathEngine;
+import jscl.math.Expression;
+import jscl.text.ParseException;
+import jscl.util.ExpressionGeneratorWithInput;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.solovyev.android.calculator.CalculatorParseException;
+import org.solovyev.android.calculator.jscl.JsclOperation;
+import org.solovyev.common.Converter;
+
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: serso
+ * Date: 12/14/11
+ * Time: 4:16 PM
+ */
+public class NumeralBaseTest {
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ CalculatorEngine.instance.init(null, null);
+ CalculatorEngine.instance.setPrecision(3);
+ CalculatorEngine.instance.setThreadKiller(new CalculatorEngine.ThreadKillerImpl());
+ }
+
+ @Test
+ public void testConversion() throws Exception {
+ CSVReader reader = null;
+ try {
+ final MathEngine me = JsclMathEngine.instance;
+
+ reader = new CSVReader(new InputStreamReader(NumeralBaseTest.class.getResourceAsStream("/org/solovyev/android/calculator/model/nb_table.csv")), '\t');
+
+ // skip first line
+ reader.readNext();
+
+ String[] line = reader.readNext();
+ for (; line != null; line = reader.readNext()) {
+ testExpression(line, new DummyExpression());
+ testExpression(line, new Expression1());
+ testExpression(line, new Expression2());
+ testExpression(line, new Expression3());
+
+ final String dec = line[0].toUpperCase();
+ final String hex = "0x:" + line[1].toUpperCase();
+ final String bin = "0b:" + line[2].toUpperCase();
+
+ final List input = new ArrayList();
+ input.add(dec);
+ input.add(hex);
+ input.add(bin);
+
+ //System.out.println("Dec: " + dec);
+ //System.out.println("Hex: " + hex);
+ //System.out.println("Bin: " + bin);
+
+ final ExpressionGeneratorWithInput eg = new ExpressionGeneratorWithInput(input, 20);
+ final List expressions = eg.generate();
+
+ final String decExpression = expressions.get(0);
+ final String hexExpression = expressions.get(1);
+ final String binExpression = expressions.get(2);
+
+ //System.out.println("Dec expression: " + decExpression);
+ //System.out.println("Hex expression: " + hexExpression);
+ //System.out.println("Bin expression: " + binExpression);
+
+ final String decResult = Expression.valueOf(decExpression).numeric().toString();
+ //System.out.println("Dec result: " + decResult);
+
+ final String hexResult = Expression.valueOf(hexExpression).numeric().toString();
+ //System.out.println("Hex result: " + hexResult);
+
+ final String binResult = Expression.valueOf(binExpression).numeric().toString();
+ //System.out.println("Bin result: " + binResult);
+
+ Assert.assertEquals("dec-hex: " + decExpression + " : " + hexExpression, decResult, hexResult);
+ Assert.assertEquals("dec-bin: " + decExpression + " : " + binExpression, decResult, binResult);
+ }
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ }
+
+ public static void testExpression(@NotNull String[] line, @NotNull Converter converter) throws ParseException, CalculatorEvalException, CalculatorParseException {
+ final String dec = line[0].toUpperCase();
+ final String hex = "0x:" + line[1].toUpperCase();
+ final String bin = "0b:" + line[2].toUpperCase();
+
+ final String decExpression = converter.convert(dec);
+ final String decResult = CalculatorEngine.instance.evaluate(JsclOperation.numeric, decExpression).getResult();
+ final String hexExpression = converter.convert(hex);
+ final String hexResult = CalculatorEngine.instance.evaluate(JsclOperation.numeric, hexExpression).getResult();
+ final String binExpression = converter.convert(bin);
+ final String binResult = CalculatorEngine.instance.evaluate(JsclOperation.numeric, binExpression).getResult();
+
+ Assert.assertEquals("dec-hex: " + decExpression + " : " + hexExpression, decResult, hexResult);
+ Assert.assertEquals("dec-bin: " + decExpression + " : " + binExpression, decResult, binResult);
+ }
+
+ private static class DummyExpression implements Converter {
+
+ @NotNull
+ @Override
+ public String convert(@NotNull String s) {
+ return s;
+ }
+ }
+
+ private static class Expression1 implements Converter {
+
+ @NotNull
+ @Override
+ public String convert(@NotNull String s) {
+ return s + "*" + s;
+ }
+ }
+
+ private static class Expression2 implements Converter {
+
+ @NotNull
+ @Override
+ public String convert(@NotNull String s) {
+ return s + "*" + s + " * sin(" + s + ") - 0b:1101";
+ }
+ }
+
+ private static class Expression3 implements Converter {
+
+ @NotNull
+ @Override
+ public String convert(@NotNull String s) {
+ return s + "*" + s + " * sin(" + s + ") - 0b:1101 + √(" + s + ") + exp ( " + s + ")";
+ }
+ }
+}
diff --git a/calculatorpp/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java b/calculatorpp/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java
index e1f92a65..57f2bb1d 100644
--- a/calculatorpp/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java
+++ b/calculatorpp/src/test/java/org/solovyev/android/calculator/model/ToJsclTextProcessorTest.java
@@ -1,161 +1,163 @@
-/*
- * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
- * For more information, please, contact se.solovyev@gmail.com
- * or visit http://se.solovyev.org
- */
-
-package org.solovyev.android.calculator.model;
-
-import jscl.JsclMathEngine;
-import jscl.NumeralBase;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * User: serso
- * Date: 9/26/11
- * Time: 12:13 PM
- */
-public class ToJsclTextProcessorTest {
-
- @BeforeClass
- public static void setUp() throws Exception {
- CalculatorEngine.instance.init(null, null);
- }
-
- @Test
- public void testSpecialCases() throws CalculatorParseException {
- final TextProcessor preprocessor = ToJsclTextProcessor.getInstance();
- Assert.assertEquals( "3^E10", preprocessor.process("3^E10").toString());
- }
-
- @Test
- public void testProcess() throws Exception {
- final TextProcessor preprocessor = ToJsclTextProcessor.getInstance();
-
- Assert.assertEquals( "", preprocessor.process("").toString());
- Assert.assertEquals( "()", preprocessor.process("[]").toString());
- Assert.assertEquals( "()*()", preprocessor.process("[][]").toString());
- Assert.assertEquals( "()*(1)", preprocessor.process("[][1]").toString());
- Assert.assertEquals( "(0)*(1)", preprocessor.process("[0][1]").toString());
- Assert.assertEquals( "(0)*(1E)", preprocessor.process("[0][1E]").toString());
- Assert.assertEquals( "(0)*(1E1)", preprocessor.process("[0][1E1]").toString());
- Assert.assertEquals( "(0)*(1E-1)", preprocessor.process("[0][1E-1]").toString());
- Assert.assertEquals( "(0)*(1.E-1)", preprocessor.process("[0][1.E-1]").toString());
- Assert.assertEquals( "(0)*(2*E-1)", preprocessor.process("[0][2*E-1]").toString());
- Assert.assertEquals( "(0)*ln(1)*(2*E-1)", preprocessor.process("[0]ln(1)[2*E-1]").toString());
- Assert.assertEquals( "sin(4)*asin(0.5)*√(2)", preprocessor.process("sin(4)asin(0.5)√(2)").toString());
- Assert.assertEquals( "sin(4)*cos(5)", preprocessor.process("sin(4)cos(5)").toString());
- Assert.assertEquals( "π*sin(4)*π*cos(√(5))", preprocessor.process("πsin(4)πcos(√(5))").toString());
- Assert.assertEquals( "π*sin(4)+π*cos(√(5))", preprocessor.process("πsin(4)+πcos(√(5))").toString());
- Assert.assertEquals( "π*sin(4)+π*cos(√(5+(√(-1))))", preprocessor.process("πsin(4)+πcos(√(5+i))").toString());
- Assert.assertEquals( "π*sin(4.01)+π*cos(√(5+(√(-1))))", preprocessor.process("πsin(4.01)+πcos(√(5+i))").toString());
- Assert.assertEquals( "e^π*sin(4.01)+π*cos(√(5+(√(-1))))", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))").toString());
- Assert.assertEquals( "e^π*sin(4.01)+π*cos(√(5+(√(-1))))E2", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))E2").toString());
- Assert.assertEquals( "e^π*sin(4.01)+π*cos(√(5+(√(-1))))E-2", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))E-2").toString());
- Assert.assertEquals( "E2", preprocessor.process("E2").toString());
- Assert.assertEquals( "E-2", preprocessor.process("E-2").toString());
- Assert.assertEquals( "E-1/2", preprocessor.process("E-1/2").toString());
- Assert.assertEquals( "E-1.2", preprocessor.process("E-1.2").toString());
- Assert.assertEquals( "E+1.2", preprocessor.process("E+1.2").toString());
- Assert.assertEquals( "E(-1.2)", preprocessor.process("E(-1.2)").toString());
- Assert.assertEquals( "EE", preprocessor.process("EE").toString());
-
- try {
- CalculatorEngine.instance.getEngine().setNumeralBase(NumeralBase.hex);
- Assert.assertEquals( "22F*exp(F)", preprocessor.process("22Fexp(F)").toString());
- } finally {
- CalculatorEngine.instance.getEngine().setNumeralBase(NumeralBase.dec);
- }
- 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());
- Assert.assertEquals( "0x:ABCDEF*0*x", preprocessor.process("0x:A BC DEF*0x").toString());
- Assert.assertEquals( "0x:ABCDEF001*0*x", preprocessor.process("0x:A BC DEF001*0x").toString());
- Assert.assertEquals( "0x:ABCDEF001*0*c", preprocessor.process("0x:A BC DEF001*0c").toString());
- Assert.assertEquals( "0x:ABCDEF001*c", preprocessor.process("0x:A BC DEF001*c").toString());
- Assert.assertEquals( "0b:1101", preprocessor.process("0b:1101").toString());
- Assert.assertEquals( "0x:1C", preprocessor.process("0x:1C").toString());
- Assert.assertEquals( "0x:1C", preprocessor.process(" 0x:1C").toString());
- Assert.assertEquals( "0x:1C*0x:1C*sin(0x:1C)-0b:1101+√(0x:1C)+exp(0x:1C)", preprocessor.process("0x:1C*0x:1C * sin(0x:1C) - 0b:1101 + √(0x:1C) + exp ( 0x:1C)").toString());
- Assert.assertEquals( "0x:1C*0x:1C*sin(0x:1C)-0b:1101+√(0x:1C)+exp(0x:1C)", preprocessor.process("0x:1C*0x:1C * sin(0x:1C) - 0b:1101 + √(0x:1C) + exp ( 0x:1C)").toString());
-
- try {
- preprocessor.process("ln()");
- Assert.fail();
- } catch (CalculatorParseException e) {
- }
- try {
- preprocessor.process("ln()ln()");
- Assert.fail();
- } catch (CalculatorParseException e) {
- }
-
- try {
- preprocessor.process("eln()eln()ln()ln()ln()e");
- Assert.fail();
- } catch (CalculatorParseException e) {
- }
-
- try {
- preprocessor.process("ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln()))))))))))))))");
- Assert.fail();
- } catch (CalculatorParseException e) {
- }
-
- try {
- preprocessor.process("cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos(cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos())))))))))))))))))))))))))))))))))))))");
- Assert.fail();
- } catch (CalculatorParseException e) {
- }
- }
-
- @Test
- public void testDegrees() throws Exception {
- final TextProcessor preprocessor = ToJsclTextProcessor.getInstance();
-
- Assert.assertEquals( "", preprocessor.process("").toString());
- /* try {
- Assert.assertEquals( "π/180", preprocessor.process("°").toString());
- } catch (ParseException e) {
- if ( !e.getMessage().startsWith("Could not find start of prefix") ){
- junit.framework.Assert.fail();
- }
- }
- Assert.assertEquals( "1*π/180", preprocessor.process("1°").toString());
- Assert.assertEquals( "20.0*π/180", preprocessor.process("20.0°").toString());
- Assert.assertEquals( "sin(30*π/180)", preprocessor.process("sin(30°)").toString());
- Assert.assertEquals( "asin(sin(π/6))*π/180", preprocessor.process("asin(sin(π/6))°").toString());
- Assert.assertEquals( "1*π/180*sin(1)", preprocessor.process("1°sin(1)").toString());
- try {
- Assert.assertEquals( "1*π/180^sin(1)", preprocessor.process("1°^sin(1)").toString());
- junit.framework.Assert.fail();
- } catch (ParseException e) {
- if ( !e.getMessage().equals("Power operation after postfix function is currently unsupported!") ) {
- junit.framework.Assert.fail();
- }
- }*/
-
- }
-
- @Test
- public void testPostfixFunction() throws Exception {
- }
-
- @Test
- public void testNumeralBases() throws Exception {
- final TextProcessor processor = ToJsclTextProcessor.getInstance();
-
- final NumeralBase defaultNumeralBase = JsclMathEngine.instance.getNumeralBase();
- try{
- JsclMathEngine.instance.setNumeralBase(NumeralBase.bin);
- Assert.assertEquals("101", JsclMathEngine.instance.evaluate("10+11"));
-
- JsclMathEngine.instance.setNumeralBase(NumeralBase.hex);
- Assert.assertEquals("56CE+CAD", processor.process("56CE+CAD").getExpression());
- } finally {
- JsclMathEngine.instance.setNumeralBase(defaultNumeralBase);
- }
- }
-}
+/*
+ * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
+ * For more information, please, contact se.solovyev@gmail.com
+ * or visit http://se.solovyev.org
+ */
+
+package org.solovyev.android.calculator.model;
+
+import jscl.JsclMathEngine;
+import jscl.NumeralBase;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.solovyev.android.calculator.CalculatorParseException;
+import org.solovyev.android.calculator.text.TextProcessor;
+
+/**
+ * User: serso
+ * Date: 9/26/11
+ * Time: 12:13 PM
+ */
+public class ToJsclTextProcessorTest {
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ CalculatorEngine.instance.init(null, null);
+ }
+
+ @Test
+ public void testSpecialCases() throws CalculatorParseException {
+ final TextProcessor preprocessor = ToJsclTextProcessor.getInstance();
+ Assert.assertEquals( "3^E10", preprocessor.process("3^E10").toString());
+ }
+
+ @Test
+ public void testProcess() throws Exception {
+ final TextProcessor preprocessor = ToJsclTextProcessor.getInstance();
+
+ Assert.assertEquals( "", preprocessor.process("").toString());
+ Assert.assertEquals( "()", preprocessor.process("[]").toString());
+ Assert.assertEquals( "()*()", preprocessor.process("[][]").toString());
+ Assert.assertEquals( "()*(1)", preprocessor.process("[][1]").toString());
+ Assert.assertEquals( "(0)*(1)", preprocessor.process("[0][1]").toString());
+ Assert.assertEquals( "(0)*(1E)", preprocessor.process("[0][1E]").toString());
+ Assert.assertEquals( "(0)*(1E1)", preprocessor.process("[0][1E1]").toString());
+ Assert.assertEquals( "(0)*(1E-1)", preprocessor.process("[0][1E-1]").toString());
+ Assert.assertEquals( "(0)*(1.E-1)", preprocessor.process("[0][1.E-1]").toString());
+ Assert.assertEquals( "(0)*(2*E-1)", preprocessor.process("[0][2*E-1]").toString());
+ Assert.assertEquals( "(0)*ln(1)*(2*E-1)", preprocessor.process("[0]ln(1)[2*E-1]").toString());
+ Assert.assertEquals( "sin(4)*asin(0.5)*√(2)", preprocessor.process("sin(4)asin(0.5)√(2)").toString());
+ Assert.assertEquals( "sin(4)*cos(5)", preprocessor.process("sin(4)cos(5)").toString());
+ Assert.assertEquals( "π*sin(4)*π*cos(√(5))", preprocessor.process("πsin(4)πcos(√(5))").toString());
+ Assert.assertEquals( "π*sin(4)+π*cos(√(5))", preprocessor.process("πsin(4)+πcos(√(5))").toString());
+ Assert.assertEquals( "π*sin(4)+π*cos(√(5+(√(-1))))", preprocessor.process("πsin(4)+πcos(√(5+i))").toString());
+ Assert.assertEquals( "π*sin(4.01)+π*cos(√(5+(√(-1))))", preprocessor.process("πsin(4.01)+πcos(√(5+i))").toString());
+ Assert.assertEquals( "e^π*sin(4.01)+π*cos(√(5+(√(-1))))", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))").toString());
+ Assert.assertEquals( "e^π*sin(4.01)+π*cos(√(5+(√(-1))))E2", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))E2").toString());
+ Assert.assertEquals( "e^π*sin(4.01)+π*cos(√(5+(√(-1))))E-2", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))E-2").toString());
+ Assert.assertEquals( "E2", preprocessor.process("E2").toString());
+ Assert.assertEquals( "E-2", preprocessor.process("E-2").toString());
+ Assert.assertEquals( "E-1/2", preprocessor.process("E-1/2").toString());
+ Assert.assertEquals( "E-1.2", preprocessor.process("E-1.2").toString());
+ Assert.assertEquals( "E+1.2", preprocessor.process("E+1.2").toString());
+ Assert.assertEquals( "E(-1.2)", preprocessor.process("E(-1.2)").toString());
+ Assert.assertEquals( "EE", preprocessor.process("EE").toString());
+
+ try {
+ CalculatorEngine.instance.getEngine().setNumeralBase(NumeralBase.hex);
+ Assert.assertEquals( "22F*exp(F)", preprocessor.process("22Fexp(F)").toString());
+ } finally {
+ CalculatorEngine.instance.getEngine().setNumeralBase(NumeralBase.dec);
+ }
+ 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());
+ Assert.assertEquals( "0x:ABCDEF*0*x", preprocessor.process("0x:A BC DEF*0x").toString());
+ Assert.assertEquals( "0x:ABCDEF001*0*x", preprocessor.process("0x:A BC DEF001*0x").toString());
+ Assert.assertEquals( "0x:ABCDEF001*0*c", preprocessor.process("0x:A BC DEF001*0c").toString());
+ Assert.assertEquals( "0x:ABCDEF001*c", preprocessor.process("0x:A BC DEF001*c").toString());
+ Assert.assertEquals( "0b:1101", preprocessor.process("0b:1101").toString());
+ Assert.assertEquals( "0x:1C", preprocessor.process("0x:1C").toString());
+ Assert.assertEquals( "0x:1C", preprocessor.process(" 0x:1C").toString());
+ Assert.assertEquals( "0x:1C*0x:1C*sin(0x:1C)-0b:1101+√(0x:1C)+exp(0x:1C)", preprocessor.process("0x:1C*0x:1C * sin(0x:1C) - 0b:1101 + √(0x:1C) + exp ( 0x:1C)").toString());
+ Assert.assertEquals( "0x:1C*0x:1C*sin(0x:1C)-0b:1101+√(0x:1C)+exp(0x:1C)", preprocessor.process("0x:1C*0x:1C * sin(0x:1C) - 0b:1101 + √(0x:1C) + exp ( 0x:1C)").toString());
+
+ try {
+ preprocessor.process("ln()");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ }
+ try {
+ preprocessor.process("ln()ln()");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ }
+
+ try {
+ preprocessor.process("eln()eln()ln()ln()ln()e");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ }
+
+ try {
+ preprocessor.process("ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln(ln()))))))))))))))");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ }
+
+ try {
+ preprocessor.process("cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos(cos(cos(cos(cos(acos(acos(acos(acos(acos(acos(acos(acos(cos(cos(cos(cos(cosh(acos(cos())))))))))))))))))))))))))))))))))))))");
+ Assert.fail();
+ } catch (CalculatorParseException e) {
+ }
+ }
+
+ @Test
+ public void testDegrees() throws Exception {
+ final TextProcessor preprocessor = ToJsclTextProcessor.getInstance();
+
+ Assert.assertEquals( "", preprocessor.process("").toString());
+ /* try {
+ Assert.assertEquals( "π/180", preprocessor.process("°").toString());
+ } catch (ParseException e) {
+ if ( !e.getMessage().startsWith("Could not find start of prefix") ){
+ junit.framework.Assert.fail();
+ }
+ }
+ Assert.assertEquals( "1*π/180", preprocessor.process("1°").toString());
+ Assert.assertEquals( "20.0*π/180", preprocessor.process("20.0°").toString());
+ Assert.assertEquals( "sin(30*π/180)", preprocessor.process("sin(30°)").toString());
+ Assert.assertEquals( "asin(sin(π/6))*π/180", preprocessor.process("asin(sin(π/6))°").toString());
+ Assert.assertEquals( "1*π/180*sin(1)", preprocessor.process("1°sin(1)").toString());
+ try {
+ Assert.assertEquals( "1*π/180^sin(1)", preprocessor.process("1°^sin(1)").toString());
+ junit.framework.Assert.fail();
+ } catch (ParseException e) {
+ if ( !e.getMessage().equals("Power operation after postfix function is currently unsupported!") ) {
+ junit.framework.Assert.fail();
+ }
+ }*/
+
+ }
+
+ @Test
+ public void testPostfixFunction() throws Exception {
+ }
+
+ @Test
+ public void testNumeralBases() throws Exception {
+ final TextProcessor processor = ToJsclTextProcessor.getInstance();
+
+ final NumeralBase defaultNumeralBase = JsclMathEngine.instance.getNumeralBase();
+ try{
+ JsclMathEngine.instance.setNumeralBase(NumeralBase.bin);
+ Assert.assertEquals("101", JsclMathEngine.instance.evaluate("10+11"));
+
+ JsclMathEngine.instance.setNumeralBase(NumeralBase.hex);
+ Assert.assertEquals("56CE+CAD", processor.process("56CE+CAD").getExpression());
+ } finally {
+ JsclMathEngine.instance.setNumeralBase(defaultNumeralBase);
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 041abf06..61bbd3f4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -122,6 +122,22 @@
11.0.2
+
+ org.simpleframework
+ simple-xml
+ 2.6.1
+
+
+ stax-api
+ stax
+
+
+ xpp3
+ xpp3
+
+
+
+