New architecture
This commit is contained in:
@@ -4,17 +4,20 @@ import jscl.NumeralBase;
|
||||
import jscl.math.Generic;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistoryState;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
import org.solovyev.common.history.HistoryControl;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 16:38
|
||||
*/
|
||||
public interface Calculator extends CalculatorEventContainer {
|
||||
public interface Calculator extends CalculatorEventContainer, HistoryControl<CalculatorHistoryState> {
|
||||
|
||||
@NotNull
|
||||
CalculatorEventDataId createFirstEventDataId();
|
||||
void evaluate();
|
||||
|
||||
void simplify();
|
||||
|
||||
@NotNull
|
||||
CalculatorEventDataId evaluate(@NotNull JsclOperation operation,
|
||||
@@ -34,4 +37,5 @@ public interface Calculator extends CalculatorEventContainer {
|
||||
@NotNull
|
||||
CalculatorEventDataId fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data, @NotNull Long sequenceId);
|
||||
|
||||
void init();
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ public class CalculatorDisplayImpl implements CalculatorDisplay {
|
||||
|
||||
public CalculatorDisplayImpl(@NotNull Calculator calculator) {
|
||||
this.calculator = calculator;
|
||||
this.lastCalculatorEventData = CalculatorEventDataImpl.newInstance(calculator.createFirstEventDataId());
|
||||
this.lastCalculatorEventData = CalculatorEventDataImpl.newInstance(CalculatorUtils.createFirstEventDataId());
|
||||
this.calculator.addCalculatorEventListener(this);
|
||||
}
|
||||
|
||||
@@ -138,11 +138,11 @@ public class CalculatorDisplayImpl implements CalculatorDisplay {
|
||||
private void processCalculationCancelled(@NotNull CalculatorEvaluationEventData calculatorEventData) {
|
||||
final String errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
|
||||
|
||||
this.setViewState(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage));
|
||||
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage), calculatorEventData.getSequenceId());
|
||||
}
|
||||
|
||||
private void processCalculationResult(@NotNull CalculatorEvaluationEventData calculatorEventData, @NotNull CalculatorOutput data) {
|
||||
final String stringResult = data.getStringResult();
|
||||
this.setViewState(CalculatorDisplayViewStateImpl.newValidState(calculatorEventData.getOperation(), data.getResult(), stringResult, 0));
|
||||
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newValidState(calculatorEventData.getOperation(), data.getResult(), stringResult, 0), calculatorEventData.getSequenceId());
|
||||
}
|
||||
}
|
||||
|
@@ -2,13 +2,14 @@ package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.common.gui.CursorControl;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 21.09.12
|
||||
* Time: 11:47
|
||||
*/
|
||||
public interface CalculatorEditor extends CalculatorEventListener/*, CursorControl*/ {
|
||||
public interface CalculatorEditor extends CalculatorEventListener {
|
||||
|
||||
void setView(@Nullable CalculatorEditorView view);
|
||||
|
||||
@@ -48,6 +49,9 @@ public interface CalculatorEditor extends CalculatorEventListener/*, CursorContr
|
||||
@NotNull
|
||||
public CalculatorEditorViewState moveCursorRight();
|
||||
|
||||
@NotNull
|
||||
CursorControl asCursorControl();
|
||||
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
|
@@ -2,6 +2,7 @@ package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.common.gui.CursorControl;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
@@ -22,6 +23,9 @@ public class CalculatorEditorImpl implements CalculatorEditor {
|
||||
@NotNull
|
||||
private final Calculator calculator;
|
||||
|
||||
@NotNull
|
||||
private final CursorControlAdapter cursorControlAdapter = new CursorControlAdapter(this);
|
||||
|
||||
public CalculatorEditorImpl(@NotNull Calculator calculator) {
|
||||
this.calculator = calculator;
|
||||
this.calculator.addCalculatorEventListener(this);
|
||||
@@ -65,12 +69,13 @@ public class CalculatorEditorImpl implements CalculatorEditor {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CalculatorEditorViewState setCursorOnStart() {
|
||||
synchronized (viewLock) {
|
||||
return newSelectionViewState(0);
|
||||
}
|
||||
}
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* SELECTION
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@NotNull
|
||||
private CalculatorEditorViewState newSelectionViewState(int newSelection) {
|
||||
@@ -83,6 +88,14 @@ public class CalculatorEditorImpl implements CalculatorEditor {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CalculatorEditorViewState setCursorOnStart() {
|
||||
synchronized (viewLock) {
|
||||
return newSelectionViewState(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public CalculatorEditorViewState setCursorOnEnd() {
|
||||
synchronized (viewLock) {
|
||||
@@ -112,6 +125,20 @@ public class CalculatorEditorImpl implements CalculatorEditor {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CursorControl asCursorControl() {
|
||||
return cursorControlAdapter;
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* EDITOR ACTIONS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CalculatorEditorViewState erase() {
|
||||
@@ -221,4 +248,34 @@ public class CalculatorEditorImpl implements CalculatorEditor {
|
||||
result = Math.min(result, textLength);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final class CursorControlAdapter implements CursorControl {
|
||||
|
||||
@NotNull
|
||||
private final CalculatorEditor calculatorEditor;
|
||||
|
||||
private CursorControlAdapter(@NotNull CalculatorEditor calculatorEditor) {
|
||||
this.calculatorEditor = calculatorEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorOnStart() {
|
||||
this.calculatorEditor.setCursorOnStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorOnEnd() {
|
||||
this.calculatorEditor.setCursorOnEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorLeft() {
|
||||
this.calculatorEditor.moveCursorLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorRight() {
|
||||
this.calculatorEditor.moveCursorRight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,34 +1,39 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import jscl.MathEngine;
|
||||
import jscl.math.function.Function;
|
||||
import jscl.math.function.IConstant;
|
||||
import jscl.math.operator.Operator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.common.math.MathRegistry;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 12:43
|
||||
*/
|
||||
public interface JCalculatorEngine {
|
||||
|
||||
@NotNull
|
||||
String getMultiplicationSign();
|
||||
|
||||
@NotNull
|
||||
MathRegistry<IConstant> getVarsRegistry();
|
||||
|
||||
@NotNull
|
||||
MathRegistry<Function> getFunctionsRegistry();
|
||||
|
||||
@NotNull
|
||||
MathRegistry<Operator> getOperatorsRegistry();
|
||||
|
||||
@NotNull
|
||||
MathRegistry<Operator> getPostfixFunctionsRegistry();
|
||||
|
||||
@NotNull
|
||||
MathEngine getEngine();
|
||||
}
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import jscl.MathEngine;
|
||||
import jscl.math.function.Function;
|
||||
import jscl.math.function.IConstant;
|
||||
import jscl.math.operator.Operator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 12:43
|
||||
*/
|
||||
public interface CalculatorEngine {
|
||||
|
||||
@NotNull
|
||||
String getMultiplicationSign();
|
||||
|
||||
@NotNull
|
||||
CalculatorMathRegistry<IConstant> getVarsRegistry();
|
||||
|
||||
@NotNull
|
||||
CalculatorMathRegistry<Function> getFunctionsRegistry();
|
||||
|
||||
@NotNull
|
||||
CalculatorMathRegistry<Operator> getOperatorsRegistry();
|
||||
|
||||
@NotNull
|
||||
CalculatorMathRegistry<Operator> getPostfixFunctionsRegistry();
|
||||
|
||||
@NotNull
|
||||
MathEngine getEngine();
|
||||
|
||||
void init();
|
||||
|
||||
void reset();
|
||||
|
||||
void softReset();
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
/**
|
||||
@@ -60,4 +59,9 @@ public class CalculatorEvaluationEventDataImpl implements CalculatorEvaluationEv
|
||||
public boolean isSameSequence(@NotNull CalculatorEventDataId that) {
|
||||
return this.calculatorEventData.isSameSequence(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfterSequence(@NotNull CalculatorEventDataId that) {
|
||||
return this.calculatorEventData.isAfterSequence(that);
|
||||
}
|
||||
}
|
||||
|
@@ -19,4 +19,6 @@ public interface CalculatorEventDataId {
|
||||
boolean isAfter(@NotNull CalculatorEventDataId that);
|
||||
|
||||
boolean isSameSequence(@NotNull CalculatorEventDataId that);
|
||||
|
||||
boolean isAfterSequence(@NotNull CalculatorEventDataId that);
|
||||
}
|
||||
|
@@ -47,6 +47,11 @@ class CalculatorEventDataIdImpl implements CalculatorEventDataId {
|
||||
return !this.sequenceId.equals(NO_SEQUENCE) && this.sequenceId.equals(that.getSequenceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfterSequence(@NotNull CalculatorEventDataId that) {
|
||||
return !this.sequenceId.equals(NO_SEQUENCE) && this.sequenceId > that.getSequenceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
@@ -43,6 +42,11 @@ class CalculatorEventDataImpl implements CalculatorEventData {
|
||||
return this.calculatorEventDataId.isSameSequence(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfterSequence(@NotNull CalculatorEventDataId that) {
|
||||
return this.calculatorEventDataId.isAfterSequence(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@@ -8,8 +8,11 @@ import jscl.math.Generic;
|
||||
import jscl.text.ParseInterruptedException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistory;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistoryState;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
import org.solovyev.android.calculator.text.TextProcessor;
|
||||
import org.solovyev.common.history.HistoryAction;
|
||||
import org.solovyev.common.msg.MessageRegistry;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
import org.solovyev.common.text.StringUtils;
|
||||
@@ -29,13 +32,11 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
*/
|
||||
public class CalculatorImpl implements Calculator, CalculatorEventListener {
|
||||
|
||||
private static final long FIRST_ID = 0;
|
||||
|
||||
@NotNull
|
||||
private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer();
|
||||
|
||||
@NotNull
|
||||
private final AtomicLong counter = new AtomicLong(FIRST_ID);
|
||||
private final AtomicLong counter = new AtomicLong(CalculatorUtils.FIRST_ID);
|
||||
|
||||
@NotNull
|
||||
private final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
|
||||
@@ -93,10 +94,14 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CalculatorEventDataId createFirstEventDataId() {
|
||||
return CalculatorEventDataIdImpl.newInstance(FIRST_ID, FIRST_ID);
|
||||
public void evaluate() {
|
||||
this.evaluate(JsclOperation.numeric, getEditor().getViewState().getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simplify() {
|
||||
this.evaluate(JsclOperation.simplify, getEditor().getViewState().getText());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -144,7 +149,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
|
||||
|
||||
fireCalculatorEvent(newConversionEventData(sequenceId), CalculatorEventType.conversion_started, null);
|
||||
|
||||
final NumeralBase from = CalculatorLocatorImpl.getInstance().getCalculatorEngine().getEngine().getNumeralBase();
|
||||
final NumeralBase from = CalculatorLocatorImpl.getInstance().getEngine().getEngine().getNumeralBase();
|
||||
|
||||
if (from != to) {
|
||||
String fromString = generic.toString();
|
||||
@@ -197,6 +202,12 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
|
||||
return eventDataId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
CalculatorLocatorImpl.getInstance().getEngine().init();
|
||||
CalculatorLocatorImpl.getInstance().getHistory().load();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CalculatorEventData newConversionEventData(@NotNull Long sequenceId) {
|
||||
return CalculatorEventDataImpl.newInstance(nextEventDataId(sequenceId));
|
||||
@@ -215,7 +226,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
|
||||
|
||||
expression = expression.trim();
|
||||
|
||||
if ( StringUtils.isEmpty(expression) ) {
|
||||
if (StringUtils.isEmpty(expression)) {
|
||||
final CalculatorOutputImpl data = new CalculatorOutputImpl("", operation, Expression.valueOf(""));
|
||||
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, data);
|
||||
} else {
|
||||
@@ -330,12 +341,44 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
|
||||
final String newText = changeEventData.getNewState().getText();
|
||||
final String oldText = changeEventData.getOldState().getText();
|
||||
|
||||
if ( !newText.equals(oldText) ) {
|
||||
if (!newText.equals(oldText)) {
|
||||
evaluate(JsclOperation.numeric, changeEventData.getNewState().getText(), calculatorEventData.getSequenceId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doHistoryAction(@NotNull HistoryAction historyAction) {
|
||||
final CalculatorHistory history = CalculatorLocatorImpl.getInstance().getHistory();
|
||||
if (history.isActionAvailable(historyAction)) {
|
||||
final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState());
|
||||
if (newState != null) {
|
||||
setCurrentHistoryState(newState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
|
||||
editorHistoryState.setValuesFromHistory(getEditor(), getDisplay());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CalculatorEditor getEditor() {
|
||||
return CalculatorLocatorImpl.getInstance().getEditor();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CalculatorHistoryState getCurrentHistoryState() {
|
||||
return CalculatorHistoryState.newInstance(getEditor(), getDisplay());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CalculatorDisplay getDisplay() {
|
||||
return CalculatorLocatorImpl.getInstance().getDisplay();
|
||||
}
|
||||
|
||||
public static final class ConversionException extends Exception {
|
||||
private ConversionException() {
|
||||
}
|
||||
|
@@ -18,4 +18,8 @@ public interface CalculatorKeyboard {
|
||||
void clearButtonPressed();
|
||||
|
||||
void copyButtonPressed();
|
||||
|
||||
void moveCursorLeft();
|
||||
|
||||
void moveCursorRight();
|
||||
}
|
||||
|
@@ -49,14 +49,14 @@ public class CalculatorKeyboardImpl implements CalculatorKeyboard {
|
||||
}
|
||||
}
|
||||
|
||||
final CalculatorEditor editor = CalculatorLocatorImpl.getInstance().getCalculatorEditor();
|
||||
final CalculatorEditor editor = CalculatorLocatorImpl.getInstance().getEditor();
|
||||
editor.insert(textToBeInserted.toString(), cursorPositionOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void roundBracketsButtonPressed() {
|
||||
final CalculatorEditor editor = CalculatorLocatorImpl.getInstance().getCalculatorEditor();
|
||||
final CalculatorEditor editor = CalculatorLocatorImpl.getInstance().getEditor();
|
||||
CalculatorEditorViewState viewState = editor.getViewState();
|
||||
|
||||
final int cursorPosition = viewState.getSelection();
|
||||
@@ -72,26 +72,36 @@ public class CalculatorKeyboardImpl implements CalculatorKeyboard {
|
||||
|
||||
@Override
|
||||
public void pasteButtonPressed() {
|
||||
final String text = CalculatorLocatorImpl.getInstance().getCalculatorClipboard().getText();
|
||||
final String text = CalculatorLocatorImpl.getInstance().getClipboard().getText();
|
||||
if (text != null) {
|
||||
CalculatorLocatorImpl.getInstance().getCalculatorEditor().insert(text);
|
||||
CalculatorLocatorImpl.getInstance().getEditor().insert(text);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearButtonPressed() {
|
||||
CalculatorLocatorImpl.getInstance().getCalculatorEditor().clear();
|
||||
CalculatorLocatorImpl.getInstance().getEditor().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyButtonPressed() {
|
||||
final CalculatorDisplayViewState displayViewState = CalculatorLocatorImpl.getInstance().getCalculatorDisplay().getViewState();
|
||||
final CalculatorDisplayViewState displayViewState = CalculatorLocatorImpl.getInstance().getDisplay().getViewState();
|
||||
if (displayViewState.isValid()) {
|
||||
final CharSequence text = displayViewState.getText();
|
||||
if (!StringUtils.isEmpty(text)) {
|
||||
CalculatorLocatorImpl.getInstance().getCalculatorClipboard().setText(text);
|
||||
CalculatorLocatorImpl.getInstance().getCalculatorNotifier().showMessage(CalculatorMessage.newInfoMessage(CalculatorMessages.result_copied));
|
||||
CalculatorLocatorImpl.getInstance().getClipboard().setText(text);
|
||||
CalculatorLocatorImpl.getInstance().getNotifier().showMessage(CalculatorMessage.newInfoMessage(CalculatorMessages.result_copied));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorLeft() {
|
||||
CalculatorLocatorImpl.getInstance().getEditor().moveCursorLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorRight() {
|
||||
CalculatorLocatorImpl.getInstance().getEditor().moveCursorRight();
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistory;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
@@ -9,30 +10,33 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public interface CalculatorLocator {
|
||||
|
||||
@NotNull
|
||||
JCalculatorEngine getCalculatorEngine();
|
||||
void init(@NotNull Calculator calculator,
|
||||
@NotNull CalculatorEngine engine,
|
||||
@NotNull CalculatorClipboard clipboard,
|
||||
@NotNull CalculatorNotifier notifier,
|
||||
@NotNull CalculatorHistory history);
|
||||
|
||||
@NotNull
|
||||
Calculator getCalculator();
|
||||
|
||||
@NotNull
|
||||
CalculatorDisplay getCalculatorDisplay();
|
||||
CalculatorEngine getEngine();
|
||||
|
||||
@NotNull
|
||||
CalculatorEditor getCalculatorEditor();
|
||||
|
||||
void setCalculatorEngine(@NotNull JCalculatorEngine calculatorEngine);
|
||||
CalculatorDisplay getDisplay();
|
||||
|
||||
@NotNull
|
||||
CalculatorKeyboard getCalculatorKeyboard();
|
||||
CalculatorEditor getEditor();
|
||||
|
||||
@NotNull
|
||||
CalculatorClipboard getCalculatorClipboard();
|
||||
|
||||
void setCalculatorClipboard(@NotNull CalculatorClipboard calculatorClipboard);
|
||||
CalculatorKeyboard getKeyboard();
|
||||
|
||||
@NotNull
|
||||
CalculatorNotifier getCalculatorNotifier();
|
||||
CalculatorClipboard getClipboard();
|
||||
|
||||
void setCalculatorNotifier(@NotNull CalculatorNotifier calculatorNotifier);
|
||||
@NotNull
|
||||
CalculatorNotifier getNotifier();
|
||||
|
||||
@NotNull
|
||||
CalculatorHistory getHistory();
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistory;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
@@ -10,19 +11,22 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class CalculatorLocatorImpl implements CalculatorLocator {
|
||||
|
||||
@NotNull
|
||||
private JCalculatorEngine calculatorEngine;
|
||||
private CalculatorEngine calculatorEngine;
|
||||
|
||||
@NotNull
|
||||
private final Calculator calculator = new CalculatorImpl();
|
||||
private Calculator calculator;
|
||||
|
||||
@NotNull
|
||||
private final CalculatorEditor calculatorEditor = new CalculatorEditorImpl(calculator);
|
||||
private CalculatorEditor calculatorEditor;
|
||||
|
||||
@NotNull
|
||||
private final CalculatorDisplay calculatorDisplay = new CalculatorDisplayImpl(calculator);
|
||||
private CalculatorDisplay calculatorDisplay;
|
||||
|
||||
@NotNull
|
||||
private final CalculatorKeyboard calculatorKeyboard = new CalculatorKeyboardImpl(calculator);
|
||||
private CalculatorKeyboard calculatorKeyboard;
|
||||
|
||||
@NotNull
|
||||
private CalculatorHistory calculatorHistory;
|
||||
|
||||
@NotNull
|
||||
private CalculatorNotifier calculatorNotifier = new DummyCalculatorNotifier();
|
||||
@@ -36,6 +40,24 @@ public class CalculatorLocatorImpl implements CalculatorLocator {
|
||||
private CalculatorLocatorImpl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(@NotNull Calculator calculator,
|
||||
@NotNull CalculatorEngine engine,
|
||||
@NotNull CalculatorClipboard clipboard,
|
||||
@NotNull CalculatorNotifier notifier,
|
||||
@NotNull CalculatorHistory history) {
|
||||
|
||||
this.calculator = calculator;
|
||||
this.calculatorEngine = engine;
|
||||
this.calculatorClipboard = clipboard;
|
||||
this.calculatorNotifier = notifier;
|
||||
this.calculatorHistory = history;
|
||||
|
||||
calculatorEditor = new CalculatorEditorImpl(this.calculator);
|
||||
calculatorDisplay = new CalculatorDisplayImpl(this.calculator);
|
||||
calculatorKeyboard = new CalculatorKeyboardImpl(this.calculator);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CalculatorLocator getInstance() {
|
||||
return instance;
|
||||
@@ -43,7 +65,7 @@ public class CalculatorLocatorImpl implements CalculatorLocator {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JCalculatorEngine getCalculatorEngine() {
|
||||
public CalculatorEngine getEngine() {
|
||||
return calculatorEngine;
|
||||
}
|
||||
|
||||
@@ -53,48 +75,39 @@ public class CalculatorLocatorImpl implements CalculatorLocator {
|
||||
return this.calculator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCalculatorEngine(@NotNull JCalculatorEngine calculatorEngine) {
|
||||
this.calculatorEngine = calculatorEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CalculatorDisplay getCalculatorDisplay() {
|
||||
public CalculatorDisplay getDisplay() {
|
||||
return calculatorDisplay;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CalculatorEditor getCalculatorEditor() {
|
||||
public CalculatorEditor getEditor() {
|
||||
return calculatorEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CalculatorKeyboard getCalculatorKeyboard() {
|
||||
public CalculatorKeyboard getKeyboard() {
|
||||
return calculatorKeyboard;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CalculatorClipboard getCalculatorClipboard() {
|
||||
public CalculatorClipboard getClipboard() {
|
||||
return calculatorClipboard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCalculatorClipboard(@NotNull CalculatorClipboard calculatorClipboard) {
|
||||
this.calculatorClipboard = calculatorClipboard;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CalculatorNotifier getCalculatorNotifier() {
|
||||
public CalculatorNotifier getNotifier() {
|
||||
return calculatorNotifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCalculatorNotifier(@NotNull CalculatorNotifier calculatorNotifier) {
|
||||
this.calculatorNotifier = calculatorNotifier;
|
||||
@NotNull
|
||||
public CalculatorHistory getHistory() {
|
||||
return calculatorHistory;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||
* For more information, please, contact se.solovyev@gmail.com
|
||||
* or visit http://se.solovyev.org
|
||||
*/
|
||||
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.common.math.MathEntity;
|
||||
import org.solovyev.common.math.MathRegistry;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/30/11
|
||||
* Time: 1:02 AM
|
||||
*/
|
||||
public interface CalculatorMathRegistry<T extends MathEntity> extends MathRegistry<T> {
|
||||
|
||||
@Nullable
|
||||
String getDescription(@NotNull String mathEntityName);
|
||||
|
||||
@Nullable
|
||||
String getCategory(@NotNull T mathEntity);
|
||||
|
||||
void load();
|
||||
|
||||
void save();
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/22/12
|
||||
* Time: 7:13 PM
|
||||
*/
|
||||
public final class CalculatorUtils {
|
||||
|
||||
static final long FIRST_ID = 0;
|
||||
|
||||
private CalculatorUtils() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CalculatorEventDataId createFirstEventDataId() {
|
||||
return CalculatorEventDataIdImpl.newInstance(FIRST_ID, FIRST_ID);
|
||||
}
|
||||
}
|
@@ -1,147 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||
* For more information, please, contact se.solovyev@gmail.com
|
||||
* or visit http://se.solovyev.org
|
||||
*/
|
||||
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import jscl.math.function.IConstant;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.text.TextProcessor;
|
||||
import org.solovyev.common.StartsWithFinder;
|
||||
import org.solovyev.android.calculator.math.MathType;
|
||||
import org.solovyev.common.collections.CollectionsUtils;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ToJsclTextProcessor implements TextProcessor<PreparedExpression, String> {
|
||||
|
||||
@NotNull
|
||||
private static final Integer MAX_DEPTH = 20;
|
||||
|
||||
@NotNull
|
||||
private static final TextProcessor<PreparedExpression, String> instance = new ToJsclTextProcessor();
|
||||
|
||||
private ToJsclTextProcessor() {
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static TextProcessor<PreparedExpression, String> getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public PreparedExpression process(@NotNull String s) throws CalculatorParseException {
|
||||
return processWithDepth(s, 0, new ArrayList<IConstant>());
|
||||
}
|
||||
|
||||
private static PreparedExpression processWithDepth(@NotNull String s, int depth, @NotNull List<IConstant> undefinedVars) throws CalculatorParseException {
|
||||
return replaceVariables(processExpression(s).toString(), depth, undefinedVars);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static StringBuilder processExpression(@NotNull String s) throws CalculatorParseException {
|
||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
||||
final StringBuilder result = new StringBuilder();
|
||||
|
||||
MathType.Result mathTypeResult = null;
|
||||
MathType.Result mathTypeBefore;
|
||||
|
||||
final LiteNumberBuilder nb = new LiteNumberBuilder(CalculatorLocatorImpl.getInstance().getCalculatorEngine().getEngine());
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (s.charAt(i) == ' ') continue;
|
||||
startsWithFinder.setI(i);
|
||||
|
||||
mathTypeBefore = mathTypeResult == null ? null : mathTypeResult;
|
||||
|
||||
mathTypeResult = MathType.getType(s, i, nb.isHexMode());
|
||||
|
||||
nb.process(mathTypeResult);
|
||||
|
||||
if (mathTypeBefore != null) {
|
||||
|
||||
final MathType current = mathTypeResult.getMathType();
|
||||
|
||||
if (current.isNeedMultiplicationSignBefore(mathTypeBefore.getMathType())) {
|
||||
result.append("*");
|
||||
}
|
||||
}
|
||||
|
||||
if (mathTypeBefore != null &&
|
||||
(mathTypeBefore.getMathType() == MathType.function || mathTypeBefore.getMathType() == MathType.operator) &&
|
||||
CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) {
|
||||
throw new CalculatorParseException(i, s, new CalculatorMessage(CalculatorMessages.msg_005, MessageType.error, mathTypeBefore.getMatch()));
|
||||
}
|
||||
|
||||
i = mathTypeResult.processToJscl(result, i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PreparedExpression replaceVariables(@NotNull final String s, int depth, @NotNull List<IConstant> undefinedVars) throws CalculatorParseException {
|
||||
if (depth >= MAX_DEPTH) {
|
||||
throw new CalculatorParseException(s, new CalculatorMessage(CalculatorMessages.msg_006, MessageType.error));
|
||||
} else {
|
||||
depth++;
|
||||
}
|
||||
|
||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
||||
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
startsWithFinder.setI(i);
|
||||
|
||||
int offset = 0;
|
||||
String functionName = CollectionsUtils.find(MathType.function.getTokens(), startsWithFinder);
|
||||
if (functionName == null) {
|
||||
String operatorName = CollectionsUtils.find(MathType.operator.getTokens(), startsWithFinder);
|
||||
if (operatorName == null) {
|
||||
String varName = CollectionsUtils.find(CalculatorLocatorImpl.getInstance().getCalculatorEngine().getVarsRegistry().getNames(), startsWithFinder);
|
||||
if (varName != null) {
|
||||
final IConstant var = CalculatorLocatorImpl.getInstance().getCalculatorEngine().getVarsRegistry().get(varName);
|
||||
if (var != null) {
|
||||
if (!var.isDefined()) {
|
||||
undefinedVars.add(var);
|
||||
result.append(varName);
|
||||
offset = varName.length();
|
||||
} else {
|
||||
final String value = var.getValue();
|
||||
assert value != null;
|
||||
|
||||
if ( var.getDoubleValue() != null ) {
|
||||
//result.append(value);
|
||||
// NOTE: append varName as JSCL engine will convert it to double if needed
|
||||
result.append(varName);
|
||||
} else {
|
||||
result.append("(").append(processWithDepth(value, depth, undefinedVars)).append(")");
|
||||
}
|
||||
offset = varName.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.append(operatorName);
|
||||
offset = operatorName.length();
|
||||
}
|
||||
} else {
|
||||
result.append(functionName);
|
||||
offset = functionName.length();
|
||||
}
|
||||
|
||||
|
||||
if (offset == 0) {
|
||||
result.append(s.charAt(i));
|
||||
} else {
|
||||
i += offset - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return new PreparedExpression(result.toString(), undefinedVars);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||
* For more information, please, contact se.solovyev@gmail.com
|
||||
* or visit http://se.solovyev.org
|
||||
*/
|
||||
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import jscl.math.function.IConstant;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.text.TextProcessor;
|
||||
import org.solovyev.common.StartsWithFinder;
|
||||
import org.solovyev.android.calculator.math.MathType;
|
||||
import org.solovyev.common.collections.CollectionsUtils;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ToJsclTextProcessor implements TextProcessor<PreparedExpression, String> {
|
||||
|
||||
@NotNull
|
||||
private static final Integer MAX_DEPTH = 20;
|
||||
|
||||
@NotNull
|
||||
private static final TextProcessor<PreparedExpression, String> instance = new ToJsclTextProcessor();
|
||||
|
||||
private ToJsclTextProcessor() {
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static TextProcessor<PreparedExpression, String> getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public PreparedExpression process(@NotNull String s) throws CalculatorParseException {
|
||||
return processWithDepth(s, 0, new ArrayList<IConstant>());
|
||||
}
|
||||
|
||||
private static PreparedExpression processWithDepth(@NotNull String s, int depth, @NotNull List<IConstant> undefinedVars) throws CalculatorParseException {
|
||||
return replaceVariables(processExpression(s).toString(), depth, undefinedVars);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static StringBuilder processExpression(@NotNull String s) throws CalculatorParseException {
|
||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
||||
final StringBuilder result = new StringBuilder();
|
||||
|
||||
MathType.Result mathTypeResult = null;
|
||||
MathType.Result mathTypeBefore;
|
||||
|
||||
final LiteNumberBuilder nb = new LiteNumberBuilder(CalculatorLocatorImpl.getInstance().getEngine().getEngine());
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (s.charAt(i) == ' ') continue;
|
||||
startsWithFinder.setI(i);
|
||||
|
||||
mathTypeBefore = mathTypeResult == null ? null : mathTypeResult;
|
||||
|
||||
mathTypeResult = MathType.getType(s, i, nb.isHexMode());
|
||||
|
||||
nb.process(mathTypeResult);
|
||||
|
||||
if (mathTypeBefore != null) {
|
||||
|
||||
final MathType current = mathTypeResult.getMathType();
|
||||
|
||||
if (current.isNeedMultiplicationSignBefore(mathTypeBefore.getMathType())) {
|
||||
result.append("*");
|
||||
}
|
||||
}
|
||||
|
||||
if (mathTypeBefore != null &&
|
||||
(mathTypeBefore.getMathType() == MathType.function || mathTypeBefore.getMathType() == MathType.operator) &&
|
||||
CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) {
|
||||
throw new CalculatorParseException(i, s, new CalculatorMessage(CalculatorMessages.msg_005, MessageType.error, mathTypeBefore.getMatch()));
|
||||
}
|
||||
|
||||
i = mathTypeResult.processToJscl(result, i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PreparedExpression replaceVariables(@NotNull final String s, int depth, @NotNull List<IConstant> undefinedVars) throws CalculatorParseException {
|
||||
if (depth >= MAX_DEPTH) {
|
||||
throw new CalculatorParseException(s, new CalculatorMessage(CalculatorMessages.msg_006, MessageType.error));
|
||||
} else {
|
||||
depth++;
|
||||
}
|
||||
|
||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
|
||||
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
startsWithFinder.setI(i);
|
||||
|
||||
int offset = 0;
|
||||
String functionName = CollectionsUtils.find(MathType.function.getTokens(), startsWithFinder);
|
||||
if (functionName == null) {
|
||||
String operatorName = CollectionsUtils.find(MathType.operator.getTokens(), startsWithFinder);
|
||||
if (operatorName == null) {
|
||||
String varName = CollectionsUtils.find(CalculatorLocatorImpl.getInstance().getEngine().getVarsRegistry().getNames(), startsWithFinder);
|
||||
if (varName != null) {
|
||||
final IConstant var = CalculatorLocatorImpl.getInstance().getEngine().getVarsRegistry().get(varName);
|
||||
if (var != null) {
|
||||
if (!var.isDefined()) {
|
||||
undefinedVars.add(var);
|
||||
result.append(varName);
|
||||
offset = varName.length();
|
||||
} else {
|
||||
final String value = var.getValue();
|
||||
assert value != null;
|
||||
|
||||
if ( var.getDoubleValue() != null ) {
|
||||
//result.append(value);
|
||||
// NOTE: append varName as JSCL engine will convert it to double if needed
|
||||
result.append(varName);
|
||||
} else {
|
||||
result.append("(").append(processWithDepth(value, depth, undefinedVars)).append(")");
|
||||
}
|
||||
offset = varName.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.append(operatorName);
|
||||
offset = operatorName.length();
|
||||
}
|
||||
} else {
|
||||
result.append(functionName);
|
||||
offset = functionName.length();
|
||||
}
|
||||
|
||||
|
||||
if (offset == 0) {
|
||||
result.append(s.charAt(i));
|
||||
} else {
|
||||
i += offset - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return new PreparedExpression(result.toString(), undefinedVars);
|
||||
}
|
||||
}
|
||||
|
@@ -1,21 +1,33 @@
|
||||
package org.solovyev.android.calculator.history;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.CalculatorEventListener;
|
||||
import org.solovyev.common.history.HistoryHelper;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 16:11
|
||||
*/
|
||||
public interface CalculatorHistory extends HistoryHelper<CalculatorHistoryState>, CalculatorEventListener {
|
||||
|
||||
void fromXml(@NotNull String xml);
|
||||
|
||||
String toXml();
|
||||
|
||||
void clearSavedHistory();
|
||||
|
||||
void removeSavedHistory(@NotNull CalculatorHistoryState historyState);
|
||||
}
|
||||
package org.solovyev.android.calculator.history;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.CalculatorEventListener;
|
||||
import org.solovyev.common.history.HistoryHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 16:11
|
||||
*/
|
||||
public interface CalculatorHistory extends HistoryHelper<CalculatorHistoryState>, CalculatorEventListener {
|
||||
|
||||
void load();
|
||||
|
||||
void save();
|
||||
|
||||
void fromXml(@NotNull String xml);
|
||||
|
||||
String toXml();
|
||||
|
||||
void clearSavedHistory();
|
||||
|
||||
void removeSavedHistory(@NotNull CalculatorHistoryState historyState);
|
||||
|
||||
@NotNull
|
||||
List<CalculatorHistoryState> getSavedHistory();
|
||||
|
||||
@NotNull
|
||||
CalculatorHistoryState addSavedState(@NotNull CalculatorHistoryState historyState);
|
||||
}
|
||||
|
@@ -31,29 +31,41 @@ public class CalculatorHistoryImpl implements CalculatorHistory {
|
||||
private final List<CalculatorHistoryState> savedHistory = new ArrayList<CalculatorHistoryState>();
|
||||
|
||||
@NotNull
|
||||
private volatile CalculatorEventDataId lastEventDataId = CalculatorLocatorImpl.getInstance().getCalculator().createFirstEventDataId();
|
||||
private volatile CalculatorEventDataId lastEventDataId = CalculatorUtils.createFirstEventDataId();
|
||||
|
||||
@Nullable
|
||||
private volatile CalculatorEditorViewState lastEditorViewState;
|
||||
|
||||
public CalculatorHistoryImpl(@NotNull Calculator calculator) {
|
||||
calculator.addCalculatorEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.history.isEmpty();
|
||||
synchronized (history) {
|
||||
return this.history.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalculatorHistoryState getLastHistoryState() {
|
||||
return this.history.getLastHistoryState();
|
||||
synchronized (history) {
|
||||
return this.history.getLastHistoryState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUndoAvailable() {
|
||||
return history.isUndoAvailable();
|
||||
synchronized (history) {
|
||||
return history.isUndoAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) {
|
||||
return history.undo(currentState);
|
||||
synchronized (history) {
|
||||
return history.undo(currentState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,40 +75,54 @@ public class CalculatorHistoryImpl implements CalculatorHistory {
|
||||
|
||||
@Override
|
||||
public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) {
|
||||
return history.redo(currentState);
|
||||
synchronized (history) {
|
||||
return history.redo(currentState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionAvailable(@NotNull HistoryAction historyAction) {
|
||||
return history.isActionAvailable(historyAction);
|
||||
synchronized (history) {
|
||||
return history.isActionAvailable(historyAction);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalculatorHistoryState doAction(@NotNull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) {
|
||||
return history.doAction(historyAction, currentState);
|
||||
synchronized (history) {
|
||||
return history.doAction(historyAction, currentState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addState(@Nullable CalculatorHistoryState currentState) {
|
||||
history.addState(currentState);
|
||||
synchronized (history) {
|
||||
history.addState(currentState);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<CalculatorHistoryState> getStates() {
|
||||
return history.getStates();
|
||||
synchronized (history) {
|
||||
return history.getStates();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.history.clear();
|
||||
synchronized (history) {
|
||||
this.history.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<CalculatorHistoryState> getSavedHistory() {
|
||||
return Collections.unmodifiableList(savedHistory);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public CalculatorHistoryState addSavedState(@NotNull CalculatorHistoryState historyState) {
|
||||
if (historyState.isSaved()) {
|
||||
@@ -113,6 +139,16 @@ public class CalculatorHistoryImpl implements CalculatorHistory {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
// todo serso: create saved/loader class
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
// todo serso: create saved/loader class
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromXml(@NotNull String xml) {
|
||||
clearSavedHistory();
|
||||
@@ -148,20 +184,27 @@ public class CalculatorHistoryImpl implements CalculatorHistory {
|
||||
if (calculatorEventData.isAfter(this.lastEventDataId)) {
|
||||
final boolean sameSequence = calculatorEventData.isSameSequence(this.lastEventDataId);
|
||||
|
||||
this.lastEventDataId = calculatorEventData;
|
||||
if (sameSequence || calculatorEventData.isAfterSequence(this.lastEventDataId)) {
|
||||
this.lastEventDataId = calculatorEventData;
|
||||
|
||||
switch (calculatorEventType) {
|
||||
case editor_state_changed:
|
||||
final CalculatorEditorChangeEventData changeEventData = (CalculatorEditorChangeEventData) data;
|
||||
lastEditorViewState = changeEventData.getNewState();
|
||||
break;
|
||||
case display_state_changed:
|
||||
if (sameSequence) {
|
||||
|
||||
} else {
|
||||
lastEditorViewState = null;
|
||||
}
|
||||
break;
|
||||
switch (calculatorEventType) {
|
||||
case editor_state_changed:
|
||||
final CalculatorEditorChangeEventData editorChangeData = (CalculatorEditorChangeEventData) data;
|
||||
lastEditorViewState = editorChangeData.getNewState();
|
||||
break;
|
||||
case display_state_changed:
|
||||
if (sameSequence) {
|
||||
if (lastEditorViewState != null) {
|
||||
final CalculatorEditorViewState editorViewState = lastEditorViewState;
|
||||
final CalculatorDisplayChangeEventData displayChangeData = (CalculatorDisplayChangeEventData) data;
|
||||
final CalculatorDisplayViewState displayViewState = displayChangeData.getNewState();
|
||||
addState(CalculatorHistoryState.newInstance(editorViewState, displayViewState));
|
||||
}
|
||||
} else {
|
||||
lastEditorViewState = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,70 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||
* For more information, please, contact se.solovyev@gmail.com
|
||||
*/
|
||||
|
||||
package org.solovyev.android.calculator.jscl;
|
||||
|
||||
|
||||
import jscl.math.Generic;
|
||||
import jscl.text.ParseException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.CalculatorLocatorImpl;
|
||||
import org.solovyev.android.calculator.text.DummyTextProcessor;
|
||||
import org.solovyev.android.calculator.text.FromJsclSimplifyTextProcessor;
|
||||
import org.solovyev.android.calculator.text.TextProcessor;
|
||||
|
||||
public enum JsclOperation {
|
||||
|
||||
simplify,
|
||||
elementary,
|
||||
numeric;
|
||||
|
||||
JsclOperation() {
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public TextProcessor<String, Generic> getFromProcessor() {
|
||||
switch (this) {
|
||||
case simplify:
|
||||
return FromJsclSimplifyTextProcessor.instance;
|
||||
case elementary:
|
||||
return DummyTextProcessor.instance;
|
||||
case numeric:
|
||||
return FromJsclNumericTextProcessor.instance;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final String evaluate(@NotNull String expression) throws ParseException {
|
||||
switch (this) {
|
||||
case simplify:
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getEngine().simplify(expression);
|
||||
case elementary:
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getEngine().elementary(expression);
|
||||
case numeric:
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getEngine().evaluate(expression);
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final Generic evaluateGeneric(@NotNull String expression) throws ParseException {
|
||||
switch (this) {
|
||||
case simplify:
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getEngine().simplifyGeneric(expression);
|
||||
case elementary:
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getEngine().elementaryGeneric(expression);
|
||||
case numeric:
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getEngine().evaluateGeneric(expression);
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||
* For more information, please, contact se.solovyev@gmail.com
|
||||
*/
|
||||
|
||||
package org.solovyev.android.calculator.jscl;
|
||||
|
||||
|
||||
import jscl.math.Generic;
|
||||
import jscl.text.ParseException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.android.calculator.CalculatorLocatorImpl;
|
||||
import org.solovyev.android.calculator.text.DummyTextProcessor;
|
||||
import org.solovyev.android.calculator.text.FromJsclSimplifyTextProcessor;
|
||||
import org.solovyev.android.calculator.text.TextProcessor;
|
||||
|
||||
public enum JsclOperation {
|
||||
|
||||
simplify,
|
||||
elementary,
|
||||
numeric;
|
||||
|
||||
JsclOperation() {
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public TextProcessor<String, Generic> getFromProcessor() {
|
||||
switch (this) {
|
||||
case simplify:
|
||||
return FromJsclSimplifyTextProcessor.instance;
|
||||
case elementary:
|
||||
return DummyTextProcessor.instance;
|
||||
case numeric:
|
||||
return FromJsclNumericTextProcessor.instance;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final String evaluate(@NotNull String expression) throws ParseException {
|
||||
switch (this) {
|
||||
case simplify:
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().simplify(expression);
|
||||
case elementary:
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().elementary(expression);
|
||||
case numeric:
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().evaluate(expression);
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final Generic evaluateGeneric(@NotNull String expression) throws ParseException {
|
||||
switch (this) {
|
||||
case simplify:
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().simplifyGeneric(expression);
|
||||
case elementary:
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().elementaryGeneric(expression);
|
||||
case numeric:
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getEngine().evaluateGeneric(expression);
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -1,445 +1,445 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||
* For more information, please, contact se.solovyev@gmail.com
|
||||
*/
|
||||
|
||||
package org.solovyev.android.calculator.math;
|
||||
|
||||
import jscl.JsclMathEngine;
|
||||
import jscl.NumeralBase;
|
||||
import jscl.math.function.Constants;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.CalculatorLocatorImpl;
|
||||
import org.solovyev.common.JPredicate;
|
||||
import org.solovyev.common.StartsWithFinder;
|
||||
import org.solovyev.android.calculator.CalculatorParseException;
|
||||
import org.solovyev.common.collections.CollectionsUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public enum MathType {
|
||||
|
||||
numeral_base(50, true, false, MathGroupType.number) {
|
||||
|
||||
private final List<String> tokens = new ArrayList<String>(10);
|
||||
{
|
||||
for (NumeralBase numeralBase : NumeralBase.values()) {
|
||||
tokens.add(numeralBase.getJsclPrefix());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
},
|
||||
|
||||
dot(200, true, true, MathGroupType.number, ".") {
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit;
|
||||
}
|
||||
},
|
||||
|
||||
grouping_separator(250, false, false, MathGroupType.number, "'", " "){
|
||||
@Override
|
||||
public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws CalculatorParseException {
|
||||
return i;
|
||||
}
|
||||
},
|
||||
|
||||
power_10(300, false, false, MathGroupType.number, "E"),
|
||||
|
||||
postfix_function(400, false, true, MathGroupType.function) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getPostfixFunctionsRegistry().getNames();
|
||||
}
|
||||
},
|
||||
|
||||
unary_operation(500, false, false, MathGroupType.operation, "-", "="),
|
||||
binary_operation(600, false, false, MathGroupType.operation, "-", "+", "*", "×", "∙", "/", "^") {
|
||||
@Override
|
||||
protected String getSubstituteToJscl(@NotNull String match) {
|
||||
if (match.equals("×") || match.equals("∙")) {
|
||||
return "*";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
open_group_symbol(800, true, false, MathGroupType.other, "[", "(", "{") {
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function && mathTypeBefore != operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSubstituteToJscl(@NotNull String match) {
|
||||
return "(";
|
||||
}
|
||||
},
|
||||
|
||||
close_group_symbol(900, false, true, MathGroupType.other, "]", ")", "}") {
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSubstituteToJscl(@NotNull String match) {
|
||||
return ")";
|
||||
}
|
||||
},
|
||||
|
||||
function(1000, true, true, MathGroupType.function) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getFunctionsRegistry().getNames();
|
||||
}
|
||||
},
|
||||
|
||||
operator(1050, true, true, MathGroupType.function) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getOperatorsRegistry().getNames();
|
||||
}
|
||||
},
|
||||
|
||||
constant(1100, true, true, MathGroupType.other) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return CalculatorLocatorImpl.getInstance().getCalculatorEngine().getVarsRegistry().getNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSubstituteFromJscl(@NotNull String match) {
|
||||
return Constants.INF_2.getName().equals(match) ? MathType.INFINITY : super.getSubstituteFromJscl(match);
|
||||
}
|
||||
},
|
||||
|
||||
digit(1125, true, true, MathGroupType.number) {
|
||||
|
||||
private final List<String> tokens = new ArrayList<String>(16);
|
||||
{
|
||||
for (Character character : NumeralBase.hex.getAcceptableCharacters()) {
|
||||
tokens.add(character.toString());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit && mathTypeBefore != dot /*&& mathTypeBefore != numeral_base*/;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
},
|
||||
|
||||
comma(1150, false, false, MathGroupType.other, ","),
|
||||
|
||||
text(1200, false, false, MathGroupType.other) {
|
||||
@Override
|
||||
public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) {
|
||||
if (match.length() > 0) {
|
||||
result.append(match.charAt(0));
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int processFromJscl(@NotNull StringBuilder result, int i, @NotNull String match) {
|
||||
if (match.length() > 0) {
|
||||
result.append(match.charAt(0));
|
||||
}
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
public static enum MathGroupType {
|
||||
function,
|
||||
number,
|
||||
operation,
|
||||
other
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final List<String> tokens;
|
||||
|
||||
@NotNull
|
||||
private final Integer priority;
|
||||
|
||||
private final boolean needMultiplicationSignBefore;
|
||||
|
||||
private final boolean needMultiplicationSignAfter;
|
||||
|
||||
@NotNull
|
||||
private final MathGroupType groupType;
|
||||
|
||||
MathType(@NotNull Integer priority,
|
||||
boolean needMultiplicationSignBefore,
|
||||
boolean needMultiplicationSignAfter,
|
||||
@NotNull MathGroupType groupType,
|
||||
@NotNull String... tokens) {
|
||||
this(priority, needMultiplicationSignBefore, needMultiplicationSignAfter, groupType, CollectionsUtils.asList(tokens));
|
||||
}
|
||||
|
||||
MathType(@NotNull Integer priority,
|
||||
boolean needMultiplicationSignBefore,
|
||||
boolean needMultiplicationSignAfter,
|
||||
@NotNull MathGroupType groupType,
|
||||
@NotNull List<String> tokens) {
|
||||
this.priority = priority;
|
||||
this.needMultiplicationSignBefore = needMultiplicationSignBefore;
|
||||
this.needMultiplicationSignAfter = needMultiplicationSignAfter;
|
||||
this.groupType = groupType;
|
||||
this.tokens = Collections.unmodifiableList(tokens);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MathGroupType getGroupType() {
|
||||
return groupType;
|
||||
}
|
||||
|
||||
/* public static int getPostfixFunctionStart(@NotNull CharSequence s, int position) throws ParseException {
|
||||
assert s.length() > position;
|
||||
|
||||
int numberOfOpenGroups = 0;
|
||||
int result = position;
|
||||
for (; result >= 0; result--) {
|
||||
|
||||
final MathType mathType = getType(s.toString(), result).getMathType();
|
||||
|
||||
if (CollectionsUtils.contains(mathType, digit, dot, grouping_separator, power_10)) {
|
||||
// continue
|
||||
} else if (mathType == close_group_symbol) {
|
||||
numberOfOpenGroups++;
|
||||
} else if (mathType == open_group_symbol) {
|
||||
if (numberOfOpenGroups > 0) {
|
||||
numberOfOpenGroups--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (stop(s, numberOfOpenGroups, result)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (numberOfOpenGroups != 0){
|
||||
throw new ParseException("Could not find start of prefix function!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean stop(CharSequence s, int numberOfOpenGroups, int i) {
|
||||
if (numberOfOpenGroups == 0) {
|
||||
if (i > 0) {
|
||||
final EndsWithFinder endsWithFinder = new EndsWithFinder(s);
|
||||
endsWithFinder.setI(i + 1);
|
||||
if (!CollectionsUtils.contains(function.getTokens(), FilterType.included, endsWithFinder)) {
|
||||
MathType type = getType(s.toString(), i).getMathType();
|
||||
if (type != constant) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}*/
|
||||
|
||||
@NotNull
|
||||
public List<String> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private boolean isNeedMultiplicationSignBefore() {
|
||||
return needMultiplicationSignBefore;
|
||||
}
|
||||
|
||||
private boolean isNeedMultiplicationSignAfter() {
|
||||
return needMultiplicationSignAfter;
|
||||
}
|
||||
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return needMultiplicationSignBefore && mathTypeBefore.isNeedMultiplicationSignAfter();
|
||||
}
|
||||
|
||||
public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws CalculatorParseException {
|
||||
final String substitute = getSubstituteToJscl(match);
|
||||
result.append(substitute == null ? match : substitute);
|
||||
return returnI(i, match);
|
||||
}
|
||||
|
||||
protected int returnI(int i, @NotNull String match) {
|
||||
if (match.length() > 1) {
|
||||
return i + match.length() - 1;
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
public int processFromJscl(@NotNull StringBuilder result, int i, @NotNull String match) {
|
||||
final String substitute = getSubstituteFromJscl(match);
|
||||
result.append(substitute == null ? match : substitute);
|
||||
return returnI(i, match);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String getSubstituteFromJscl(@NotNull String match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String getSubstituteToJscl(@NotNull String match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final List<String> openGroupSymbols = Arrays.asList("[]", "()", "{}");
|
||||
|
||||
public final static Character POWER_10 = 'E';
|
||||
|
||||
public static final String IMAGINARY_NUMBER = "i";
|
||||
public static final String IMAGINARY_NUMBER_JSCL = "√(-1)";
|
||||
|
||||
public static final String PI = "π";
|
||||
public static final String E = "e";
|
||||
public static final String C = "c";
|
||||
public static final Double C_VALUE = 299792458d;
|
||||
public static final String G = "G";
|
||||
public static final Double G_VALUE = 6.6738480E-11;
|
||||
public static final String H_REDUCED = "h";
|
||||
public static final Double H_REDUCED_VALUE = 6.6260695729E-34 / ( 2 * Math.PI );
|
||||
public final static String NAN = "NaN";
|
||||
|
||||
public final static String INFINITY = "∞";
|
||||
public final static String INFINITY_JSCL = "Infinity";
|
||||
|
||||
|
||||
/**
|
||||
* Method determines mathematical entity type for text substring starting from ith index
|
||||
*
|
||||
*
|
||||
* @param text analyzed text
|
||||
* @param i index which points to start of substring
|
||||
* @param hexMode
|
||||
* @return math entity type of substring starting from ith index of specified text
|
||||
*/
|
||||
@NotNull
|
||||
public static Result getType(@NotNull String text, int i, boolean hexMode) {
|
||||
if (i < 0) {
|
||||
throw new IllegalArgumentException("I must be more or equals to 0.");
|
||||
} else if (i >= text.length() && i != 0) {
|
||||
throw new IllegalArgumentException("I must be less than size of text.");
|
||||
} else if (i == 0 && text.length() == 0) {
|
||||
return new Result(MathType.text, text);
|
||||
}
|
||||
|
||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(text, i);
|
||||
|
||||
for (MathType mathType : getMathTypesByPriority()) {
|
||||
final String s = CollectionsUtils.find(mathType.getTokens(), startsWithFinder);
|
||||
if (s != null) {
|
||||
if ( s.length() == 1 ) {
|
||||
if (hexMode || JsclMathEngine.instance.getNumeralBase() == NumeralBase.hex) {
|
||||
final Character ch = s.charAt(0);
|
||||
if ( NumeralBase.hex.getAcceptableCharacters().contains(ch) ) {
|
||||
return new Result(MathType.digit, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Result(mathType, s);
|
||||
}
|
||||
}
|
||||
|
||||
return new Result(MathType.text, text.substring(i));
|
||||
}
|
||||
|
||||
|
||||
private static List<MathType> mathTypesByPriority;
|
||||
|
||||
@NotNull
|
||||
private static List<MathType> getMathTypesByPriority() {
|
||||
if (mathTypesByPriority == null) {
|
||||
final List<MathType> result = CollectionsUtils.asList(MathType.values());
|
||||
|
||||
Collections.sort(result, new Comparator<MathType>() {
|
||||
@Override
|
||||
public int compare(MathType l, MathType r) {
|
||||
return l.priority.compareTo(r.priority);
|
||||
}
|
||||
});
|
||||
|
||||
mathTypesByPriority = result;
|
||||
}
|
||||
|
||||
return mathTypesByPriority;
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
|
||||
@NotNull
|
||||
private final MathType mathType;
|
||||
|
||||
@NotNull
|
||||
private final String match;
|
||||
|
||||
public Result(@NotNull MathType mathType, @NotNull String match) {
|
||||
this.mathType = mathType;
|
||||
|
||||
this.match = match;
|
||||
}
|
||||
|
||||
public int processToJscl(@NotNull StringBuilder result, int i) throws CalculatorParseException {
|
||||
return mathType.processToJscl(result, i, match);
|
||||
}
|
||||
|
||||
public int processFromJscl(@NotNull StringBuilder result, int i) {
|
||||
return mathType.processFromJscl(result, i, match);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getMatch() {
|
||||
return match;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MathType getMathType() {
|
||||
return mathType;
|
||||
}
|
||||
}
|
||||
|
||||
private static class EndsWithFinder implements JPredicate<String> {
|
||||
|
||||
private int i;
|
||||
|
||||
@NotNull
|
||||
private final CharSequence targetString;
|
||||
|
||||
private EndsWithFinder(@NotNull CharSequence targetString) {
|
||||
this.targetString = targetString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(@Nullable String s) {
|
||||
return targetString.subSequence(0, i).toString().endsWith(s);
|
||||
}
|
||||
|
||||
public void setI(int i) {
|
||||
this.i = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
|
||||
* For more information, please, contact se.solovyev@gmail.com
|
||||
*/
|
||||
|
||||
package org.solovyev.android.calculator.math;
|
||||
|
||||
import jscl.JsclMathEngine;
|
||||
import jscl.NumeralBase;
|
||||
import jscl.math.function.Constants;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.CalculatorLocatorImpl;
|
||||
import org.solovyev.common.JPredicate;
|
||||
import org.solovyev.common.StartsWithFinder;
|
||||
import org.solovyev.android.calculator.CalculatorParseException;
|
||||
import org.solovyev.common.collections.CollectionsUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public enum MathType {
|
||||
|
||||
numeral_base(50, true, false, MathGroupType.number) {
|
||||
|
||||
private final List<String> tokens = new ArrayList<String>(10);
|
||||
{
|
||||
for (NumeralBase numeralBase : NumeralBase.values()) {
|
||||
tokens.add(numeralBase.getJsclPrefix());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
},
|
||||
|
||||
dot(200, true, true, MathGroupType.number, ".") {
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit;
|
||||
}
|
||||
},
|
||||
|
||||
grouping_separator(250, false, false, MathGroupType.number, "'", " "){
|
||||
@Override
|
||||
public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws CalculatorParseException {
|
||||
return i;
|
||||
}
|
||||
},
|
||||
|
||||
power_10(300, false, false, MathGroupType.number, "E"),
|
||||
|
||||
postfix_function(400, false, true, MathGroupType.function) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getPostfixFunctionsRegistry().getNames();
|
||||
}
|
||||
},
|
||||
|
||||
unary_operation(500, false, false, MathGroupType.operation, "-", "="),
|
||||
binary_operation(600, false, false, MathGroupType.operation, "-", "+", "*", "×", "∙", "/", "^") {
|
||||
@Override
|
||||
protected String getSubstituteToJscl(@NotNull String match) {
|
||||
if (match.equals("×") || match.equals("∙")) {
|
||||
return "*";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
open_group_symbol(800, true, false, MathGroupType.other, "[", "(", "{") {
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function && mathTypeBefore != operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSubstituteToJscl(@NotNull String match) {
|
||||
return "(";
|
||||
}
|
||||
},
|
||||
|
||||
close_group_symbol(900, false, true, MathGroupType.other, "]", ")", "}") {
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSubstituteToJscl(@NotNull String match) {
|
||||
return ")";
|
||||
}
|
||||
},
|
||||
|
||||
function(1000, true, true, MathGroupType.function) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getFunctionsRegistry().getNames();
|
||||
}
|
||||
},
|
||||
|
||||
operator(1050, true, true, MathGroupType.function) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getOperatorsRegistry().getNames();
|
||||
}
|
||||
},
|
||||
|
||||
constant(1100, true, true, MathGroupType.other) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return CalculatorLocatorImpl.getInstance().getEngine().getVarsRegistry().getNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSubstituteFromJscl(@NotNull String match) {
|
||||
return Constants.INF_2.getName().equals(match) ? MathType.INFINITY : super.getSubstituteFromJscl(match);
|
||||
}
|
||||
},
|
||||
|
||||
digit(1125, true, true, MathGroupType.number) {
|
||||
|
||||
private final List<String> tokens = new ArrayList<String>(16);
|
||||
{
|
||||
for (Character character : NumeralBase.hex.getAcceptableCharacters()) {
|
||||
tokens.add(character.toString());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit && mathTypeBefore != dot /*&& mathTypeBefore != numeral_base*/;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
},
|
||||
|
||||
comma(1150, false, false, MathGroupType.other, ","),
|
||||
|
||||
text(1200, false, false, MathGroupType.other) {
|
||||
@Override
|
||||
public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) {
|
||||
if (match.length() > 0) {
|
||||
result.append(match.charAt(0));
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int processFromJscl(@NotNull StringBuilder result, int i, @NotNull String match) {
|
||||
if (match.length() > 0) {
|
||||
result.append(match.charAt(0));
|
||||
}
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
public static enum MathGroupType {
|
||||
function,
|
||||
number,
|
||||
operation,
|
||||
other
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final List<String> tokens;
|
||||
|
||||
@NotNull
|
||||
private final Integer priority;
|
||||
|
||||
private final boolean needMultiplicationSignBefore;
|
||||
|
||||
private final boolean needMultiplicationSignAfter;
|
||||
|
||||
@NotNull
|
||||
private final MathGroupType groupType;
|
||||
|
||||
MathType(@NotNull Integer priority,
|
||||
boolean needMultiplicationSignBefore,
|
||||
boolean needMultiplicationSignAfter,
|
||||
@NotNull MathGroupType groupType,
|
||||
@NotNull String... tokens) {
|
||||
this(priority, needMultiplicationSignBefore, needMultiplicationSignAfter, groupType, CollectionsUtils.asList(tokens));
|
||||
}
|
||||
|
||||
MathType(@NotNull Integer priority,
|
||||
boolean needMultiplicationSignBefore,
|
||||
boolean needMultiplicationSignAfter,
|
||||
@NotNull MathGroupType groupType,
|
||||
@NotNull List<String> tokens) {
|
||||
this.priority = priority;
|
||||
this.needMultiplicationSignBefore = needMultiplicationSignBefore;
|
||||
this.needMultiplicationSignAfter = needMultiplicationSignAfter;
|
||||
this.groupType = groupType;
|
||||
this.tokens = Collections.unmodifiableList(tokens);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MathGroupType getGroupType() {
|
||||
return groupType;
|
||||
}
|
||||
|
||||
/* public static int getPostfixFunctionStart(@NotNull CharSequence s, int position) throws ParseException {
|
||||
assert s.length() > position;
|
||||
|
||||
int numberOfOpenGroups = 0;
|
||||
int result = position;
|
||||
for (; result >= 0; result--) {
|
||||
|
||||
final MathType mathType = getType(s.toString(), result).getMathType();
|
||||
|
||||
if (CollectionsUtils.contains(mathType, digit, dot, grouping_separator, power_10)) {
|
||||
// continue
|
||||
} else if (mathType == close_group_symbol) {
|
||||
numberOfOpenGroups++;
|
||||
} else if (mathType == open_group_symbol) {
|
||||
if (numberOfOpenGroups > 0) {
|
||||
numberOfOpenGroups--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (stop(s, numberOfOpenGroups, result)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (numberOfOpenGroups != 0){
|
||||
throw new ParseException("Could not find start of prefix function!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean stop(CharSequence s, int numberOfOpenGroups, int i) {
|
||||
if (numberOfOpenGroups == 0) {
|
||||
if (i > 0) {
|
||||
final EndsWithFinder endsWithFinder = new EndsWithFinder(s);
|
||||
endsWithFinder.setI(i + 1);
|
||||
if (!CollectionsUtils.contains(function.getTokens(), FilterType.included, endsWithFinder)) {
|
||||
MathType type = getType(s.toString(), i).getMathType();
|
||||
if (type != constant) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}*/
|
||||
|
||||
@NotNull
|
||||
public List<String> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private boolean isNeedMultiplicationSignBefore() {
|
||||
return needMultiplicationSignBefore;
|
||||
}
|
||||
|
||||
private boolean isNeedMultiplicationSignAfter() {
|
||||
return needMultiplicationSignAfter;
|
||||
}
|
||||
|
||||
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
|
||||
return needMultiplicationSignBefore && mathTypeBefore.isNeedMultiplicationSignAfter();
|
||||
}
|
||||
|
||||
public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws CalculatorParseException {
|
||||
final String substitute = getSubstituteToJscl(match);
|
||||
result.append(substitute == null ? match : substitute);
|
||||
return returnI(i, match);
|
||||
}
|
||||
|
||||
protected int returnI(int i, @NotNull String match) {
|
||||
if (match.length() > 1) {
|
||||
return i + match.length() - 1;
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
public int processFromJscl(@NotNull StringBuilder result, int i, @NotNull String match) {
|
||||
final String substitute = getSubstituteFromJscl(match);
|
||||
result.append(substitute == null ? match : substitute);
|
||||
return returnI(i, match);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String getSubstituteFromJscl(@NotNull String match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String getSubstituteToJscl(@NotNull String match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final List<String> openGroupSymbols = Arrays.asList("[]", "()", "{}");
|
||||
|
||||
public final static Character POWER_10 = 'E';
|
||||
|
||||
public static final String IMAGINARY_NUMBER = "i";
|
||||
public static final String IMAGINARY_NUMBER_JSCL = "√(-1)";
|
||||
|
||||
public static final String PI = "π";
|
||||
public static final String E = "e";
|
||||
public static final String C = "c";
|
||||
public static final Double C_VALUE = 299792458d;
|
||||
public static final String G = "G";
|
||||
public static final Double G_VALUE = 6.6738480E-11;
|
||||
public static final String H_REDUCED = "h";
|
||||
public static final Double H_REDUCED_VALUE = 6.6260695729E-34 / ( 2 * Math.PI );
|
||||
public final static String NAN = "NaN";
|
||||
|
||||
public final static String INFINITY = "∞";
|
||||
public final static String INFINITY_JSCL = "Infinity";
|
||||
|
||||
|
||||
/**
|
||||
* Method determines mathematical entity type for text substring starting from ith index
|
||||
*
|
||||
*
|
||||
* @param text analyzed text
|
||||
* @param i index which points to start of substring
|
||||
* @param hexMode
|
||||
* @return math entity type of substring starting from ith index of specified text
|
||||
*/
|
||||
@NotNull
|
||||
public static Result getType(@NotNull String text, int i, boolean hexMode) {
|
||||
if (i < 0) {
|
||||
throw new IllegalArgumentException("I must be more or equals to 0.");
|
||||
} else if (i >= text.length() && i != 0) {
|
||||
throw new IllegalArgumentException("I must be less than size of text.");
|
||||
} else if (i == 0 && text.length() == 0) {
|
||||
return new Result(MathType.text, text);
|
||||
}
|
||||
|
||||
final StartsWithFinder startsWithFinder = new StartsWithFinder(text, i);
|
||||
|
||||
for (MathType mathType : getMathTypesByPriority()) {
|
||||
final String s = CollectionsUtils.find(mathType.getTokens(), startsWithFinder);
|
||||
if (s != null) {
|
||||
if ( s.length() == 1 ) {
|
||||
if (hexMode || JsclMathEngine.instance.getNumeralBase() == NumeralBase.hex) {
|
||||
final Character ch = s.charAt(0);
|
||||
if ( NumeralBase.hex.getAcceptableCharacters().contains(ch) ) {
|
||||
return new Result(MathType.digit, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Result(mathType, s);
|
||||
}
|
||||
}
|
||||
|
||||
return new Result(MathType.text, text.substring(i));
|
||||
}
|
||||
|
||||
|
||||
private static List<MathType> mathTypesByPriority;
|
||||
|
||||
@NotNull
|
||||
private static List<MathType> getMathTypesByPriority() {
|
||||
if (mathTypesByPriority == null) {
|
||||
final List<MathType> result = CollectionsUtils.asList(MathType.values());
|
||||
|
||||
Collections.sort(result, new Comparator<MathType>() {
|
||||
@Override
|
||||
public int compare(MathType l, MathType r) {
|
||||
return l.priority.compareTo(r.priority);
|
||||
}
|
||||
});
|
||||
|
||||
mathTypesByPriority = result;
|
||||
}
|
||||
|
||||
return mathTypesByPriority;
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
|
||||
@NotNull
|
||||
private final MathType mathType;
|
||||
|
||||
@NotNull
|
||||
private final String match;
|
||||
|
||||
public Result(@NotNull MathType mathType, @NotNull String match) {
|
||||
this.mathType = mathType;
|
||||
|
||||
this.match = match;
|
||||
}
|
||||
|
||||
public int processToJscl(@NotNull StringBuilder result, int i) throws CalculatorParseException {
|
||||
return mathType.processToJscl(result, i, match);
|
||||
}
|
||||
|
||||
public int processFromJscl(@NotNull StringBuilder result, int i) {
|
||||
return mathType.processFromJscl(result, i, match);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getMatch() {
|
||||
return match;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MathType getMathType() {
|
||||
return mathType;
|
||||
}
|
||||
}
|
||||
|
||||
private static class EndsWithFinder implements JPredicate<String> {
|
||||
|
||||
private int i;
|
||||
|
||||
@NotNull
|
||||
private final CharSequence targetString;
|
||||
|
||||
private EndsWithFinder(@NotNull CharSequence targetString) {
|
||||
this.targetString = targetString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(@Nullable String s) {
|
||||
return targetString.subSequence(0, i).toString().endsWith(s);
|
||||
}
|
||||
|
||||
public void setI(int i) {
|
||||
this.i = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,94 +1,94 @@
|
||||
package org.solovyev.android.calculator.text;
|
||||
|
||||
import jscl.math.Generic;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.CalculatorLocatorImpl;
|
||||
import org.solovyev.android.calculator.math.MathType;
|
||||
import org.solovyev.android.calculator.CalculatorParseException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/20/11
|
||||
* Time: 2:59 PM
|
||||
*/
|
||||
public class FromJsclSimplifyTextProcessor implements TextProcessor<String, Generic> {
|
||||
|
||||
public static final FromJsclSimplifyTextProcessor instance = new FromJsclSimplifyTextProcessor();
|
||||
|
||||
public FromJsclSimplifyTextProcessor() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String process(@NotNull Generic from) throws CalculatorParseException {
|
||||
return removeMultiplicationSigns(from.toString());
|
||||
}
|
||||
|
||||
public String process(@NotNull String s) {
|
||||
return removeMultiplicationSigns(s);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String removeMultiplicationSigns(String s) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
MathType.Result mathTypeBefore;
|
||||
MathType.Result mathType = null;
|
||||
MathType.Result mathTypeAfter = null;
|
||||
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
mathTypeBefore = mathType;
|
||||
if (mathTypeAfter == null) {
|
||||
mathType = MathType.getType(s, i, false);
|
||||
} else {
|
||||
mathType = mathTypeAfter;
|
||||
}
|
||||
|
||||
char ch = s.charAt(i);
|
||||
if (ch == '*') {
|
||||
if (i + 1 < s.length()) {
|
||||
mathTypeAfter = MathType.getType(s, i + 1, false);
|
||||
} else {
|
||||
mathTypeAfter = null;
|
||||
}
|
||||
|
||||
if (needMultiplicationSign(mathTypeBefore == null ? null : mathTypeBefore.getMathType(), mathTypeAfter == null ? null : mathTypeAfter.getMathType())) {
|
||||
sb.append(CalculatorLocatorImpl.getInstance().getCalculatorEngine().getMultiplicationSign());
|
||||
}
|
||||
|
||||
} else {
|
||||
if (mathType.getMathType() == MathType.constant || mathType.getMathType() == MathType.function || mathType.getMathType() == MathType.operator) {
|
||||
sb.append(mathType.getMatch());
|
||||
i += mathType.getMatch().length() - 1;
|
||||
} else {
|
||||
sb.append(ch);
|
||||
}
|
||||
mathTypeAfter = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private final List<MathType> mathTypes = Arrays.asList(MathType.function, MathType.constant);
|
||||
|
||||
private boolean needMultiplicationSign(@Nullable MathType mathTypeBefore, @Nullable MathType mathTypeAfter) {
|
||||
if (mathTypeBefore == null || mathTypeAfter == null) {
|
||||
return true;
|
||||
} else if (mathTypes.contains(mathTypeBefore) || mathTypes.contains(mathTypeAfter)) {
|
||||
return false;
|
||||
} else if ( mathTypeBefore == MathType.close_group_symbol ) {
|
||||
return false;
|
||||
} else if ( mathTypeAfter == MathType.open_group_symbol ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package org.solovyev.android.calculator.text;
|
||||
|
||||
import jscl.math.Generic;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.CalculatorLocatorImpl;
|
||||
import org.solovyev.android.calculator.math.MathType;
|
||||
import org.solovyev.android.calculator.CalculatorParseException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/20/11
|
||||
* Time: 2:59 PM
|
||||
*/
|
||||
public class FromJsclSimplifyTextProcessor implements TextProcessor<String, Generic> {
|
||||
|
||||
public static final FromJsclSimplifyTextProcessor instance = new FromJsclSimplifyTextProcessor();
|
||||
|
||||
public FromJsclSimplifyTextProcessor() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String process(@NotNull Generic from) throws CalculatorParseException {
|
||||
return removeMultiplicationSigns(from.toString());
|
||||
}
|
||||
|
||||
public String process(@NotNull String s) {
|
||||
return removeMultiplicationSigns(s);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String removeMultiplicationSigns(String s) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
MathType.Result mathTypeBefore;
|
||||
MathType.Result mathType = null;
|
||||
MathType.Result mathTypeAfter = null;
|
||||
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
mathTypeBefore = mathType;
|
||||
if (mathTypeAfter == null) {
|
||||
mathType = MathType.getType(s, i, false);
|
||||
} else {
|
||||
mathType = mathTypeAfter;
|
||||
}
|
||||
|
||||
char ch = s.charAt(i);
|
||||
if (ch == '*') {
|
||||
if (i + 1 < s.length()) {
|
||||
mathTypeAfter = MathType.getType(s, i + 1, false);
|
||||
} else {
|
||||
mathTypeAfter = null;
|
||||
}
|
||||
|
||||
if (needMultiplicationSign(mathTypeBefore == null ? null : mathTypeBefore.getMathType(), mathTypeAfter == null ? null : mathTypeAfter.getMathType())) {
|
||||
sb.append(CalculatorLocatorImpl.getInstance().getEngine().getMultiplicationSign());
|
||||
}
|
||||
|
||||
} else {
|
||||
if (mathType.getMathType() == MathType.constant || mathType.getMathType() == MathType.function || mathType.getMathType() == MathType.operator) {
|
||||
sb.append(mathType.getMatch());
|
||||
i += mathType.getMatch().length() - 1;
|
||||
} else {
|
||||
sb.append(ch);
|
||||
}
|
||||
mathTypeAfter = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private final List<MathType> mathTypes = Arrays.asList(MathType.function, MathType.constant);
|
||||
|
||||
private boolean needMultiplicationSign(@Nullable MathType mathTypeBefore, @Nullable MathType mathTypeAfter) {
|
||||
if (mathTypeBefore == null || mathTypeAfter == null) {
|
||||
return true;
|
||||
} else if (mathTypes.contains(mathTypeBefore) || mathTypes.contains(mathTypeAfter)) {
|
||||
return false;
|
||||
} else if ( mathTypeBefore == MathType.close_group_symbol ) {
|
||||
return false;
|
||||
} else if ( mathTypeAfter == MathType.open_group_symbol ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user