diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java new file mode 100644 index 00000000..32d89298 --- /dev/null +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java @@ -0,0 +1,19 @@ +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: Solovyev_S + * Date: 21.09.12 + * Time: 11:47 + */ +public interface CalculatorEditor extends CalculatorEventListener/*, CursorControl*/ { + + void setView(@Nullable CalculatorEditorView view); + + @NotNull + CalculatorEditorViewState getViewState(); + + void setViewState(@NotNull CalculatorEditorViewState viewState); +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorImpl.java new file mode 100644 index 00000000..04b6590c --- /dev/null +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorImpl.java @@ -0,0 +1,87 @@ +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: Solovyev_S + * Date: 21.09.12 + * Time: 11:53 + */ +public class CalculatorEditorImpl implements CalculatorEditor { + + @Nullable + private CalculatorEditorView view; + + @NotNull + private final Object viewLock = new Object(); + + @NotNull + private CalculatorEditorViewState lastViewState = CalculatorEditorViewStateImpl.newDefaultInstance(); + + @Override + public void setView(@Nullable CalculatorEditorView view) { + synchronized (viewLock) { + this.view = view; + + if ( view != null ) { + view.setState(lastViewState); + } + } + } + + @NotNull + @Override + public CalculatorEditorViewState getViewState() { + return lastViewState; + } + + @Override + public void setViewState(@NotNull CalculatorEditorViewState viewState) { + synchronized (viewLock) { + this.lastViewState = viewState; + if (this.view != null) { + this.view.setState(viewState); + } + } + } + + @Override + public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, + @NotNull CalculatorEventType calculatorEventType, + @Nullable Object data) { + //To change body of implemented methods use File | Settings | File Templates. + } + + public void setCursorOnStart() { + synchronized (viewLock) { + newSelectionViewState(0); + } + } + + private void newSelectionViewState(int newSelection) { + setViewState(CalculatorEditorViewStateImpl.newSelection(this.lastViewState, newSelection)); + } + + public void setCursorOnEnd() { + synchronized (viewLock) { + newSelectionViewState(this.lastViewState.getText().length()); + } + } + + public void moveCursorLeft() { + synchronized (viewLock) { + if (this.lastViewState.getSelection() > 0) { + newSelectionViewState(this.lastViewState.getSelection() - 1); + } + } + } + + public void moveCursorRight() { + synchronized (viewLock) { + if (this.lastViewState.getSelection() < this.lastViewState.getText().length()) { + newSelectionViewState(this.lastViewState.getSelection() + 1); + } + } + } +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorView.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorView.java new file mode 100644 index 00000000..c6587997 --- /dev/null +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorView.java @@ -0,0 +1,13 @@ +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; + +/** + * User: Solovyev_S + * Date: 21.09.12 + * Time: 11:48 + */ +public interface CalculatorEditorView { + + void setState(@NotNull CalculatorEditorViewState viewState); +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorViewState.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorViewState.java new file mode 100644 index 00000000..1189957e --- /dev/null +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorViewState.java @@ -0,0 +1,16 @@ +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; + +/** + * User: Solovyev_S + * Date: 21.09.12 + * Time: 11:48 + */ +public interface CalculatorEditorViewState { + + @NotNull + String getText(); + + int getSelection(); +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorViewStateImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorViewStateImpl.java new file mode 100644 index 00000000..2cc03f0e --- /dev/null +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEditorViewStateImpl.java @@ -0,0 +1,49 @@ +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; + +/** + * User: Solovyev_S + * Date: 21.09.12 + * Time: 12:02 + */ +public class CalculatorEditorViewStateImpl implements CalculatorEditorViewState { + + @NotNull + private String text = ""; + + private int selection = 0; + + private CalculatorEditorViewStateImpl() { + } + + public CalculatorEditorViewStateImpl(@NotNull CalculatorEditorViewState viewState) { + this.text = viewState.getText(); + this.selection = viewState.getSelection(); + } + + @NotNull + @Override + public String getText() { + return this.text; + } + + @Override + public int getSelection() { + return this.selection; + } + + @NotNull + public static CalculatorEditorViewState newDefaultInstance() { + return new CalculatorEditorViewStateImpl(); + } + + @NotNull + public static CalculatorEditorViewState newSelection(@NotNull CalculatorEditorViewState viewState, int newSelection) { + final CalculatorEditorViewStateImpl result = new CalculatorEditorViewStateImpl(viewState); + + result.selection = newSelection; + + return result; + } +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEvaluationEventDataImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEvaluationEventDataImpl.java index 9df965a0..5feae068 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEvaluationEventDataImpl.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEvaluationEventDataImpl.java @@ -1,58 +1,63 @@ -package org.solovyev.android.calculator; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.solovyev.android.calculator.jscl.JsclOperation; - -/** - * User: serso - * Date: 9/20/12 - * Time: 10:01 PM - */ -public class CalculatorEvaluationEventDataImpl implements CalculatorEvaluationEventData { - - @NotNull - private final CalculatorEventData calculatorEventData; - - @NotNull - private final JsclOperation operation; - - @NotNull - private final String expression; - - public CalculatorEvaluationEventDataImpl(@NotNull CalculatorEventData calculatorEventData, - @NotNull JsclOperation operation, - @NotNull String expression) { - this.calculatorEventData = calculatorEventData; - this.operation = operation; - this.expression = expression; - } - - @NotNull - @Override - public JsclOperation getOperation() { - return this.operation; - } - - @NotNull - @Override - public String getExpression() { - return this.expression; - } - - @Override - public long getEventId() { - return calculatorEventData.getEventId(); - } - - @Override - @Nullable - public Long getSequenceId() { - return calculatorEventData.getSequenceId(); - } - - @Override - public boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId) { - return calculatorEventData.isAfter(calculatorEventDataId); - } -} +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.solovyev.android.calculator.jscl.JsclOperation; + +/** + * User: serso + * Date: 9/20/12 + * Time: 10:01 PM + */ +public class CalculatorEvaluationEventDataImpl implements CalculatorEvaluationEventData { + + @NotNull + private final CalculatorEventData calculatorEventData; + + @NotNull + private final JsclOperation operation; + + @NotNull + private final String expression; + + public CalculatorEvaluationEventDataImpl(@NotNull CalculatorEventData calculatorEventData, + @NotNull JsclOperation operation, + @NotNull String expression) { + this.calculatorEventData = calculatorEventData; + this.operation = operation; + this.expression = expression; + } + + @NotNull + @Override + public JsclOperation getOperation() { + return this.operation; + } + + @NotNull + @Override + public String getExpression() { + return this.expression; + } + + @Override + public long getEventId() { + return calculatorEventData.getEventId(); + } + + @Override + @Nullable + public Long getSequenceId() { + return calculatorEventData.getSequenceId(); + } + + @Override + public boolean isAfter(@NotNull CalculatorEventDataId that) { + return calculatorEventData.isAfter(that); + } + + @Override + public boolean isSameSequence(@NotNull CalculatorEventDataId that) { + return this.calculatorEventData.isSameSequence(that); + } +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataId.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataId.java index 783d82d6..780e4e12 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataId.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataId.java @@ -1,21 +1,23 @@ -package org.solovyev.android.calculator; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * User: Solovyev_S - * Date: 20.09.12 - * Time: 18:18 - */ -public interface CalculatorEventDataId { - - // the higher id => the later event - long getEventId(); - - // the higher id => the later event - @Nullable - Long getSequenceId(); - - boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId); -} +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: Solovyev_S + * Date: 20.09.12 + * Time: 18:18 + */ +public interface CalculatorEventDataId { + + // the higher id => the later event + long getEventId(); + + // the higher id => the later event + @Nullable + Long getSequenceId(); + + boolean isAfter(@NotNull CalculatorEventDataId that); + + boolean isSameSequence(@NotNull CalculatorEventDataId that); +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataIdImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataIdImpl.java index ad2e2ca9..87d023d7 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataIdImpl.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataIdImpl.java @@ -1,64 +1,69 @@ -package org.solovyev.android.calculator; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * User: Solovyev_S - * Date: 20.09.12 - * Time: 18:18 - */ -class CalculatorEventDataIdImpl implements CalculatorEventDataId { - - private final long eventId; - - @Nullable - private final Long sequenceId; - - private CalculatorEventDataIdImpl(long id, @Nullable Long sequenceId) { - this.eventId = id; - this.sequenceId = sequenceId; - } - - @NotNull - static CalculatorEventDataId newInstance(long id, @Nullable Long sequenceId) { - return new CalculatorEventDataIdImpl(id, sequenceId); - } - - @Override - public long getEventId() { - return this.eventId; - } - - @Nullable - @Override - public Long getSequenceId() { - return this.sequenceId; - } - - @Override - public boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId) { - return this.eventId > calculatorEventDataId.getEventId(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof CalculatorEventDataIdImpl)) return false; - - CalculatorEventDataIdImpl that = (CalculatorEventDataIdImpl) o; - - if (eventId != that.eventId) return false; - if (sequenceId != null ? !sequenceId.equals(that.sequenceId) : that.sequenceId != null) - return false; - - return true; - } - - @Override - public int hashCode() { - int result = (int) (eventId ^ (eventId >>> 32)); - result = 31 * result + (sequenceId != null ? sequenceId.hashCode() : 0); - return result; - } -} +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: Solovyev_S + * Date: 20.09.12 + * Time: 18:18 + */ +class CalculatorEventDataIdImpl implements CalculatorEventDataId { + + private final long eventId; + + @Nullable + private final Long sequenceId; + + private CalculatorEventDataIdImpl(long id, @Nullable Long sequenceId) { + this.eventId = id; + this.sequenceId = sequenceId; + } + + @NotNull + static CalculatorEventDataId newInstance(long id, @Nullable Long sequenceId) { + return new CalculatorEventDataIdImpl(id, sequenceId); + } + + @Override + public long getEventId() { + return this.eventId; + } + + @Nullable + @Override + public Long getSequenceId() { + return this.sequenceId; + } + + @Override + public boolean isAfter(@NotNull CalculatorEventDataId that) { + return this.eventId > that.getEventId(); + } + + @Override + public boolean isSameSequence(@NotNull CalculatorEventDataId that) { + return this.sequenceId != null && this.sequenceId.equals(that.getSequenceId()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CalculatorEventDataIdImpl)) return false; + + CalculatorEventDataIdImpl that = (CalculatorEventDataIdImpl) o; + + if (eventId != that.eventId) return false; + if (sequenceId != null ? !sequenceId.equals(that.sequenceId) : that.sequenceId != null) + return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) (eventId ^ (eventId >>> 32)); + result = 31 * result + (sequenceId != null ? sequenceId.hashCode() : 0); + return result; + } +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataImpl.java index 34b37d2b..aba57c7a 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataImpl.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorEventDataImpl.java @@ -1,57 +1,62 @@ -package org.solovyev.android.calculator; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * User: Solovyev_S - * Date: 20.09.12 - * Time: 16:54 - */ -class CalculatorEventDataImpl implements CalculatorEventData { - - @NotNull - private CalculatorEventDataId calculatorEventDataId; - - private CalculatorEventDataImpl(@NotNull CalculatorEventDataId calculatorEventDataId) { - this.calculatorEventDataId = calculatorEventDataId; - } - - @NotNull - public static CalculatorEventData newInstance(@NotNull CalculatorEventDataId calculatorEventDataId) { - return new CalculatorEventDataImpl(calculatorEventDataId); - } - - @Override - public long getEventId() { - return calculatorEventDataId.getEventId(); - } - - @Override - @Nullable - public Long getSequenceId() { - return calculatorEventDataId.getSequenceId(); - } - - @Override - public boolean isAfter(@NotNull CalculatorEventDataId calculatorEventDataId) { - return this.calculatorEventDataId.isAfter(calculatorEventDataId); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof CalculatorEventDataImpl)) return false; - - CalculatorEventDataImpl that = (CalculatorEventDataImpl) o; - - if (!calculatorEventDataId.equals(that.calculatorEventDataId)) return false; - - return true; - } - - @Override - public int hashCode() { - return calculatorEventDataId.hashCode(); - } -} +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: Solovyev_S + * Date: 20.09.12 + * Time: 16:54 + */ +class CalculatorEventDataImpl implements CalculatorEventData { + + @NotNull + private CalculatorEventDataId calculatorEventDataId; + + private CalculatorEventDataImpl(@NotNull CalculatorEventDataId calculatorEventDataId) { + this.calculatorEventDataId = calculatorEventDataId; + } + + @NotNull + public static CalculatorEventData newInstance(@NotNull CalculatorEventDataId calculatorEventDataId) { + return new CalculatorEventDataImpl(calculatorEventDataId); + } + + @Override + public long getEventId() { + return calculatorEventDataId.getEventId(); + } + + @Override + @Nullable + public Long getSequenceId() { + return calculatorEventDataId.getSequenceId(); + } + + @Override + public boolean isAfter(@NotNull CalculatorEventDataId that) { + return this.calculatorEventDataId.isAfter(that); + } + + @Override + public boolean isSameSequence(@NotNull CalculatorEventDataId that) { + return this.calculatorEventDataId.isSameSequence(that); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CalculatorEventDataImpl)) return false; + + CalculatorEventDataImpl that = (CalculatorEventDataImpl) o; + + if (!calculatorEventDataId.equals(that.calculatorEventDataId)) return false; + + return true; + } + + @Override + public int hashCode() { + return calculatorEventDataId.hashCode(); + } +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorLocator.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorLocator.java index 3b04e8be..ffde6161 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorLocator.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorLocator.java @@ -1,22 +1,25 @@ -package org.solovyev.android.calculator; - -import org.jetbrains.annotations.NotNull; - -/** - * User: Solovyev_S - * Date: 20.09.12 - * Time: 12:45 - */ -public interface CalculatorLocator { - - @NotNull - JCalculatorEngine getCalculatorEngine(); - - @NotNull - Calculator getCalculator(); - - @NotNull - CalculatorDisplay getCalculatorDisplay(); - - void setCalculatorEngine(@NotNull JCalculatorEngine calculatorEngine); -} +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; + +/** + * User: Solovyev_S + * Date: 20.09.12 + * Time: 12:45 + */ +public interface CalculatorLocator { + + @NotNull + JCalculatorEngine getCalculatorEngine(); + + @NotNull + Calculator getCalculator(); + + @NotNull + CalculatorDisplay getCalculatorDisplay(); + + @NotNull + CalculatorEditor getCalculatorEditor(); + + void setCalculatorEngine(@NotNull JCalculatorEngine calculatorEngine); +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorLocatorImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorLocatorImpl.java index 989e1445..56f57426 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorLocatorImpl.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorLocatorImpl.java @@ -1,54 +1,63 @@ -package org.solovyev.android.calculator; - -import org.jetbrains.annotations.NotNull; - -/** - * User: Solovyev_S - * Date: 20.09.12 - * Time: 12:45 - */ -public class CalculatorLocatorImpl implements CalculatorLocator { - - @NotNull - private JCalculatorEngine calculatorEngine; - - @NotNull - private CalculatorDisplay calculatorDisplay = new CalculatorDisplayImpl(); - - @NotNull - private Calculator calculator = new CalculatorImpl(); - - @NotNull - private static final CalculatorLocator instance = new CalculatorLocatorImpl(); - - private CalculatorLocatorImpl() { - } - - @NotNull - public static CalculatorLocator getInstance() { - return instance; - } - - @NotNull - @Override - public JCalculatorEngine getCalculatorEngine() { - return calculatorEngine; - } - - @NotNull - @Override - public Calculator getCalculator() { - return this.calculator; - } - - @Override - public void setCalculatorEngine(@NotNull JCalculatorEngine calculatorEngine) { - this.calculatorEngine = calculatorEngine; - } - - @Override - @NotNull - public CalculatorDisplay getCalculatorDisplay() { - return calculatorDisplay; - } -} +package org.solovyev.android.calculator; + +import org.jetbrains.annotations.NotNull; + +/** + * User: Solovyev_S + * Date: 20.09.12 + * Time: 12:45 + */ +public class CalculatorLocatorImpl implements CalculatorLocator { + + @NotNull + private JCalculatorEngine calculatorEngine; + + @NotNull + private final CalculatorDisplay calculatorDisplay = new CalculatorDisplayImpl(); + + @NotNull + private final CalculatorEditor calculatorEditor = new CalculatorEditorImpl(); + + @NotNull + private final Calculator calculator = new CalculatorImpl(); + + @NotNull + private static final CalculatorLocator instance = new CalculatorLocatorImpl(); + + private CalculatorLocatorImpl() { + } + + @NotNull + public static CalculatorLocator getInstance() { + return instance; + } + + @NotNull + @Override + public JCalculatorEngine getCalculatorEngine() { + return calculatorEngine; + } + + @NotNull + @Override + public Calculator getCalculator() { + return this.calculator; + } + + @Override + public void setCalculatorEngine(@NotNull JCalculatorEngine calculatorEngine) { + this.calculatorEngine = calculatorEngine; + } + + @Override + @NotNull + public CalculatorDisplay getCalculatorDisplay() { + return calculatorDisplay; + } + + @NotNull + @Override + public CalculatorEditor getCalculatorEditor() { + return calculatorEditor; + } +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java index c8c37c41..ae498be5 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorDisplayHistoryState.java @@ -1,144 +1,142 @@ -/* - * 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.CalculatorDisplay; -import org.solovyev.android.calculator.CalculatorDisplayViewState; -import org.solovyev.android.calculator.CalculatorDisplayViewStateImpl; -import org.solovyev.android.calculator.jscl.JsclOperation; -import org.solovyev.common.text.StringUtils; - -/** - * 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 CalculatorDisplay display) { - final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState(); - - result.editorState = EditorHistoryState.newInstance(display.getViewState()); - - final CalculatorDisplayViewState displayViewState = display.getViewState(); - - result.valid = displayViewState.isValid(); - result.jsclOperation = displayViewState.getOperation(); - result.genericResult = displayViewState.getResult(); - result.errorMessage = displayViewState.getErrorMessage(); - - return result; - } - - public void setValuesFromHistory(@NotNull CalculatorDisplay display) { - if ( this.isValid() ) { - display.setViewState(CalculatorDisplayViewStateImpl.newValidState(this.getJsclOperation(), this.getGenericResult(), StringUtils.getNotEmpty(this.getEditorState().getText(), ""), this.getEditorState().getCursorPosition())); - } else { - display.setViewState(CalculatorDisplayViewStateImpl.newErrorState(this.getJsclOperation(), StringUtils.getNotEmpty(this.getErrorMessage(), ""))); - } - } - - - 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.CalculatorDisplay; +import org.solovyev.android.calculator.CalculatorDisplayViewState; +import org.solovyev.android.calculator.CalculatorDisplayViewStateImpl; +import org.solovyev.android.calculator.jscl.JsclOperation; +import org.solovyev.common.text.StringUtils; + +/** + * 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 CalculatorDisplayViewState viewState) { + final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState(); + + result.editorState = EditorHistoryState.newInstance(viewState); + + result.valid = viewState.isValid(); + result.jsclOperation = viewState.getOperation(); + result.genericResult = viewState.getResult(); + result.errorMessage = viewState.getErrorMessage(); + + return result; + } + + public void setValuesFromHistory(@NotNull CalculatorDisplay display) { + if ( this.isValid() ) { + display.setViewState(CalculatorDisplayViewStateImpl.newValidState(this.getJsclOperation(), this.getGenericResult(), StringUtils.getNotEmpty(this.getEditorState().getText(), ""), this.getEditorState().getCursorPosition())); + } else { + display.setViewState(CalculatorDisplayViewStateImpl.newErrorState(this.getJsclOperation(), StringUtils.getNotEmpty(this.getErrorMessage(), ""))); + } + } + + + 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-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistory.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistory.java index c7f8f828..517db8d0 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistory.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistory.java @@ -1,6 +1,7 @@ package org.solovyev.android.calculator.history; import org.jetbrains.annotations.NotNull; +import org.solovyev.android.calculator.CalculatorEventListener; import org.solovyev.common.history.HistoryHelper; /** @@ -8,7 +9,7 @@ import org.solovyev.common.history.HistoryHelper; * Date: 20.09.12 * Time: 16:11 */ -public interface CalculatorHistory extends HistoryHelper { +public interface CalculatorHistory extends HistoryHelper, CalculatorEventListener { void fromXml(@NotNull String xml); diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryImpl.java index fc881c5c..140dde60 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryImpl.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryImpl.java @@ -2,6 +2,7 @@ package org.solovyev.android.calculator.history; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.solovyev.android.calculator.*; import org.solovyev.common.history.HistoryAction; import org.solovyev.common.history.HistoryHelper; import org.solovyev.common.history.SimpleHistoryHelper; @@ -26,6 +27,9 @@ public class CalculatorHistoryImpl implements CalculatorHistory { @NotNull private final List savedHistory = new ArrayList(); + @NotNull + private CalculatorEventDataId lastEventDataId = CalculatorLocatorImpl.getInstance().getCalculator().createFirstEventDataId(); + @Override public boolean isEmpty() { return this.history.isEmpty(); @@ -128,4 +132,26 @@ public class CalculatorHistoryImpl implements CalculatorHistory { public void removeSavedHistory(@NotNull CalculatorHistoryState historyState) { this.savedHistory.remove(historyState); } + + @Override + public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, + @NotNull CalculatorEventType calculatorEventType, + @Nullable Object data) { + if (calculatorEventType.isOfType(CalculatorEventType.calculation_started, CalculatorEventType.calculation_result, CalculatorEventType.calculation_failed)) { + + if ( calculatorEventData.isAfter(this.lastEventDataId) ) { + + switch (calculatorEventType) { + case calculation_started: + CalculatorHistoryState.newInstance() + break; + } + + CalculatorLocatorImpl.getInstance().getCalculatorDisplay().get + CalculatorHistoryState.newInstance(new TextViewEditorAdapter(this.editor), display); + + this.lastEventDataId = calculatorEventData; + } + } + } } diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryState.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryState.java index f866596a..096a1afa 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryState.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/CalculatorHistoryState.java @@ -1,111 +1,115 @@ -/* - * 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 org.jetbrains.annotations.NotNull; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; -import org.solovyev.android.calculator.CalculatorDisplay; -import org.solovyev.android.calculator.Editor; - -/** - * User: serso - * Date: 9/11/11 - * Time: 12:16 AM - */ - -@Root -public class CalculatorHistoryState extends AbstractHistoryState { - - @Element - @NotNull - private EditorHistoryState editorState; - - @Element - @NotNull - private CalculatorDisplayHistoryState displayState; - - private CalculatorHistoryState() { - // for xml - } - - private CalculatorHistoryState(@NotNull EditorHistoryState editorState, - @NotNull CalculatorDisplayHistoryState displayState) { - this.editorState = editorState; - this.displayState = displayState; - } - - public static CalculatorHistoryState newInstance(@NotNull Editor editor, @NotNull CalculatorDisplay display) { - final EditorHistoryState editorHistoryState = EditorHistoryState.newInstance(editor); - final CalculatorDisplayHistoryState displayHistoryState = CalculatorDisplayHistoryState.newInstance(display); - return new CalculatorHistoryState(editorHistoryState, displayHistoryState); - } - - @NotNull - public EditorHistoryState getEditorState() { - return editorState; - } - - public void setEditorState(@NotNull EditorHistoryState editorState) { - this.editorState = editorState; - } - - @NotNull - public CalculatorDisplayHistoryState getDisplayState() { - return displayState; - } - - public void setDisplayState(@NotNull CalculatorDisplayHistoryState displayState) { - this.displayState = displayState; - } - - @Override - public String toString() { - return "CalculatorHistoryState{" + - "editorState=" + editorState + - ", displayState=" + displayState + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - CalculatorHistoryState that = (CalculatorHistoryState) o; - - if (this.isSaved() != that.isSaved()) return false; - if (this.getId() != that.getId()) return false; - if (!displayState.equals(that.displayState)) return false; - if (!editorState.equals(that.editorState)) return false; - - return true; - } - - @Override - public int hashCode() { - int result = Boolean.valueOf(isSaved()).hashCode(); - result = 31 * result + getId(); - result = 31 * result + editorState.hashCode(); - result = 31 * result + displayState.hashCode(); - return result; - } - - public void setValuesFromHistory(@NotNull Editor editor, @NotNull CalculatorDisplay display) { - this.getEditorState().setValuesFromHistory(editor); - this.getDisplayState().setValuesFromHistory(display); - } - - @Override - protected CalculatorHistoryState clone() { - final CalculatorHistoryState clone = (CalculatorHistoryState)super.clone(); - - clone.editorState = this.editorState.clone(); - clone.displayState = this.displayState.clone(); - - return clone; - } -} +/* + * 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 org.jetbrains.annotations.NotNull; +import org.simpleframework.xml.Element; +import org.simpleframework.xml.Root; +import org.solovyev.android.calculator.CalculatorDisplay; +import org.solovyev.android.calculator.CalculatorEditor; +import org.solovyev.android.calculator.Editor; + +/** + * User: serso + * Date: 9/11/11 + * Time: 12:16 AM + */ + +@Root +public class CalculatorHistoryState extends AbstractHistoryState { + + @Element + @NotNull + private EditorHistoryState editorState; + + @Element + @NotNull + private CalculatorDisplayHistoryState displayState; + + private CalculatorHistoryState() { + // for xml + } + + private CalculatorHistoryState(@NotNull EditorHistoryState editorState, + @NotNull CalculatorDisplayHistoryState displayState) { + this.editorState = editorState; + this.displayState = displayState; + } + + public static CalculatorHistoryState newInstance(@NotNull CalculatorEditor editor, + @NotNull CalculatorDisplay display) { + final EditorHistoryState editorHistoryState = EditorHistoryState.newInstance(editor.getViewState()); + + final CalculatorDisplayHistoryState displayHistoryState = CalculatorDisplayHistoryState.newInstance(display.getViewState()); + + return new CalculatorHistoryState(editorHistoryState, displayHistoryState); + } + + @NotNull + public EditorHistoryState getEditorState() { + return editorState; + } + + public void setEditorState(@NotNull EditorHistoryState editorState) { + this.editorState = editorState; + } + + @NotNull + public CalculatorDisplayHistoryState getDisplayState() { + return displayState; + } + + public void setDisplayState(@NotNull CalculatorDisplayHistoryState displayState) { + this.displayState = displayState; + } + + @Override + public String toString() { + return "CalculatorHistoryState{" + + "editorState=" + editorState + + ", displayState=" + displayState + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CalculatorHistoryState that = (CalculatorHistoryState) o; + + if (this.isSaved() != that.isSaved()) return false; + if (this.getId() != that.getId()) return false; + if (!displayState.equals(that.displayState)) return false; + if (!editorState.equals(that.editorState)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = Boolean.valueOf(isSaved()).hashCode(); + result = 31 * result + getId(); + result = 31 * result + editorState.hashCode(); + result = 31 * result + displayState.hashCode(); + return result; + } + + public void setValuesFromHistory(@NotNull Editor editor, @NotNull CalculatorDisplay display) { + this.getEditorState().setValuesFromHistory(editor); + this.getDisplayState().setValuesFromHistory(display); + } + + @Override + protected CalculatorHistoryState clone() { + final CalculatorHistoryState clone = (CalculatorHistoryState)super.clone(); + + clone.editorState = this.editorState.clone(); + clone.displayState = this.displayState.clone(); + + return clone; + } +} diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/EditorHistoryState.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/EditorHistoryState.java index 2ffa241b..5a0fcb44 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/EditorHistoryState.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/history/EditorHistoryState.java @@ -1,99 +1,100 @@ -/* - * 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 org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.simpleframework.xml.Element; -import org.simpleframework.xml.Root; -import org.solovyev.android.calculator.CalculatorDisplayViewState; -import org.solovyev.android.calculator.Editor; - -@Root -public class EditorHistoryState implements Cloneable{ - - @Element - private int cursorPosition; - - @Element(required = false) - @Nullable - private String text; - - private EditorHistoryState() { - // for xml - } - - @NotNull - public static EditorHistoryState newInstance(@NotNull Editor editor) { - final EditorHistoryState result = new EditorHistoryState(); - - result.text = String.valueOf(editor.getText()); - result.cursorPosition = editor.getSelection(); - - return result; - } - - @NotNull - public static EditorHistoryState newInstance(@NotNull CalculatorDisplayViewState viewState) { - final EditorHistoryState result = new EditorHistoryState(); - - result.text = viewState.getText(); - result.cursorPosition = viewState.getSelection(); - - return result; - } - - public void setValuesFromHistory(@NotNull Editor editor) { - editor.setText(this.getText()); - editor.setSelection(this.getCursorPosition()); - } - - @Nullable - public String getText() { - return text; - } - - public int getCursorPosition() { - return cursorPosition; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof EditorHistoryState)) return false; - - EditorHistoryState that = (EditorHistoryState) o; - - if (cursorPosition != that.cursorPosition) return false; - if (text != null ? !text.equals(that.text) : that.text != null) return false; - - return true; - } - - @Override - public int hashCode() { - int result = cursorPosition; - result = 31 * result + (text != null ? text.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "EditorHistoryState{" + - "cursorPosition=" + cursorPosition + - ", text='" + text + '\'' + - '}'; - } - - @Override - protected EditorHistoryState clone() { - try { - return (EditorHistoryState)super.clone(); - } catch (CloneNotSupportedException e) { - throw new UnsupportedOperationException(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 org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.simpleframework.xml.Element; +import org.simpleframework.xml.Root; +import org.solovyev.android.calculator.CalculatorDisplayViewState; +import org.solovyev.android.calculator.CalculatorEditorViewState; +import org.solovyev.android.calculator.Editor; + +@Root +public class EditorHistoryState implements Cloneable{ + + @Element + private int cursorPosition; + + @Element(required = false) + @Nullable + private String text; + + private EditorHistoryState() { + // for xml + } + + @NotNull + public static EditorHistoryState newInstance(@NotNull CalculatorEditorViewState viewState) { + final EditorHistoryState result = new EditorHistoryState(); + + result.text = String.valueOf(viewState.getText()); + result.cursorPosition = viewState.getSelection(); + + return result; + } + + @NotNull + public static EditorHistoryState newInstance(@NotNull CalculatorDisplayViewState viewState) { + final EditorHistoryState result = new EditorHistoryState(); + + result.text = viewState.getText(); + result.cursorPosition = viewState.getSelection(); + + return result; + } + + public void setValuesFromHistory(@NotNull Editor editor) { + editor.setText(this.getText()); + editor.setSelection(this.getCursorPosition()); + } + + @Nullable + public String getText() { + return text; + } + + public int getCursorPosition() { + return cursorPosition; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof EditorHistoryState)) return false; + + EditorHistoryState that = (EditorHistoryState) o; + + if (cursorPosition != that.cursorPosition) return false; + if (text != null ? !text.equals(that.text) : that.text != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = cursorPosition; + result = 31 * result + (text != null ? text.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "EditorHistoryState{" + + "cursorPosition=" + cursorPosition + + ", text='" + text + '\'' + + '}'; + } + + @Override + protected EditorHistoryState clone() { + try { + return (EditorHistoryState)super.clone(); + } catch (CloneNotSupportedException e) { + throw new UnsupportedOperationException(e); + } + } +} diff --git a/calculatorpp/res/layout/calc_editor.xml b/calculatorpp/res/layout/calc_editor.xml index b159ec40..124b7d0a 100644 --- a/calculatorpp/res/layout/calc_editor.xml +++ b/calculatorpp/res/layout/calc_editor.xml @@ -1,22 +1,22 @@ - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculatorDisplayView.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculatorDisplayView.java index d8db12c7..baa5d898 100644 --- a/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculatorDisplayView.java +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculatorDisplayView.java @@ -1,235 +1,150 @@ -/* - * 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.math.Generic; -import jscl.math.function.Constant; -import jscl.math.function.IConstant; -import org.jetbrains.annotations.NotNull; -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.view.NumeralBaseConverterDialog; -import org.solovyev.android.calculator.view.TextHighlighter; -import org.solovyev.android.menu.LabeledMenuItem; -import org.solovyev.android.view.AutoResizeTextView; -import org.solovyev.common.collections.CollectionsUtils; - -import java.util.HashSet; -import java.util.Set; - -/** - * User: serso - * Date: 9/17/11 - * Time: 10:58 PM - */ -public class AndroidCalculatorDisplayView extends AutoResizeTextView implements CalculatorDisplayView { - - public static enum MenuItem implements LabeledMenuItem { - - copy(R.string.c_copy) { - @Override - public void onClick(@NotNull CalculatorDisplayViewState data, @NotNull Context context) { - CalculatorModel.copyResult(context, data); - } - }, - - convert_to_bin(R.string.convert_to_bin) { - @Override - public void onClick(@NotNull CalculatorDisplayViewState 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 CalculatorDisplayViewState 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 CalculatorDisplayViewState 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 CalculatorDisplayViewState data, @NotNull Context context) { - final Generic result = data.getResult(); - if (result != null) { - new NumeralBaseConverterDialog(result.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 CalculatorDisplayViewState data, @NotNull Context context) { - final Generic generic = data.getResult(); - 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 CalculatorDisplayViewState displayViewState) { - //noinspection ConstantConditions - return displayViewState.isValid() && displayViewState.getResult() != null && isItemVisibleFor(displayViewState.getResult(), displayViewState.getOperation()); - } - - protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) { - return true; - } - - @NotNull - @Override - public String getCaption(@NotNull Context context) { - return context.getString(captionId); - } - } - - @NotNull - private CalculatorDisplayViewState state = CalculatorDisplayViewStateImpl.newDefaultInstance(); - - @NotNull - private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, false, CalculatorEngine.instance.getEngine()); - - public AndroidCalculatorDisplayView(Context context) { - super(context); - } - - public AndroidCalculatorDisplayView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public AndroidCalculatorDisplayView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - public boolean isValid() { - return this.state.isValid(); - } - - - @Override - public void setState(@NotNull CalculatorDisplayViewState state) { - this.state = state; - if ( state.isValid() ) { - setTextColor(getResources().getColor(R.color.default_text_color)); - setText(state.getStringResult()); - } else { - setTextColor(getResources().getColor(R.color.display_error_text_color)); - setText(state.getErrorMessage()); - } - } - - @NotNull - @Override - public CalculatorDisplayViewState getState() { - return this.state; - } - - @Override - public void setText(CharSequence text, BufferType type) { - super.setText(text, type); - } - - 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 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.os.Handler; +import android.text.Html; +import android.util.AttributeSet; +import android.util.Log; +import jscl.math.Generic; +import jscl.math.function.Constant; +import jscl.math.function.IConstant; +import org.jetbrains.annotations.NotNull; +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.view.NumeralBaseConverterDialog; +import org.solovyev.android.calculator.view.TextHighlighter; +import org.solovyev.android.menu.LabeledMenuItem; +import org.solovyev.android.view.AutoResizeTextView; +import org.solovyev.common.collections.CollectionsUtils; + +import java.util.HashSet; +import java.util.Set; + +/** + * User: serso + * Date: 9/17/11 + * Time: 10:58 PM + */ +public class AndroidCalculatorDisplayView extends AutoResizeTextView implements CalculatorDisplayView { + + /* + ********************************************************************** + * + * STATIC FIELDS + * + ********************************************************************** + */ + + @NotNull + private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, false, CalculatorEngine.instance.getEngine()); + + /* + ********************************************************************** + * + * FIELDS + * + ********************************************************************** + */ + + @NotNull + private CalculatorDisplayViewState state = CalculatorDisplayViewStateImpl.newDefaultInstance(); + + @NotNull + private final Object lock = new Object(); + + @NotNull + private final Handler handler = new Handler(); + + /* + ********************************************************************** + * + * CONSTRUCTORS + * + ********************************************************************** + */ + + public AndroidCalculatorDisplayView(Context context) { + super(context); + } + + public AndroidCalculatorDisplayView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public AndroidCalculatorDisplayView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /* + ********************************************************************** + * + * METHODS + * + ********************************************************************** + */ + + public boolean isValid() { + synchronized (lock) { + return this.state.isValid(); + } + } + + @Override + public void setState(@NotNull final CalculatorDisplayViewState state) { + handler.postDelayed(new Runnable() { + @Override + public void run() { + synchronized (lock) { + AndroidCalculatorDisplayView.this.state = state; + if ( state.isValid() ) { + setTextColor(getResources().getColor(R.color.default_text_color)); + setText(state.getStringResult()); + redraw(); + } else { + setTextColor(getResources().getColor(R.color.display_error_text_color)); + setText(state.getErrorMessage()); + redraw(); + } + } + } + }, 1); + } + + @NotNull + @Override + public CalculatorDisplayViewState getState() { + synchronized (lock) { + return this.state; + } + } + + private 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(); + } +} diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculatorEditorView.java similarity index 73% rename from calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java rename to calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculatorEditorView.java index 3f9b20c9..1f14c34e 100644 --- a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorEditor.java +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculatorEditorView.java @@ -25,7 +25,7 @@ import org.solovyev.common.collections.CollectionsUtils; * Date: 9/17/11 * Time: 12:25 AM */ -public class CalculatorEditor extends EditText implements SharedPreferences.OnSharedPreferenceChangeListener { +public class AndroidCalculatorEditorView extends EditText implements SharedPreferences.OnSharedPreferenceChangeListener, CalculatorEditorView { private static final String CALC_COLOR_DISPLAY_KEY = "org.solovyev.android.calculator.CalculatorModel_color_display"; private static final boolean CALC_COLOR_DISPLAY_DEFAULT = true; @@ -35,39 +35,16 @@ public class CalculatorEditor extends EditText implements SharedPreferences.OnSh @NotNull private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE, true, CalculatorEngine.instance.getEngine()); - public CalculatorEditor(Context context) { + public AndroidCalculatorEditorView(Context context) { super(context); - init(); } - public CalculatorEditor(Context context, AttributeSet attrs) { + public AndroidCalculatorEditorView(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; - } - });*/ + public AndroidCalculatorEditorView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); } @@ -95,11 +72,6 @@ public class CalculatorEditor extends EditText implements SharedPreferences.OnSh } } - public CalculatorEditor(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - @Override protected void onCreateContextMenu(ContextMenu menu) { super.onCreateContextMenu(menu); @@ -107,11 +79,6 @@ public class CalculatorEditor extends EditText implements SharedPreferences.OnSh 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(); diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplayMenuItem.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplayMenuItem.java new file mode 100644 index 00000000..bf433c73 --- /dev/null +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplayMenuItem.java @@ -0,0 +1,141 @@ +package org.solovyev.android.calculator; + +import android.content.Context; +import jscl.math.Generic; +import jscl.math.function.Constant; +import jscl.math.function.IConstant; +import org.jetbrains.annotations.NotNull; +import org.solovyev.android.calculator.jscl.JsclOperation; +import org.solovyev.android.calculator.model.CalculatorEngine; +import org.solovyev.android.calculator.view.NumeralBaseConverterDialog; +import org.solovyev.android.menu.LabeledMenuItem; +import org.solovyev.common.collections.CollectionsUtils; + +import java.util.HashSet; +import java.util.Set; + +/** +* User: Solovyev_S +* Date: 21.09.12 +* Time: 10:55 +*/ +public enum CalculatorDisplayMenuItem implements LabeledMenuItem { + + copy(R.string.c_copy) { + @Override + public void onClick(@NotNull CalculatorDisplayViewState data, @NotNull Context context) { + CalculatorModel.copyResult(context, data); + } + }, + + convert_to_bin(R.string.convert_to_bin) { + @Override + public void onClick(@NotNull CalculatorDisplayViewState 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 CalculatorDisplayViewState 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 CalculatorDisplayViewState 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 CalculatorDisplayViewState data, @NotNull Context context) { + final Generic result = data.getResult(); + if (result != null) { + new NumeralBaseConverterDialog(result.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 CalculatorDisplayViewState data, @NotNull Context context) { + final Generic generic = data.getResult(); + 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; + + CalculatorDisplayMenuItem(int captionId) { + this.captionId = captionId; + } + + public final boolean isItemVisible(@NotNull CalculatorDisplayViewState displayViewState) { + //noinspection ConstantConditions + return displayViewState.isValid() && displayViewState.getResult() != null && isItemVisibleFor(displayViewState.getResult(), displayViewState.getOperation()); + } + + protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) { + return true; + } + + @NotNull + @Override + public String getCaption(@NotNull Context context) { + return context.getString(captionId); + } +} diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplayOnClickListener.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplayOnClickListener.java new file mode 100644 index 00000000..eb84cc82 --- /dev/null +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorDisplayOnClickListener.java @@ -0,0 +1,53 @@ +package org.solovyev.android.calculator; + +import android.app.Activity; +import android.view.View; +import org.jetbrains.annotations.NotNull; +import org.solovyev.android.menu.AMenuBuilder; +import org.solovyev.android.menu.MenuImpl; + +import java.util.ArrayList; +import java.util.List; + +/** + * User: Solovyev_S + * Date: 21.09.12 + * Time: 10:58 + */ +public 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 CalculatorDisplayView) { + final CalculatorDisplay cd = CalculatorLocatorImpl.getInstance().getCalculatorDisplay(); + + final CalculatorDisplayViewState displayViewState = cd.getViewState(); + + if (displayViewState.isValid()) { + final List filteredMenuItems = new ArrayList(CalculatorDisplayMenuItem.values().length); + for (CalculatorDisplayMenuItem menuItem : CalculatorDisplayMenuItem.values()) { + if (menuItem.isItemVisible(displayViewState)) { + filteredMenuItems.add(menuItem); + } + } + + if (!filteredMenuItems.isEmpty()) { + AMenuBuilder.newInstance(activity, MenuImpl.newInstance(filteredMenuItems)).create(displayViewState).show(); + } + + } else { + final String errorMessage = displayViewState.getErrorMessage(); + if (errorMessage != null) { + CalculatorModel.showEvaluationError(activity, errorMessage); + } + } + } + } +} 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 e43e9131..be86a912 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,356 @@ -/* - * 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.AndroidCalculatorHistoryImpl; -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.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 AndroidCalculatorDisplayView 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 = (AndroidCalculatorDisplayView) activity.findViewById(R.id.calculatorDisplay); - this.display.setOnClickListener(new CalculatorDisplayOnClickListener(activity)); - - final CalculatorHistoryState lastState = AndroidCalculatorHistoryImpl.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 CalculatorDisplayViewState viewState) { - if (viewState.isValid()) { - final CharSequence text = viewState.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() { - AndroidCalculatorHistoryImpl.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) { - AndroidCalculatorHistoryImpl.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) { - AndroidCalculatorHistoryImpl.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 CalculatorOutput 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.getStringResult()); - } else { - display.setText(""); - } - display.setJsclOperation(result.getOperation()); - display.setGenericResult(result.getResult()); - } 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 AndroidCalculatorDisplayView 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 (AndroidCalculatorHistoryImpl.instance) { - if (AndroidCalculatorHistoryImpl.instance.isActionAvailable(historyAction)) { - final CalculatorHistoryState newState = AndroidCalculatorHistoryImpl.instance.doAction(historyAction, getCurrentHistoryState()); - if (newState != null) { - setCurrentHistoryState(newState); - } - } - } - } - - @Override - public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) { - synchronized (AndroidCalculatorHistoryImpl.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 (AndroidCalculatorHistoryImpl.instance) { - return CalculatorHistoryState.newInstance(new TextViewEditorAdapter(this.editor), this.display); - } - } - - @NotNull - public AndroidCalculatorDisplayView 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 CalculatorDisplayView) { - final CalculatorDisplay cd = CalculatorLocatorImpl.getInstance().getCalculatorDisplay(); - - final CalculatorDisplayViewState displayViewState = cd.getViewState(); - - if (displayViewState.isValid()) { - final List filteredMenuItems = new ArrayList(AndroidCalculatorDisplayView.MenuItem.values().length); - for (AndroidCalculatorDisplayView.MenuItem menuItem : AndroidCalculatorDisplayView.MenuItem.values()) { - if (menuItem.isItemVisible(displayViewState)) { - filteredMenuItems.add(menuItem); - } - } - - if (!filteredMenuItems.isEmpty()) { - AMenuBuilder.newInstance(activity, MenuImpl.newInstance(filteredMenuItems)).create(cd).show(); - } - - } else { - final String errorMessage = displayViewState.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.AndroidCalculatorHistoryImpl; +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.history.HistoryControl; +import org.solovyev.common.MutableObject; +import org.solovyev.common.history.HistoryAction; +import org.solovyev.common.msg.Message; +import org.solovyev.common.text.StringUtils; + +/** + * User: serso + * Date: 9/12/11 + * Time: 11:15 PM + */ +public enum CalculatorModel implements HistoryControl, CalculatorEngineControl { + + instance; + + // millis to wait before evaluation after user edit action + public static final int EVAL_DELAY_MILLIS = 0; + + @NotNull + private final CalculatorEditor editor; + + @NotNull + private final CalculatorDisplay display; + + @NotNull + private CalculatorEngine calculatorEngine; + + private CalculatorModel() { + display = CalculatorLocatorImpl.getInstance().getCalculatorDisplay(); + editor = CalculatorLocatorImpl.getInstance().getCalculatorEditor(); + } + + 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; + + final AndroidCalculatorEditorView editorView = (AndroidCalculatorEditorView) activity.findViewById(R.id.calculatorEditor); + editorView.init(preferences); + preferences.registerOnSharedPreferenceChangeListener(editorView); + editor.setView(editorView); + + final AndroidCalculatorDisplayView displayView = (AndroidCalculatorDisplayView) activity.findViewById(R.id.calculatorDisplay); + displayView.setOnClickListener(new CalculatorDisplayOnClickListener(activity)); + display.setView(displayView); + + final CalculatorHistoryState lastState = AndroidCalculatorHistoryImpl.instance.getLastHistoryState(); + if (lastState == null) { + saveHistoryState(); + } else { + setCurrentHistoryState(lastState); + } + + + return this; + } + + public 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.getViewState()); + } + + public static void copyResult(@NotNull Context context, @NotNull final CalculatorDisplayViewState viewState) { + if (viewState.isValid()) { + final CharSequence text = viewState.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() { + AndroidCalculatorHistoryImpl.instance.addState(getCurrentHistoryState()); + } + + 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) { + AndroidCalculatorHistoryImpl.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) { + AndroidCalculatorHistoryImpl.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 CalculatorOutput 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.getStringResult()); + } else { + display.setText(""); + } + display.setJsclOperation(result.getOperation()); + display.setGenericResult(result.getResult()); + } 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 AndroidCalculatorDisplayView 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 (AndroidCalculatorHistoryImpl.instance) { + if (AndroidCalculatorHistoryImpl.instance.isActionAvailable(historyAction)) { + final CalculatorHistoryState newState = AndroidCalculatorHistoryImpl.instance.doAction(historyAction, getCurrentHistoryState()); + if (newState != null) { + setCurrentHistoryState(newState); + } + } + } + } + + @Override + public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) { + synchronized (AndroidCalculatorHistoryImpl.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 (AndroidCalculatorHistoryImpl.instance) { + return CalculatorHistoryState.newInstance(new TextViewEditorAdapter(this.editor), display); + } + } + + @NotNull + public CalculatorDisplay getDisplay() { + return display; + } + +} diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/AndroidCalculatorHistoryImpl.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/history/AndroidCalculatorHistoryImpl.java index b5cba95f..51ca2b69 100644 --- a/calculatorpp/src/main/java/org/solovyev/android/calculator/history/AndroidCalculatorHistoryImpl.java +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/history/AndroidCalculatorHistoryImpl.java @@ -11,6 +11,8 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.solovyev.android.calculator.CalculatorEventData; +import org.solovyev.android.calculator.CalculatorEventType; import org.solovyev.android.calculator.R; import org.solovyev.common.history.HistoryAction; @@ -142,4 +144,9 @@ public enum AndroidCalculatorHistoryImpl implements AndroidCalculatorHistory { public void removeSavedHistory(@NotNull CalculatorHistoryState historyState) { calculatorHistory.removeSavedHistory(historyState); } + + @Override + public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) { + calculatorHistory.onCalculatorEvent(calculatorEventData, calculatorEventType, data); + } } 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 0d616fcc..c5ad71b9 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 @@ -173,7 +173,7 @@ public class TextHighlighter implements TextProcessor