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(""); - 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(""); + 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 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 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 + + + +