New core implementation

This commit is contained in:
serso 2012-09-20 18:35:11 +04:00
parent eb37fe495b
commit 1d2aaa9d47
40 changed files with 1845 additions and 1153 deletions

View File

@ -1,85 +1,85 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator;
import jscl.MathEngine; import jscl.MathEngine;
import jscl.NumeralBase; import jscl.NumeralBase;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.text.StringUtils;
/** /**
* User: serso * User: serso
* Date: 12/15/11 * Date: 12/15/11
* Time: 9:01 PM * Time: 9:01 PM
*/ */
public abstract class AbstractNumberBuilder { public abstract class AbstractNumberBuilder {
@NotNull @NotNull
protected final MathEngine engine; protected final MathEngine engine;
@Nullable @Nullable
protected StringBuilder numberBuilder = null; protected StringBuilder numberBuilder = null;
@Nullable @Nullable
protected NumeralBase nb; protected NumeralBase nb;
protected AbstractNumberBuilder(@NotNull MathEngine engine) { protected AbstractNumberBuilder(@NotNull MathEngine engine) {
this.engine = engine; this.engine = engine;
this.nb = engine.getNumeralBase(); this.nb = engine.getNumeralBase();
} }
/** /**
* Method determines if we can continue to process current number * Method determines if we can continue to process current number
* *
* @param mathTypeResult current math type result * @param mathTypeResult current math type result
* @return true if we can continue of processing of current number, if false - new number should be constructed * @return true if we can continue of processing of current number, if false - new number should be constructed
*/ */
protected boolean canContinue(@NotNull MathType.Result mathTypeResult) { protected boolean canContinue(@NotNull MathType.Result mathTypeResult) {
boolean result = mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number && boolean result = mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number &&
!spaceBefore(mathTypeResult) && !spaceBefore(mathTypeResult) &&
numeralBaseCheck(mathTypeResult) && numeralBaseCheck(mathTypeResult) &&
numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult); numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult);
return result; return result;
} }
private boolean spaceBefore(@NotNull MathType.Result mathTypeResult) { private boolean spaceBefore(@NotNull MathType.Result mathTypeResult) {
return numberBuilder == null && StringUtils.isEmpty(mathTypeResult.getMatch().trim()); return numberBuilder == null && StringUtils.isEmpty(mathTypeResult.getMatch().trim());
} }
private boolean numeralBaseInTheStart(@NotNull MathType mathType) { private boolean numeralBaseInTheStart(@NotNull MathType mathType) {
return mathType != MathType.numeral_base || numberBuilder == null; return mathType != MathType.numeral_base || numberBuilder == null;
} }
private boolean numeralBaseCheck(@NotNull MathType.Result mathType) { private boolean numeralBaseCheck(@NotNull MathType.Result mathType) {
return mathType.getMathType() != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.getMatch().charAt(0)); return mathType.getMathType() != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.getMatch().charAt(0));
} }
private boolean isSignAfterE(@NotNull MathType.Result mathTypeResult) { private boolean isSignAfterE(@NotNull MathType.Result mathTypeResult) {
if (!isHexMode()) { if (!isHexMode()) {
if ("-".equals(mathTypeResult.getMatch()) || "+".equals(mathTypeResult.getMatch())) { if ("-".equals(mathTypeResult.getMatch()) || "+".equals(mathTypeResult.getMatch())) {
final StringBuilder localNb = numberBuilder; final StringBuilder localNb = numberBuilder;
if (localNb != null && localNb.length() > 0) { if (localNb != null && localNb.length() > 0) {
if (localNb.charAt(localNb.length() - 1) == MathType.POWER_10) { if (localNb.charAt(localNb.length() - 1) == MathType.POWER_10) {
return true; return true;
} }
} }
} }
} }
return false; return false;
} }
public boolean isHexMode() { public boolean isHexMode() {
return nb == NumeralBase.hex || (nb == null && engine.getNumeralBase() == NumeralBase.hex); return nb == NumeralBase.hex || (nb == null && engine.getNumeralBase() == NumeralBase.hex);
} }
@NotNull @NotNull
protected NumeralBase getNumeralBase() { protected NumeralBase getNumeralBase() {
return nb == null ? engine.getNumeralBase() : nb; return nb == null ? engine.getNumeralBase() : nb;
} }
} }

View File

@ -0,0 +1,9 @@
package org.solovyev.android.calculator;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:38
*/
public interface Calculator extends CalculatorEventContainer {
}

View File

@ -1,73 +1,72 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator;
import jscl.AbstractJsclArithmeticException; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.NotNull; import org.solovyev.common.exceptions.SersoException;
import org.solovyev.common.exceptions.SersoException; import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.Message; import org.solovyev.common.msg.MessageType;
import org.solovyev.common.msg.MessageType;
import java.util.List;
import java.util.List; import java.util.Locale;
import java.util.Locale;
/**
/** * User: serso
* User: serso * Date: 12/8/11
* Date: 12/8/11 * Time: 1:27 AM
* Time: 1:27 AM */
*/ public class CalculatorEvalException extends SersoException implements Message {
public class CalculatorEvalException extends SersoException implements Message {
@NotNull
@NotNull private final Message message;
private final Message message;
@NotNull
@NotNull private final String expression;
private final String expression;
public CalculatorEvalException(@NotNull Message message, @NotNull Throwable cause, String expression) {
public CalculatorEvalException(@NotNull Message message, @NotNull Throwable cause, String expression) { super(cause);
super(cause); this.message = message;
this.message = message; this.expression = expression;
this.expression = expression; }
}
@NotNull
@NotNull public String getExpression() {
public String getExpression() { return expression;
return expression; }
}
@NotNull
@NotNull @Override
@Override public String getMessageCode() {
public String getMessageCode() { return this.message.getMessageCode();
return this.message.getMessageCode(); }
}
@NotNull
@NotNull @Override
@Override public List<Object> getParameters() {
public List<Object> getParameters() { return this.message.getParameters();
return this.message.getParameters(); }
}
@NotNull
@NotNull @Override
@Override public MessageType getMessageType() {
public MessageType getMessageType() { return this.message.getMessageType();
return this.message.getMessageType(); }
}
@Override
@Override @NotNull
@NotNull public String getLocalizedMessage() {
public String getLocalizedMessage() { return this.message.getLocalizedMessage(Locale.getDefault());
return this.message.getLocalizedMessage(Locale.getDefault()); }
}
@NotNull
@NotNull @Override
@Override public String getLocalizedMessage(@NotNull Locale locale) {
public String getLocalizedMessage(@NotNull Locale locale) { return this.message.getLocalizedMessage(locale);
return this.message.getLocalizedMessage(locale); }
} }
}

View File

@ -0,0 +1,57 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:39
*/
public interface CalculatorEventContainer {
void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener);
void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener);
void fireCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data);
void fireCalculatorEvents(@NotNull List<CalculatorEvent> calculatorEvents);
public static class CalculatorEvent {
@NotNull
private CalculatorEventData calculatorEventData;
@NotNull
private CalculatorEventType calculatorEventType;
@Nullable
private Object data;
public CalculatorEvent(@NotNull CalculatorEventData calculatorEventData,
@NotNull CalculatorEventType calculatorEventType,
@Nullable Object data) {
this.calculatorEventData = calculatorEventData;
this.calculatorEventType = calculatorEventType;
this.data = data;
}
@NotNull
public CalculatorEventData getCalculatorEventData() {
return calculatorEventData;
}
@NotNull
public CalculatorEventType getCalculatorEventType() {
return calculatorEventType;
}
@Nullable
public Object getData() {
return data;
}
}
}

View File

@ -0,0 +1,11 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.Nullable;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:51
*/
public interface CalculatorEventData extends CalculatorEventDataId {
}

View File

@ -0,0 +1,17 @@
package org.solovyev.android.calculator;
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();
@Nullable
Long getCalculationId();
}

View File

@ -0,0 +1,61 @@
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 class CalculatorEventDataIdImpl implements CalculatorEventDataId {
private final long eventId;
@Nullable
private final Long calculationId;
private CalculatorEventDataIdImpl(long id,
@Nullable Long calculationId) {
this.eventId = id;
this.calculationId = calculationId;
}
@NotNull
public static CalculatorEventDataId newInstance(long id,
@Nullable Long calculationId) {
return new CalculatorEventDataIdImpl(id, calculationId);
}
@Override
public long getEventId() {
return this.eventId;
}
@Nullable
@Override
public Long getCalculationId() {
return this.calculationId;
}
@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 (calculationId != null ? !calculationId.equals(that.calculationId) : that.calculationId != null)
return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (eventId ^ (eventId >>> 32));
result = 31 * result + (calculationId != null ? calculationId.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,47 @@
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;
CalculatorEventDataImpl(@NotNull CalculatorEventDataId calculatorEventDataId) {
this.calculatorEventDataId = calculatorEventDataId;
}
@Override
public long getEventId() {
return calculatorEventDataId.getEventId();
}
@Override
@Nullable
public Long getCalculationId() {
return calculatorEventDataId.getCalculationId();
}
@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();
}
}

View File

@ -0,0 +1,17 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.EventListener;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:39
*/
public interface CalculatorEventListener extends EventListener {
void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data);
}

View File

@ -0,0 +1,9 @@
package org.solovyev.android.calculator;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:40
*/
public enum CalculatorEventType {
}

View File

@ -0,0 +1,168 @@
package org.solovyev.android.calculator;
import jscl.AbstractJsclArithmeticException;
import jscl.NumeralBaseException;
import jscl.math.Generic;
import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.common.msg.MessageRegistry;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:42
*/
public class CalculatorImpl implements Calculator {
@NotNull
private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer();
@NotNull
private static final Calculator instance = new CalculatorImpl();
@NotNull
private final AtomicLong counter = new AtomicLong(0);
@NotNull
private final Object lock = new Object();
@NotNull
private final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
@NotNull
private final Executor threadPoolExecutor = Executors.newFixedThreadPool(10);
private CalculatorImpl() {
}
@NotNull
public static Calculator getInstance() {
return instance;
}
@NotNull
private CalculatorEventDataId nextCalculatorEventDataId() {
long eventId = counter.incrementAndGet();
return CalculatorEventDataIdImpl.newInstance(eventId, eventId);
}
/*
**********************************************************************
*
* CALCULATION
*
**********************************************************************
*/
public void evaluate(@NotNull JsclOperation operation,
@NotNull String expression) {
evaluate(operation, expression, null);
}
public void evaluate(@NotNull final JsclOperation operation,
@NotNull final String expression,
@Nullable final MessageRegistry mr) {
final CalculatorEventDataId eventDataId = nextCalculatorEventDataId();
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
CalculatorImpl.this.evaluate(eventDataId, operation, expression, mr);
}
});
}
private void evaluate(@NotNull CalculatorEventDataId eventDataId,
@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr) {
synchronized (lock) {
PreparedExpression preparedExpression = null;
try {
preparedExpression = preprocessor.process(expression);
final String jsclExpression = preparedExpression.toString();
try {
final Generic genericResult = operation.evaluateGeneric(jsclExpression);
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!)
genericResult.toString();
//return new Result(operation.getFromProcessor().process(genericResult), operation, genericResult);
} catch (AbstractJsclArithmeticException e) {
handleException(eventDataId, operation, expression, mr, preparedExpression, null, new CalculatorEvalException(e, e, jsclExpression));
}
} catch (ArithmeticException e) {
//final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_1, MessageType.error, CalculatorApplication.getInstance(), e.getMessage());
handleException(operation, expression, mr, preparedExpression, new CalculatorParseException(jsclExpression, androidMessage));
} catch (StackOverflowError e) {
//final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_2, MessageType.error, CalculatorApplication.getInstance());
handleException(eventDataId, operation, expression, mr, preparedExpression, new CalculatorParseException(e), null);
} catch (jscl.text.ParseException e) {
//System.out.println(e.getMessage());
handleException(eventDataId, operation, expression, mr, preparedExpression, new CalculatorParseException(e), null);
} catch (ParseInterruptedException e) {
// do nothing - we ourselves interrupt the calculations
} catch (CalculatorParseException e) {
handleException(eventDataId, operation, expression, mr, preparedExpression, e, null);
}
}
}
private void handleException(@NotNull CalculatorEventDataId eventDataId,
@NotNull JsclOperation operation,
@NotNull String expression,
@Nullable MessageRegistry mr,
@Nullable PreparedExpression preparedExpression,
@Nullable CalculatorParseException parseException,
@Nullable CalculatorEvalException evalException) {
if (operation == JsclOperation.numeric && (preparedExpression != null && preparedExpression.isExistsUndefinedVar() || (evalException != null && evalException.getCause() instanceof NumeralBaseException))) {
evaluate(eventDataId, JsclOperation.simplify, expression, mr);
}
if (parseException != null) {
throw parseException;
} else {
throw evalException;
}
}
/*
**********************************************************************
*
* EVENTS
*
**********************************************************************
*/
@Override
public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
calculatorEventContainer.addCalculatorEventListener(calculatorEventListener);
}
@Override
public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
calculatorEventContainer.removeCalculatorEventListener(calculatorEventListener);
}
@Override
public void fireCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
calculatorEventContainer.fireCalculatorEvent(calculatorEventData, calculatorEventType, data);
}
@Override
public void fireCalculatorEvents(@NotNull List<CalculatorEvent> calculatorEvents) {
calculatorEventContainer.fireCalculatorEvents(calculatorEvents);
}
}

View File

@ -17,7 +17,7 @@ import org.solovyev.android.calculator.jscl.JsclOperation;
* Date: 12/17/11 * Date: 12/17/11
* Time: 9:45 PM * Time: 9:45 PM
*/ */
public interface ICalculatorDisplay extends Editor{ public interface JCalculatorDisplay extends Editor{
boolean isValid(); boolean isValid();

View File

@ -0,0 +1,50 @@
package org.solovyev.android.calculator;
import android.util.Log;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.utils.ListListenersContainer;
import java.util.Arrays;
import java.util.List;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:42
*/
public class ListCalculatorEventContainer implements CalculatorEventContainer {
@NotNull
private static final String TAG = "CalculatorEventData";
@NotNull
private final ListListenersContainer<CalculatorEventListener> listeners = new ListListenersContainer<CalculatorEventListener>();
@Override
public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
listeners.addListener(calculatorEventListener);
}
@Override
public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
listeners.removeListener(calculatorEventListener);
}
@Override
public void fireCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
fireCalculatorEvents(Arrays.asList(new CalculatorEvent(calculatorEventData, calculatorEventType, data)));
}
@Override
public void fireCalculatorEvents(@NotNull List<CalculatorEvent> calculatorEvents) {
final List<CalculatorEventListener> listeners = this.listeners.getListeners();
for (CalculatorEvent e : calculatorEvents) {
Log.d(TAG, "Event: " + e.getCalculatorEventType() + " with data: " + e.getData());
for (CalculatorEventListener listener : listeners) {
listener.onCalculatorEvent(e.getCalculatorEventData(), e.getCalculatorEventType(), e.getData());
}
}
}
}

View File

@ -1,55 +1,55 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator;
import jscl.MathEngine; import jscl.MathEngine;
import jscl.NumeralBase; import jscl.NumeralBase;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.math.MathType;
/** /**
* User: serso * User: serso
* Date: 12/15/11 * Date: 12/15/11
* Time: 8:33 PM * Time: 8:33 PM
*/ */
public class LiteNumberBuilder extends AbstractNumberBuilder { public class LiteNumberBuilder extends AbstractNumberBuilder {
public LiteNumberBuilder(@NotNull MathEngine engine) { public LiteNumberBuilder(@NotNull MathEngine engine) {
super(engine); super(engine);
this.nb = engine.getNumeralBase(); this.nb = engine.getNumeralBase();
} }
public void process(@NotNull MathType.Result mathTypeResult) { public void process(@NotNull MathType.Result mathTypeResult) {
if (canContinue(mathTypeResult)) { if (canContinue(mathTypeResult)) {
// let's continue building number // let's continue building number
if (numberBuilder == null) { if (numberBuilder == null) {
// if new number => create new builder // if new number => create new builder
numberBuilder = new StringBuilder(); numberBuilder = new StringBuilder();
} }
if (mathTypeResult.getMathType() != MathType.numeral_base) { if (mathTypeResult.getMathType() != MathType.numeral_base) {
// just add matching string // just add matching string
numberBuilder.append(mathTypeResult.getMatch()); numberBuilder.append(mathTypeResult.getMatch());
} else { } else {
// set explicitly numeral base (do not include it into number) // set explicitly numeral base (do not include it into number)
nb = NumeralBase.getByPrefix(mathTypeResult.getMatch()); nb = NumeralBase.getByPrefix(mathTypeResult.getMatch());
} }
} else { } else {
// process current number (and go to the next one) // process current number (and go to the next one)
if (numberBuilder != null) { if (numberBuilder != null) {
numberBuilder = null; numberBuilder = null;
// must set default numeral base (exit numeral base mode) // must set default numeral base (exit numeral base mode)
nb = engine.getNumeralBase(); nb = engine.getNumeralBase();
} }
} }
} }
} }

View File

@ -1,202 +1,203 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator;
import jscl.MathContext; import jscl.MathContext;
import jscl.MathEngine; import jscl.MathEngine;
import jscl.NumeralBase; import jscl.NumeralBase;
import jscl.math.numeric.Real; import jscl.math.numeric.Real;
import jscl.text.*; import jscl.text.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.AbstractNumberBuilder;
import org.solovyev.common.MutableObject; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.common.MutableObject;
import java.util.ArrayList;
import java.util.List; import java.util.ArrayList;
import java.util.List;
/**
* User: serso /**
* Date: 10/23/11 * User: serso
* Time: 2:57 PM * Date: 10/23/11
*/ * Time: 2:57 PM
public class NumberBuilder extends AbstractNumberBuilder { */
public class NumberBuilder extends AbstractNumberBuilder {
public NumberBuilder(@NotNull MathEngine engine) {
super(engine); public NumberBuilder(@NotNull MathEngine engine) {
} super(engine);
}
/**
* Method replaces number in text according to some rules (e.g. formatting) /**
* * Method replaces number in text according to some rules (e.g. formatting)
* @param text text where number can be replaced *
* @param mathTypeResult math type result of current token * @param text text where number can be replaced
* @param offset offset between new number length and old number length (newNumberLength - oldNumberLength) * @param mathTypeResult math type result of current token
* * @param offset offset between new number length and old number length (newNumberLength - oldNumberLength)
* *
* @return new math type result (as one can be changed due to substituting of number with constant) *
*/ * @return new math type result (as one can be changed due to substituting of number with constant)
@NotNull */
public MathType.Result process(@NotNull StringBuilder text, @NotNull MathType.Result mathTypeResult, @Nullable MutableObject<Integer> offset) { @NotNull
final MathType.Result possibleResult; public MathType.Result process(@NotNull StringBuilder text, @NotNull MathType.Result mathTypeResult, @Nullable MutableObject<Integer> offset) {
if (canContinue(mathTypeResult)) { final MathType.Result possibleResult;
// let's continue building number if (canContinue(mathTypeResult)) {
if (numberBuilder == null) { // let's continue building number
// if new number => create new builder if (numberBuilder == null) {
numberBuilder = new StringBuilder(); // if new number => create new builder
} numberBuilder = new StringBuilder();
}
if (mathTypeResult.getMathType() != MathType.numeral_base) {
// just add matching string if (mathTypeResult.getMathType() != MathType.numeral_base) {
numberBuilder.append(mathTypeResult.getMatch()); // just add matching string
} else { numberBuilder.append(mathTypeResult.getMatch());
// set explicitly numeral base (do not include it into number) } else {
nb = NumeralBase.getByPrefix(mathTypeResult.getMatch()); // set explicitly numeral base (do not include it into number)
} nb = NumeralBase.getByPrefix(mathTypeResult.getMatch());
}
possibleResult = null;
} else { possibleResult = null;
// process current number (and go to the next one) } else {
possibleResult = processNumber(text, offset); // process current number (and go to the next one)
} possibleResult = processNumber(text, offset);
}
return possibleResult == null ? mathTypeResult : possibleResult;
} return possibleResult == null ? mathTypeResult : possibleResult;
}
/**
* Method replaces number in text according to some rules (e.g. formatting) /**
* * Method replaces number in text according to some rules (e.g. formatting)
* @param text text where number can be replaced *
* @param offset offset between new number length and old number length (newNumberLength - oldNumberLength) * @param text text where number can be replaced
* * @param offset offset between new number length and old number length (newNumberLength - oldNumberLength)
* @return new math type result (as one can be changed due to substituting of number with constant) *
*/ * @return new math type result (as one can be changed due to substituting of number with constant)
@Nullable */
public MathType.Result processNumber(@NotNull StringBuilder text, @Nullable MutableObject<Integer> offset) { @Nullable
// total number of trimmed chars public MathType.Result processNumber(@NotNull StringBuilder text, @Nullable MutableObject<Integer> offset) {
int trimmedChars = 0; // total number of trimmed chars
int trimmedChars = 0;
String number = null;
String number = null;
// save numeral base (as later it might be replaced)
final NumeralBase localNb = getNumeralBase(); // toXml numeral base (as later it might be replaced)
final NumeralBase localNb = getNumeralBase();
if (numberBuilder != null) {
try { if (numberBuilder != null) {
number = numberBuilder.toString(); try {
number = numberBuilder.toString();
// let's get rid of unnecessary characters (grouping separators, + after E)
final List<String> tokens = new ArrayList<String>(); // let's get rid of unnecessary characters (grouping separators, + after E)
tokens.addAll(MathType.grouping_separator.getTokens()); final List<String> tokens = new ArrayList<String>();
// + after E can be omitted: 10+E = 10E (NOTE: - cannot be omitted ) tokens.addAll(MathType.grouping_separator.getTokens());
tokens.add("+"); // + after E can be omitted: 10+E = 10E (NOTE: - cannot be omitted )
for (String groupingSeparator : tokens) { tokens.add("+");
final String trimmedNumber = number.replace(groupingSeparator, ""); for (String groupingSeparator : tokens) {
trimmedChars += number.length() - trimmedNumber.length(); final String trimmedNumber = number.replace(groupingSeparator, "");
number = trimmedNumber; trimmedChars += number.length() - trimmedNumber.length();
} number = trimmedNumber;
}
// check if number still valid
toDouble(number, getNumeralBase(), engine); // check if number still valid
toDouble(number, getNumeralBase(), engine);
} catch (NumberFormatException e) {
// number is not valid => stop } catch (NumberFormatException e) {
number = null; // number is not valid => stop
} number = null;
}
numberBuilder = null;
numberBuilder = null;
// must set default numeral base (exit numeral base mode)
nb = engine.getNumeralBase(); // must set default numeral base (exit numeral base mode)
} nb = engine.getNumeralBase();
}
return replaceNumberInText(text, number, trimmedChars, offset, localNb, engine);
} return replaceNumberInText(text, number, trimmedChars, offset, localNb, engine);
}
@Nullable
private static MathType.Result replaceNumberInText(@NotNull StringBuilder text, @Nullable
@Nullable String number, private static MathType.Result replaceNumberInText(@NotNull StringBuilder text,
int trimmedChars, @Nullable String number,
@Nullable MutableObject<Integer> offset, int trimmedChars,
@NotNull NumeralBase nb, @Nullable MutableObject<Integer> offset,
@NotNull final MathEngine engine) { @NotNull NumeralBase nb,
MathType.Result result = null; @NotNull final MathEngine engine) {
MathType.Result result = null;
if (number != null) {
// in any case remove old number from text if (number != null) {
final int oldNumberLength = number.length() + trimmedChars; // in any case remove old number from text
text.delete(text.length() - oldNumberLength, text.length()); final int oldNumberLength = number.length() + trimmedChars;
text.delete(text.length() - oldNumberLength, text.length());
final String newNumber = formatNumber(number, nb, engine);
if (offset != null) { final String newNumber = formatNumber(number, nb, engine);
// register offset between old number and new number if (offset != null) {
offset.setObject(newNumber.length() - oldNumberLength); // register offset between old number and new number
} offset.setObject(newNumber.length() - oldNumberLength);
text.append(newNumber); }
} text.append(newNumber);
}
return result;
} return result;
}
@NotNull
private static String formatNumber(@NotNull String number, @NotNull NumeralBase nb, @NotNull MathEngine engine) { @NotNull
String result; private static String formatNumber(@NotNull String number, @NotNull NumeralBase nb, @NotNull MathEngine engine) {
String result;
int indexOfDot = number.indexOf('.');
int indexOfDot = number.indexOf('.');
if (indexOfDot < 0) {
int indexOfE; if (indexOfDot < 0) {
if (nb == NumeralBase.hex) { int indexOfE;
indexOfE = -1; if (nb == NumeralBase.hex) {
} else { indexOfE = -1;
indexOfE = number.indexOf(MathType.POWER_10); } else {
} indexOfE = number.indexOf(MathType.POWER_10);
if (indexOfE < 0) { }
result = engine.addGroupingSeparators(nb, number); if (indexOfE < 0) {
} else { result = engine.addGroupingSeparators(nb, number);
final String partBeforeE; } else {
if (indexOfE != 0) { final String partBeforeE;
partBeforeE = engine.addGroupingSeparators(nb, number.substring(0, indexOfE)); if (indexOfE != 0) {
} else { partBeforeE = engine.addGroupingSeparators(nb, number.substring(0, indexOfE));
partBeforeE = ""; } else {
} partBeforeE = "";
result = partBeforeE + number.substring(indexOfE); }
} result = partBeforeE + number.substring(indexOfE);
} else { }
final String integerPart; } else {
if (indexOfDot != 0) { final String integerPart;
integerPart = engine.addGroupingSeparators(nb, number.substring(0, indexOfDot)); if (indexOfDot != 0) {
} else { integerPart = engine.addGroupingSeparators(nb, number.substring(0, indexOfDot));
integerPart = ""; } else {
} integerPart = "";
result = integerPart + number.substring(indexOfDot); }
} result = integerPart + number.substring(indexOfDot);
}
return result;
} return result;
}
@NotNull
private static Double toDouble(@NotNull String s, @NotNull NumeralBase nb, @NotNull final MathContext mc) throws NumberFormatException { @NotNull
final NumeralBase defaultNb = mc.getNumeralBase(); private static Double toDouble(@NotNull String s, @NotNull NumeralBase nb, @NotNull final MathContext mc) throws NumberFormatException {
try { final NumeralBase defaultNb = mc.getNumeralBase();
mc.setNumeralBase(nb); try {
mc.setNumeralBase(nb);
try {
return JsclIntegerParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content().doubleValue(); try {
} catch (ParseException e) { return JsclIntegerParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content().doubleValue();
try { } catch (ParseException e) {
return ((Real) DoubleParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content()).doubleValue(); try {
} catch (ParseException e1) { return ((Real) DoubleParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content()).doubleValue();
throw new NumberFormatException(); } catch (ParseException e1) {
} throw new NumberFormatException();
} }
}
} finally {
mc.setNumeralBase(defaultNb); } finally {
} mc.setNumeralBase(defaultNb);
} }
} }
}

View File

@ -1,65 +1,65 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator;
import jscl.math.function.IConstant; import jscl.math.function.IConstant;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
/** /**
* User: serso * User: serso
* Date: 10/18/11 * Date: 10/18/11
* Time: 10:07 PM * Time: 10:07 PM
*/ */
public class PreparedExpression implements CharSequence{ public class PreparedExpression implements CharSequence{
@NotNull @NotNull
private String expression; private String expression;
@NotNull @NotNull
private List<IConstant> undefinedVars; private List<IConstant> undefinedVars;
public PreparedExpression(@NotNull String expression, @NotNull List<IConstant> undefinedVars) { public PreparedExpression(@NotNull String expression, @NotNull List<IConstant> undefinedVars) {
this.expression = expression; this.expression = expression;
this.undefinedVars = undefinedVars; this.undefinedVars = undefinedVars;
} }
@NotNull @NotNull
public String getExpression() { public String getExpression() {
return expression; return expression;
} }
public boolean isExistsUndefinedVar() { public boolean isExistsUndefinedVar() {
return !this.undefinedVars.isEmpty(); return !this.undefinedVars.isEmpty();
} }
@NotNull @NotNull
public List<IConstant> getUndefinedVars() { public List<IConstant> getUndefinedVars() {
return undefinedVars; return undefinedVars;
} }
@Override @Override
public int length() { public int length() {
return expression.length(); return expression.length();
} }
@Override @Override
public char charAt(int i) { public char charAt(int i) {
return expression.charAt(i); return expression.charAt(i);
} }
@Override @Override
public CharSequence subSequence(int i, int i1) { public CharSequence subSequence(int i, int i1) {
return expression.subSequence(i, i1); return expression.subSequence(i, i1);
} }
@Override @Override
public String toString() { public String toString() {
return this.expression; return this.expression;
} }
} }

View File

@ -4,12 +4,13 @@
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator;
import jscl.math.function.IConstant; import jscl.math.function.IConstant;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.CalculatorApplication; import org.solovyev.android.calculator.CalculatorApplication;
import org.solovyev.android.calculator.CalculatorParseException; import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.PreparedExpression;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.msg.AndroidMessage; import org.solovyev.android.msg.AndroidMessage;

View File

@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
import org.simpleframework.xml.Transient; import org.simpleframework.xml.Transient;
import org.solovyev.android.calculator.ICalculatorDisplay; import org.solovyev.android.calculator.JCalculatorDisplay;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
/** /**
@ -47,7 +47,7 @@ public class CalculatorDisplayHistoryState implements Cloneable {
} }
@NotNull @NotNull
public static CalculatorDisplayHistoryState newInstance(@NotNull ICalculatorDisplay display) { public static CalculatorDisplayHistoryState newInstance(@NotNull JCalculatorDisplay display) {
final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState(); final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState();
result.editorState = EditorHistoryState.newInstance(display); result.editorState = EditorHistoryState.newInstance(display);
@ -59,7 +59,7 @@ public class CalculatorDisplayHistoryState implements Cloneable {
return result; return result;
} }
public void setValuesFromHistory(@NotNull ICalculatorDisplay display) { public void setValuesFromHistory(@NotNull JCalculatorDisplay display) {
this.getEditorState().setValuesFromHistory(display); this.getEditorState().setValuesFromHistory(display);
display.setValid(this.isValid()); display.setValid(this.isValid());
display.setErrorMessage(this.getErrorMessage()); display.setErrorMessage(this.getErrorMessage());

View File

@ -0,0 +1,20 @@
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull;
import org.solovyev.common.history.HistoryHelper;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:11
*/
public interface CalculatorHistory extends HistoryHelper<CalculatorHistoryState> {
void fromXml(@NotNull String xml);
String toXml();
void clearSavedHistory();
void removeSavedHistory(@NotNull CalculatorHistoryState historyState);
}

View File

@ -0,0 +1,131 @@
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.history.HistoryAction;
import org.solovyev.common.history.HistoryHelper;
import org.solovyev.common.history.SimpleHistoryHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:12
*/
public class CalculatorHistoryImpl implements CalculatorHistory {
private final AtomicInteger counter = new AtomicInteger(0);
@NotNull
private final HistoryHelper<CalculatorHistoryState> history = new SimpleHistoryHelper<CalculatorHistoryState>();
@NotNull
private final List<CalculatorHistoryState> savedHistory = new ArrayList<CalculatorHistoryState>();
@Override
public boolean isEmpty() {
return this.history.isEmpty();
}
@Override
public CalculatorHistoryState getLastHistoryState() {
return this.history.getLastHistoryState();
}
@Override
public boolean isUndoAvailable() {
return history.isUndoAvailable();
}
@Override
public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) {
return history.undo(currentState);
}
@Override
public boolean isRedoAvailable() {
return history.isRedoAvailable();
}
@Override
public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) {
return history.redo(currentState);
}
@Override
public boolean isActionAvailable(@NotNull HistoryAction historyAction) {
return history.isActionAvailable(historyAction);
}
@Override
public CalculatorHistoryState doAction(@NotNull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) {
return history.doAction(historyAction, currentState);
}
@Override
public void addState(@Nullable CalculatorHistoryState currentState) {
history.addState(currentState);
}
@NotNull
@Override
public List<CalculatorHistoryState> getStates() {
return history.getStates();
}
@Override
public void clear() {
this.history.clear();
}
@NotNull
public List<CalculatorHistoryState> getSavedHistory() {
return Collections.unmodifiableList(savedHistory);
}
@NotNull
public CalculatorHistoryState addSavedState(@NotNull CalculatorHistoryState historyState) {
if (historyState.isSaved()) {
return historyState;
} else {
final CalculatorHistoryState savedState = historyState.clone();
savedState.setId(counter.incrementAndGet());
savedState.setSaved(true);
savedHistory.add(savedState);
return savedState;
}
}
@Override
public void fromXml(@NotNull String xml) {
clearSavedHistory();
HistoryUtils.fromXml(xml, this.savedHistory);
for (CalculatorHistoryState historyState : savedHistory) {
historyState.setSaved(true);
historyState.setId(counter.incrementAndGet());
}
}
@Override
public String toXml() {
return HistoryUtils.toXml(this.savedHistory);
}
@Override
public void clearSavedHistory() {
this.savedHistory.clear();
}
@Override
public void removeSavedHistory(@NotNull CalculatorHistoryState historyState) {
this.savedHistory.remove(historyState);
}
}

View File

@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
import org.solovyev.android.calculator.Editor; import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.ICalculatorDisplay; import org.solovyev.android.calculator.JCalculatorDisplay;
/** /**
* User: serso * User: serso
@ -38,7 +38,7 @@ public class CalculatorHistoryState extends AbstractHistoryState {
this.displayState = displayState; this.displayState = displayState;
} }
public static CalculatorHistoryState newInstance(@NotNull Editor editor, @NotNull ICalculatorDisplay display) { public static CalculatorHistoryState newInstance(@NotNull Editor editor, @NotNull JCalculatorDisplay display) {
final EditorHistoryState editorHistoryState = EditorHistoryState.newInstance(editor); final EditorHistoryState editorHistoryState = EditorHistoryState.newInstance(editor);
final CalculatorDisplayHistoryState displayHistoryState = CalculatorDisplayHistoryState.newInstance(display); final CalculatorDisplayHistoryState displayHistoryState = CalculatorDisplayHistoryState.newInstance(display);
return new CalculatorHistoryState(editorHistoryState, displayHistoryState); return new CalculatorHistoryState(editorHistoryState, displayHistoryState);
@ -94,7 +94,7 @@ public class CalculatorHistoryState extends AbstractHistoryState {
return result; return result;
} }
public void setValuesFromHistory(@NotNull Editor editor, @NotNull ICalculatorDisplay display) { public void setValuesFromHistory(@NotNull Editor editor, @NotNull JCalculatorDisplay display) {
this.getEditorState().setValuesFromHistory(editor); this.getEditorState().setValuesFromHistory(editor);
this.getDisplayState().setValuesFromHistory(display); this.getDisplayState().setValuesFromHistory(display);
} }

View File

@ -0,0 +1,77 @@
package org.solovyev.common.utils;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:43
*/
// todo serso: move to common
public class ListListenersContainer<T> {
@NotNull
private final List<WeakReference<T>> listeners = new ArrayList<WeakReference<T>>();
public void addListener(@NotNull final T listener) {
synchronized (listeners) {
boolean contains = Iterables.any(listeners, new WeakReferencePredicate<T>(listener));
if (!contains) {
listeners.add(new WeakReference<T>(listener));
}
}
}
public void removeListener(@NotNull T listener) {
synchronized (listeners) {
Iterables.removeIf(listeners, new WeakReferencePredicate<T>(listener));
}
}
@NotNull
public List<T> getListeners() {
final List<T> localListeners;
synchronized (listeners) {
localListeners = new ArrayList<T>(listeners.size());
// copy listeners and remove garbage collected references
for ( Iterator<WeakReference<T>> it = listeners.iterator(); it.hasNext(); ) {
final WeakReference<T> r = it.next();
final T t = r.get();
if ( t == null ) {
it.remove();
} else {
localListeners.add(t);
}
}
}
return localListeners;
}
private static class WeakReferencePredicate<T> implements Predicate<WeakReference<T>> {
@NotNull
private final T t;
public WeakReferencePredicate(T t) {
this.t = t;
}
@Override
public boolean apply(@Nullable WeakReference<T> r) {
final T t = r != null ? r.get() : null;
return this.t.equals(t);
}
}
}

View File

@ -32,7 +32,7 @@ import org.solovyev.android.AndroidUtils;
import org.solovyev.android.FontSizeAdjuster; import org.solovyev.android.FontSizeAdjuster;
import org.solovyev.android.LocalBinder; import org.solovyev.android.LocalBinder;
import org.solovyev.android.calculator.about.CalculatorReleaseNotesActivity; import org.solovyev.android.calculator.about.CalculatorReleaseNotesActivity;
import org.solovyev.android.calculator.history.CalculatorHistory; import org.solovyev.android.calculator.history.AndroidCalculatorHistoryImpl;
import org.solovyev.android.calculator.history.CalculatorHistoryState; import org.solovyev.android.calculator.history.CalculatorHistoryState;
import org.solovyev.android.calculator.model.CalculatorEngine; import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.view.AngleUnitsButton; import org.solovyev.android.calculator.view.AngleUnitsButton;
@ -136,7 +136,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
vibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE); vibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
CalculatorHistory.instance.load(this, preferences); AndroidCalculatorHistoryImpl.instance.load(this, preferences);
calculatorModel = CalculatorModel.instance.init(this, preferences, CalculatorEngine.instance); calculatorModel = CalculatorModel.instance.init(this, preferences, CalculatorEngine.instance);
dpclRegister.clear(); dpclRegister.clear();

View File

@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.model.CalculatorEngine; import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.calculator.model.ToJsclTextProcessor; import org.solovyev.android.calculator.ToJsclTextProcessor;
import org.solovyev.android.calculator.view.NumeralBaseConverterDialog; import org.solovyev.android.calculator.view.NumeralBaseConverterDialog;
import org.solovyev.android.calculator.view.TextHighlighter; import org.solovyev.android.calculator.view.TextHighlighter;
import org.solovyev.android.calculator.view.UnitConverterViewBuilder; import org.solovyev.android.calculator.view.UnitConverterViewBuilder;
@ -37,7 +37,7 @@ import java.util.Set;
* Date: 9/17/11 * Date: 9/17/11
* Time: 10:58 PM * Time: 10:58 PM
*/ */
public class CalculatorDisplay extends AutoResizeTextView implements ICalculatorDisplay{ public class CalculatorDisplay extends AutoResizeTextView implements JCalculatorDisplay {
private static enum ConversionMenuItem implements AMenuItem<CalculatorDisplay> { private static enum ConversionMenuItem implements AMenuItem<CalculatorDisplay> {
convert_to_bin(NumeralBase.bin), convert_to_bin(NumeralBase.bin),

View File

@ -20,13 +20,12 @@ import android.widget.Toast;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.CursorControl; import org.solovyev.android.CursorControl;
import org.solovyev.android.calculator.history.CalculatorHistory; import org.solovyev.android.calculator.history.AndroidCalculatorHistoryImpl;
import org.solovyev.android.calculator.history.CalculatorHistoryState; import org.solovyev.android.calculator.history.CalculatorHistoryState;
import org.solovyev.android.calculator.history.TextViewEditorAdapter; import org.solovyev.android.calculator.history.TextViewEditorAdapter;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.CalculatorEngine; import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.model.CalculatorEvalException;
import org.solovyev.android.history.HistoryControl; import org.solovyev.android.history.HistoryControl;
import org.solovyev.android.menu.AMenuBuilder; import org.solovyev.android.menu.AMenuBuilder;
import org.solovyev.android.menu.MenuImpl; import org.solovyev.android.menu.MenuImpl;
@ -70,7 +69,7 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
this.display = (CalculatorDisplay) activity.findViewById(R.id.calculatorDisplay); this.display = (CalculatorDisplay) activity.findViewById(R.id.calculatorDisplay);
this.display.setOnClickListener(new CalculatorDisplayOnClickListener(activity)); this.display.setOnClickListener(new CalculatorDisplayOnClickListener(activity));
final CalculatorHistoryState lastState = CalculatorHistory.instance.getLastHistoryState(); final CalculatorHistoryState lastState = AndroidCalculatorHistoryImpl.instance.getLastHistoryState();
if (lastState == null) { if (lastState == null) {
saveHistoryState(); saveHistoryState();
} else { } else {
@ -110,7 +109,7 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
} }
private void saveHistoryState() { private void saveHistoryState() {
CalculatorHistory.instance.addState(getCurrentHistoryState()); AndroidCalculatorHistoryImpl.instance.addState(getCurrentHistoryState());
} }
public void setCursorOnStart() { public void setCursorOnStart() {
@ -196,14 +195,14 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
if (delayEvaluate) { if (delayEvaluate) {
if (historyState == null) { if (historyState == null) {
CalculatorHistory.instance.addState(localHistoryState); AndroidCalculatorHistoryImpl.instance.addState(localHistoryState);
} }
// todo serso: this is not correct - operation is processing still in the same thread // todo serso: this is not correct - operation is processing still in the same thread
new Handler().postDelayed(pendingOperation.getObject(), EVAL_DELAY_MILLIS); new Handler().postDelayed(pendingOperation.getObject(), EVAL_DELAY_MILLIS);
} else { } else {
pendingOperation.getObject().run(); pendingOperation.getObject().run();
if (historyState == null) { if (historyState == null) {
CalculatorHistory.instance.addState(localHistoryState); AndroidCalculatorHistoryImpl.instance.addState(localHistoryState);
} }
} }
} }
@ -330,9 +329,9 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
@Override @Override
public void doHistoryAction(@NotNull HistoryAction historyAction) { public void doHistoryAction(@NotNull HistoryAction historyAction) {
synchronized (CalculatorHistory.instance) { synchronized (AndroidCalculatorHistoryImpl.instance) {
if (CalculatorHistory.instance.isActionAvailable(historyAction)) { if (AndroidCalculatorHistoryImpl.instance.isActionAvailable(historyAction)) {
final CalculatorHistoryState newState = CalculatorHistory.instance.doAction(historyAction, getCurrentHistoryState()); final CalculatorHistoryState newState = AndroidCalculatorHistoryImpl.instance.doAction(historyAction, getCurrentHistoryState());
if (newState != null) { if (newState != null) {
setCurrentHistoryState(newState); setCurrentHistoryState(newState);
} }
@ -342,7 +341,7 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
@Override @Override
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) { public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
synchronized (CalculatorHistory.instance) { synchronized (AndroidCalculatorHistoryImpl.instance) {
Log.d(this.getClass().getName(), "Saved history found: " + editorHistoryState); Log.d(this.getClass().getName(), "Saved history found: " + editorHistoryState);
editorHistoryState.setValuesFromHistory(new TextViewEditorAdapter(this.editor), this.display); editorHistoryState.setValuesFromHistory(new TextViewEditorAdapter(this.editor), this.display);
@ -362,7 +361,7 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
@Override @Override
@NotNull @NotNull
public CalculatorHistoryState getCurrentHistoryState() { public CalculatorHistoryState getCurrentHistoryState() {
synchronized (CalculatorHistory.instance) { synchronized (AndroidCalculatorHistoryImpl.instance) {
return CalculatorHistoryState.newInstance(new TextViewEditorAdapter(this.editor), this.display); return CalculatorHistoryState.newInstance(new TextViewEditorAdapter(this.editor), this.display);
} }
} }

View File

@ -1,263 +1,263 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import android.app.ListActivity; import android.app.ListActivity;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ListView; import android.widget.ListView;
import com.google.ads.AdView; import com.google.ads.AdView;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.ads.AdsController; import org.solovyev.android.ads.AdsController;
import org.solovyev.android.calculator.CalculatorModel; import org.solovyev.android.calculator.CalculatorModel;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.menu.AMenuBuilder; import org.solovyev.android.menu.AMenuBuilder;
import org.solovyev.android.menu.MenuImpl; import org.solovyev.android.menu.MenuImpl;
import org.solovyev.common.collections.CollectionsUtils; import org.solovyev.common.collections.CollectionsUtils;
import org.solovyev.common.equals.Equalizer; import org.solovyev.common.equals.Equalizer;
import org.solovyev.common.filter.Filter; import org.solovyev.common.filter.Filter;
import org.solovyev.common.filter.FilterRule; import org.solovyev.common.filter.FilterRule;
import org.solovyev.common.filter.FilterRulesChain; import org.solovyev.common.filter.FilterRulesChain;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.text.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
/** /**
* User: serso * User: serso
* Date: 10/15/11 * Date: 10/15/11
* Time: 1:13 PM * Time: 1:13 PM
*/ */
public abstract class AbstractHistoryActivity extends ListActivity { public abstract class AbstractHistoryActivity extends ListActivity {
public static final Comparator<CalculatorHistoryState> COMPARATOR = new Comparator<CalculatorHistoryState>() { public static final Comparator<CalculatorHistoryState> COMPARATOR = new Comparator<CalculatorHistoryState>() {
@Override @Override
public int compare(CalculatorHistoryState state1, CalculatorHistoryState state2) { public int compare(CalculatorHistoryState state1, CalculatorHistoryState state2) {
if (state1.isSaved() == state2.isSaved()) { if (state1.isSaved() == state2.isSaved()) {
long l = state2.getTime() - state1.getTime(); long l = state2.getTime() - state1.getTime();
return l > 0l ? 1 : (l < 0l ? -1 : 0); return l > 0l ? 1 : (l < 0l ? -1 : 0);
} else if (state1.isSaved()) { } else if (state1.isSaved()) {
return -1; return -1;
} else if (state2.isSaved()) { } else if (state2.isSaved()) {
return 1; return 1;
} }
return 0; return 0;
} }
}; };
@NotNull @NotNull
private ArrayAdapter<CalculatorHistoryState> adapter; private ArrayAdapter<CalculatorHistoryState> adapter;
@Nullable @Nullable
private AdView adView; private AdView adView;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.history_activity); setContentView(R.layout.history_activity);
adView = AdsController.getInstance().inflateAd(this); adView = AdsController.getInstance().inflateAd(this);
adapter = new HistoryArrayAdapter(this, getLayoutId(), R.id.history_item, new ArrayList<CalculatorHistoryState>()); adapter = new HistoryArrayAdapter(this, getLayoutId(), R.id.history_item, new ArrayList<CalculatorHistoryState>());
setListAdapter(adapter); setListAdapter(adapter);
final ListView lv = getListView(); final ListView lv = getListView();
lv.setTextFilterEnabled(true); lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(final AdapterView<?> parent, public void onItemClick(final AdapterView<?> parent,
final View view, final View view,
final int position, final int position,
final long id) { final long id) {
useHistoryItem((CalculatorHistoryState) parent.getItemAtPosition(position), AbstractHistoryActivity.this); useHistoryItem((CalculatorHistoryState) parent.getItemAtPosition(position), AbstractHistoryActivity.this);
} }
}); });
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override @Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) { public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position); final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position);
final Context context = AbstractHistoryActivity.this; final Context context = AbstractHistoryActivity.this;
final HistoryItemMenuData data = new HistoryItemMenuData(historyState, adapter); final HistoryItemMenuData data = new HistoryItemMenuData(historyState, adapter);
final List<HistoryItemMenuItem> menuItems = CollectionsUtils.asList(HistoryItemMenuItem.values()); final List<HistoryItemMenuItem> menuItems = CollectionsUtils.asList(HistoryItemMenuItem.values());
if (historyState.isSaved()) { if (historyState.isSaved()) {
menuItems.remove(HistoryItemMenuItem.save); menuItems.remove(HistoryItemMenuItem.save);
} else { } else {
if (isAlreadySaved(historyState)) { if (isAlreadySaved(historyState)) {
menuItems.remove(HistoryItemMenuItem.save); menuItems.remove(HistoryItemMenuItem.save);
} }
menuItems.remove(HistoryItemMenuItem.remove); menuItems.remove(HistoryItemMenuItem.remove);
menuItems.remove(HistoryItemMenuItem.edit); menuItems.remove(HistoryItemMenuItem.edit);
} }
if (historyState.getDisplayState().isValid() && StringUtils.isEmpty(historyState.getDisplayState().getEditorState().getText())) { if (historyState.getDisplayState().isValid() && StringUtils.isEmpty(historyState.getDisplayState().getEditorState().getText())) {
menuItems.remove(HistoryItemMenuItem.copy_result); menuItems.remove(HistoryItemMenuItem.copy_result);
} }
final AMenuBuilder<HistoryItemMenuItem, HistoryItemMenuData> menuBuilder = AMenuBuilder.newInstance(context, MenuImpl.newInstance(menuItems)); final AMenuBuilder<HistoryItemMenuItem, HistoryItemMenuData> menuBuilder = AMenuBuilder.newInstance(context, MenuImpl.newInstance(menuItems));
menuBuilder.create(data).show(); menuBuilder.create(data).show();
return true; return true;
} }
}); });
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
if ( this.adView != null ) { if ( this.adView != null ) {
this.adView.destroy(); this.adView.destroy();
} }
super.onDestroy(); super.onDestroy();
} }
protected abstract int getLayoutId(); protected abstract int getLayoutId();
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
final List<CalculatorHistoryState> historyList = getHistoryList(); final List<CalculatorHistoryState> historyList = getHistoryList();
try { try {
this.adapter.setNotifyOnChange(false); this.adapter.setNotifyOnChange(false);
this.adapter.clear(); this.adapter.clear();
for (CalculatorHistoryState historyState : historyList) { for (CalculatorHistoryState historyState : historyList) {
this.adapter.add(historyState); this.adapter.add(historyState);
} }
} finally { } finally {
this.adapter.setNotifyOnChange(true); this.adapter.setNotifyOnChange(true);
} }
this.adapter.notifyDataSetChanged(); this.adapter.notifyDataSetChanged();
} }
public static boolean isAlreadySaved(@NotNull CalculatorHistoryState historyState) { public static boolean isAlreadySaved(@NotNull CalculatorHistoryState historyState) {
assert !historyState.isSaved(); assert !historyState.isSaved();
boolean result = false; boolean result = false;
try { try {
historyState.setSaved(true); historyState.setSaved(true);
if ( CollectionsUtils.contains(historyState, CalculatorHistory.instance.getSavedHistory(), new Equalizer<CalculatorHistoryState>() { if ( CollectionsUtils.contains(historyState, AndroidCalculatorHistoryImpl.instance.getSavedHistory(), new Equalizer<CalculatorHistoryState>() {
@Override @Override
public boolean equals(@Nullable CalculatorHistoryState first, @Nullable CalculatorHistoryState second) { public boolean equals(@Nullable CalculatorHistoryState first, @Nullable CalculatorHistoryState second) {
return first != null && second != null && return first != null && second != null &&
first.getTime() == second.getTime() && first.getTime() == second.getTime() &&
first.getDisplayState().equals(second.getDisplayState()) && first.getDisplayState().equals(second.getDisplayState()) &&
first.getEditorState().equals(second.getEditorState()); first.getEditorState().equals(second.getEditorState());
} }
}) ) { }) ) {
result = true; result = true;
} }
} finally { } finally {
historyState.setSaved(false); historyState.setSaved(false);
} }
return result; return result;
} }
public static void useHistoryItem(@NotNull final CalculatorHistoryState historyState, @NotNull AbstractHistoryActivity activity) { public static void useHistoryItem(@NotNull final CalculatorHistoryState historyState, @NotNull AbstractHistoryActivity activity) {
// before evaluating history item - clear display (in order to get Error message in display if evaluation fail) // before evaluating history item - clear display (in order to get Error message in display if evaluation fail)
CalculatorModel.instance.getDisplay().setText(""); CalculatorModel.instance.getDisplay().setText("");
CalculatorModel.instance.doTextOperation(new CalculatorModel.TextOperation() { CalculatorModel.instance.doTextOperation(new CalculatorModel.TextOperation() {
@Override @Override
public void doOperation(@NotNull EditText editor) { public void doOperation(@NotNull EditText editor) {
final EditorHistoryState editorState = historyState.getEditorState(); final EditorHistoryState editorState = historyState.getEditorState();
editor.setText(editorState.getText()); editor.setText(editorState.getText());
editor.setSelection(editorState.getCursorPosition()); editor.setSelection(editorState.getCursorPosition());
} }
}, false, historyState.getDisplayState().getJsclOperation(), true); }, false, historyState.getDisplayState().getJsclOperation(), true);
CalculatorModel.instance.setCursorOnEnd(); CalculatorModel.instance.setCursorOnEnd();
activity.finish(); activity.finish();
} }
@NotNull @NotNull
private List<CalculatorHistoryState> getHistoryList() { private List<CalculatorHistoryState> getHistoryList() {
final List<CalculatorHistoryState> calculatorHistoryStates = getHistoryItems(); final List<CalculatorHistoryState> calculatorHistoryStates = getHistoryItems();
Collections.sort(calculatorHistoryStates, COMPARATOR); Collections.sort(calculatorHistoryStates, COMPARATOR);
final FilterRulesChain<CalculatorHistoryState> filterRulesChain = new FilterRulesChain<CalculatorHistoryState>(); final FilterRulesChain<CalculatorHistoryState> filterRulesChain = new FilterRulesChain<CalculatorHistoryState>();
filterRulesChain.addFilterRule(new FilterRule<CalculatorHistoryState>() { filterRulesChain.addFilterRule(new FilterRule<CalculatorHistoryState>() {
@Override @Override
public boolean isFiltered(CalculatorHistoryState object) { public boolean isFiltered(CalculatorHistoryState object) {
return object == null || StringUtils.isEmpty(object.getEditorState().getText()); return object == null || StringUtils.isEmpty(object.getEditorState().getText());
} }
}); });
new Filter<CalculatorHistoryState>(filterRulesChain).filter(calculatorHistoryStates.iterator()); new Filter<CalculatorHistoryState>(filterRulesChain).filter(calculatorHistoryStates.iterator());
return calculatorHistoryStates; return calculatorHistoryStates;
} }
@NotNull @NotNull
protected abstract List<CalculatorHistoryState> getHistoryItems(); protected abstract List<CalculatorHistoryState> getHistoryItems();
@NotNull @NotNull
public static String getHistoryText(@NotNull CalculatorHistoryState state) { public static String getHistoryText(@NotNull CalculatorHistoryState state) {
final StringBuilder result = new StringBuilder(); final StringBuilder result = new StringBuilder();
result.append(state.getEditorState().getText()); result.append(state.getEditorState().getText());
result.append(getIdentitySign(state.getDisplayState().getJsclOperation())); result.append(getIdentitySign(state.getDisplayState().getJsclOperation()));
final String expressionResult = state.getDisplayState().getEditorState().getText(); final String expressionResult = state.getDisplayState().getEditorState().getText();
if (expressionResult != null) { if (expressionResult != null) {
result.append(expressionResult); result.append(expressionResult);
} }
return result.toString(); return result.toString();
} }
@NotNull @NotNull
private static String getIdentitySign(@NotNull JsclOperation jsclOperation) { private static String getIdentitySign(@NotNull JsclOperation jsclOperation) {
return jsclOperation == JsclOperation.simplify ? "" : "="; return jsclOperation == JsclOperation.simplify ? "" : "=";
} }
@Override @Override
public boolean onCreateOptionsMenu(android.view.Menu menu) { public boolean onCreateOptionsMenu(android.view.Menu menu) {
final MenuInflater menuInflater = getMenuInflater(); final MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.history_menu, menu); menuInflater.inflate(R.menu.history_menu, menu);
return true; return true;
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
boolean result; boolean result;
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.history_menu_clear_history: case R.id.history_menu_clear_history:
clearHistory(); clearHistory();
result = true; result = true;
break; break;
default: default:
result = super.onOptionsItemSelected(item); result = super.onOptionsItemSelected(item);
} }
return result; return result;
} }
protected abstract void clearHistory(); protected abstract void clearHistory();
@NotNull @NotNull
protected ArrayAdapter<CalculatorHistoryState> getAdapter() { protected ArrayAdapter<CalculatorHistoryState> getAdapter() {
return adapter; return adapter;
} }
} }

View File

@ -0,0 +1,18 @@
package org.solovyev.android.calculator.history;
import android.content.Context;
import android.content.SharedPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 16:07
*/
public interface AndroidCalculatorHistory extends CalculatorHistory {
void load(@Nullable Context context, @Nullable SharedPreferences preferences);
void save(@NotNull Context context);
}

View File

@ -0,0 +1,145 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
import org.solovyev.common.history.HistoryAction;
import java.util.List;
/**
* User: serso
* Date: 10/9/11
* Time: 6:35 PM
*/
public enum AndroidCalculatorHistoryImpl implements AndroidCalculatorHistory {
instance;
@NotNull
private final CalculatorHistoryImpl calculatorHistory = new CalculatorHistoryImpl();
@Override
public void load(@Nullable Context context, @Nullable SharedPreferences preferences) {
if (context != null && preferences != null) {
final String value = preferences.getString(context.getString(R.string.p_calc_history), null);
calculatorHistory.fromXml(value);
}
}
@Override
public void save(@NotNull Context context) {
final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
final SharedPreferences.Editor editor = settings.edit();
editor.putString(context.getString(R.string.p_calc_history), calculatorHistory.toXml());
editor.commit();
}
public void clearSavedHistory(@NotNull Context context) {
calculatorHistory.clearSavedHistory();
save(context);
}
public void removeSavedHistory(@NotNull CalculatorHistoryState historyState, @NotNull Context context) {
historyState.setSaved(false);
calculatorHistory.removeSavedHistory(historyState);
save(context);
}
@Override
public boolean isEmpty() {
return calculatorHistory.isEmpty();
}
@Override
public CalculatorHistoryState getLastHistoryState() {
return calculatorHistory.getLastHistoryState();
}
@Override
public boolean isUndoAvailable() {
return calculatorHistory.isUndoAvailable();
}
@Override
public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) {
return calculatorHistory.undo(currentState);
}
@Override
public boolean isRedoAvailable() {
return calculatorHistory.isRedoAvailable();
}
@Override
public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) {
return calculatorHistory.redo(currentState);
}
@Override
public boolean isActionAvailable(@NotNull HistoryAction historyAction) {
return calculatorHistory.isActionAvailable(historyAction);
}
@Override
public CalculatorHistoryState doAction(@NotNull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) {
return calculatorHistory.doAction(historyAction, currentState);
}
@Override
public void addState(@Nullable CalculatorHistoryState currentState) {
calculatorHistory.addState(currentState);
}
@NotNull
@Override
public List<CalculatorHistoryState> getStates() {
return calculatorHistory.getStates();
}
@Override
public void clear() {
calculatorHistory.clear();
}
@NotNull
public List<CalculatorHistoryState> getSavedHistory() {
return calculatorHistory.getSavedHistory();
}
@NotNull
public CalculatorHistoryState addSavedState(@NotNull CalculatorHistoryState historyState) {
return calculatorHistory.addSavedState(historyState);
}
@Override
public void fromXml(@NotNull String xml) {
calculatorHistory.fromXml(xml);
}
@Override
public String toXml() {
return calculatorHistory.toXml();
}
@Override
public void clearSavedHistory() {
calculatorHistory.clearSavedHistory();
}
@Override
public void removeSavedHistory(@NotNull CalculatorHistoryState historyState) {
calculatorHistory.removeSavedHistory(historyState);
}
}

View File

@ -1,149 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
import org.solovyev.common.history.HistoryAction;
import org.solovyev.common.history.HistoryHelper;
import org.solovyev.common.history.SimpleHistoryHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* User: serso
* Date: 10/9/11
* Time: 6:35 PM
*/
public enum CalculatorHistory implements HistoryHelper<CalculatorHistoryState> {
instance;
// todo serso: not synchronized
private int counter = 0;
@NotNull
private final HistoryHelper<CalculatorHistoryState> history = new SimpleHistoryHelper<CalculatorHistoryState>();
@NotNull
private final List<CalculatorHistoryState> savedHistory = new ArrayList<CalculatorHistoryState> ();
@Override
public boolean isEmpty() {
return this.history.isEmpty();
}
@Override
public CalculatorHistoryState getLastHistoryState() {
return this.history.getLastHistoryState();
}
@Override
public boolean isUndoAvailable() {
return history.isUndoAvailable();
}
@Override
public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) {
return history.undo(currentState);
}
@Override
public boolean isRedoAvailable() {
return history.isRedoAvailable();
}
@Override
public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) {
return history.redo(currentState);
}
@Override
public boolean isActionAvailable(@NotNull HistoryAction historyAction) {
return history.isActionAvailable(historyAction);
}
@Override
public CalculatorHistoryState doAction(@NotNull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) {
return history.doAction(historyAction, currentState);
}
@Override
public void addState(@Nullable CalculatorHistoryState currentState) {
history.addState(currentState);
}
@NotNull
@Override
public List<CalculatorHistoryState> getStates() {
return history.getStates();
}
@Override
public void clear() {
this.history.clear();
}
public void load(@Nullable Context context, @Nullable SharedPreferences preferences) {
if (context != null && preferences != null) {
final String value = preferences.getString(context.getString(R.string.p_calc_history), null);
this.savedHistory.clear();
HistoryUtils.fromXml(value, this.savedHistory);
for (CalculatorHistoryState historyState : savedHistory) {
historyState.setSaved(true);
historyState.setId(counter++);
}
}
}
public void save(@NotNull Context context) {
final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
final SharedPreferences.Editor editor = settings.edit();
editor.putString(context.getString(R.string.p_calc_history), HistoryUtils.toXml(this.savedHistory));
editor.commit();
}
@NotNull
public List<CalculatorHistoryState> getSavedHistory() {
return Collections.unmodifiableList(savedHistory);
}
@NotNull
public CalculatorHistoryState addSavedState(@NotNull CalculatorHistoryState historyState) {
if (historyState.isSaved()) {
return historyState;
} else {
final CalculatorHistoryState savedState = historyState.clone();
savedState.setId(counter++);
savedState.setSaved(true);
savedHistory.add(savedState);
return savedState;
}
}
public void clearSavedHistory(@NotNull Context context) {
this.savedHistory.clear();
save(context);
}
public void removeSavedHistory(@NotNull CalculatorHistoryState historyState, @NotNull Context context) {
historyState.setSaved(false);
this.savedHistory.remove(historyState);
save(context);
}
}

View File

@ -1,37 +1,37 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* User: serso * User: serso
* Date: 12/18/11 * Date: 12/18/11
* Time: 7:39 PM * Time: 7:39 PM
*/ */
public class HistoryActivityTab extends AbstractHistoryActivity { public class HistoryActivityTab extends AbstractHistoryActivity {
@Override @Override
protected int getLayoutId() { protected int getLayoutId() {
return R.layout.history; return R.layout.history;
} }
@NotNull @NotNull
@Override @Override
protected List<CalculatorHistoryState> getHistoryItems() { protected List<CalculatorHistoryState> getHistoryItems() {
return new ArrayList<CalculatorHistoryState>(CalculatorHistory.instance.getStates()); return new ArrayList<CalculatorHistoryState>(AndroidCalculatorHistoryImpl.instance.getStates());
} }
@Override @Override
protected void clearHistory() { protected void clearHistory() {
CalculatorHistory.instance.clear(); AndroidCalculatorHistoryImpl.instance.clear();
getAdapter().clear(); getAdapter().clear();
} }
} }

View File

@ -1,154 +1,154 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.text.ClipboardManager; import android.text.ClipboardManager;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.menu.LabeledMenuItem; import org.solovyev.android.menu.LabeledMenuItem;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.text.StringUtils;
/** /**
* User: serso * User: serso
* Date: 12/18/11 * Date: 12/18/11
* Time: 3:09 PM * Time: 3:09 PM
*/ */
public enum HistoryItemMenuItem implements LabeledMenuItem<HistoryItemMenuData> { public enum HistoryItemMenuItem implements LabeledMenuItem<HistoryItemMenuData> {
use(R.string.c_use) { use(R.string.c_use) {
@Override @Override
public void onClick(@NotNull HistoryItemMenuData data, @NotNull Context context) { public void onClick(@NotNull HistoryItemMenuData data, @NotNull Context context) {
if (context instanceof AbstractHistoryActivity) { if (context instanceof AbstractHistoryActivity) {
AbstractHistoryActivity.useHistoryItem(data.getHistoryState(), (AbstractHistoryActivity) context); AbstractHistoryActivity.useHistoryItem(data.getHistoryState(), (AbstractHistoryActivity) context);
} else { } else {
Log.e(HistoryItemMenuItem.class.getName(), AbstractHistoryActivity.class + " must be passed as context!"); Log.e(HistoryItemMenuItem.class.getName(), AbstractHistoryActivity.class + " must be passed as context!");
} }
} }
}, },
copy_expression(R.string.c_copy_expression) { copy_expression(R.string.c_copy_expression) {
@Override @Override
public void onClick(@NotNull HistoryItemMenuData data, @NotNull Context context) { public void onClick(@NotNull HistoryItemMenuData data, @NotNull Context context) {
final CalculatorHistoryState calculatorHistoryState = data.getHistoryState(); final CalculatorHistoryState calculatorHistoryState = data.getHistoryState();
final String text = calculatorHistoryState.getEditorState().getText(); final String text = calculatorHistoryState.getEditorState().getText();
if (!StringUtils.isEmpty(text)) { if (!StringUtils.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text); clipboard.setText(text);
Toast.makeText(context, context.getText(R.string.c_expression_copied), Toast.LENGTH_SHORT).show(); Toast.makeText(context, context.getText(R.string.c_expression_copied), Toast.LENGTH_SHORT).show();
} }
} }
}, },
copy_result(R.string.c_copy_result) { copy_result(R.string.c_copy_result) {
@Override @Override
public void onClick(@NotNull HistoryItemMenuData data, @NotNull Context context) { public void onClick(@NotNull HistoryItemMenuData data, @NotNull Context context) {
final CalculatorHistoryState calculatorHistoryState = data.getHistoryState(); final CalculatorHistoryState calculatorHistoryState = data.getHistoryState();
final String text = calculatorHistoryState.getDisplayState().getEditorState().getText(); final String text = calculatorHistoryState.getDisplayState().getEditorState().getText();
if (!StringUtils.isEmpty(text)) { if (!StringUtils.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text); clipboard.setText(text);
Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show(); Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show();
} }
} }
}, },
save(R.string.c_save) { save(R.string.c_save) {
@Override @Override
public void onClick(@NotNull final HistoryItemMenuData data, @NotNull final Context context) { public void onClick(@NotNull final HistoryItemMenuData data, @NotNull final Context context) {
final CalculatorHistoryState historyState = data.getHistoryState(); final CalculatorHistoryState historyState = data.getHistoryState();
if (!historyState.isSaved()) { if (!historyState.isSaved()) {
createEditHistoryDialog(data, context, true); createEditHistoryDialog(data, context, true);
} else { } else {
Toast.makeText(context, context.getText(R.string.c_history_already_saved), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getText(R.string.c_history_already_saved), Toast.LENGTH_LONG).show();
} }
} }
}, },
edit(R.string.c_edit) { edit(R.string.c_edit) {
@Override @Override
public void onClick(@NotNull final HistoryItemMenuData data, @NotNull final Context context) { public void onClick(@NotNull final HistoryItemMenuData data, @NotNull final Context context) {
final CalculatorHistoryState historyState = data.getHistoryState(); final CalculatorHistoryState historyState = data.getHistoryState();
if (historyState.isSaved()) { if (historyState.isSaved()) {
createEditHistoryDialog(data, context, false); createEditHistoryDialog(data, context, false);
} else { } else {
Toast.makeText(context, context.getText(R.string.c_history_must_be_saved), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getText(R.string.c_history_must_be_saved), Toast.LENGTH_LONG).show();
} }
} }
}, },
remove(R.string.c_remove) { remove(R.string.c_remove) {
@Override @Override
public void onClick(@NotNull HistoryItemMenuData data, @NotNull Context context) { public void onClick(@NotNull HistoryItemMenuData data, @NotNull Context context) {
final CalculatorHistoryState historyState = data.getHistoryState(); final CalculatorHistoryState historyState = data.getHistoryState();
if (historyState.isSaved()) { if (historyState.isSaved()) {
data.getAdapter().remove(historyState); data.getAdapter().remove(historyState);
CalculatorHistory.instance.removeSavedHistory(historyState, context); AndroidCalculatorHistoryImpl.instance.removeSavedHistory(historyState, context);
Toast.makeText(context, context.getText(R.string.c_history_was_removed), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getText(R.string.c_history_was_removed), Toast.LENGTH_LONG).show();
data.getAdapter().notifyDataSetChanged(); data.getAdapter().notifyDataSetChanged();
} }
} }
}; };
private static void createEditHistoryDialog(@NotNull final HistoryItemMenuData data, @NotNull final Context context, final boolean save) { private static void createEditHistoryDialog(@NotNull final HistoryItemMenuData data, @NotNull final Context context, final boolean save) {
final CalculatorHistoryState historyState = data.getHistoryState(); final CalculatorHistoryState historyState = data.getHistoryState();
final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View editView = layoutInflater.inflate(R.layout.history_edit, null); final View editView = layoutInflater.inflate(R.layout.history_edit, null);
final TextView historyExpression = (TextView)editView.findViewById(R.id.history_edit_expression); final TextView historyExpression = (TextView)editView.findViewById(R.id.history_edit_expression);
historyExpression.setText(AbstractHistoryActivity.getHistoryText(historyState)); historyExpression.setText(AbstractHistoryActivity.getHistoryText(historyState));
final EditText comment = (EditText)editView.findViewById(R.id.history_edit_comment); final EditText comment = (EditText)editView.findViewById(R.id.history_edit_comment);
comment.setText(historyState.getComment()); comment.setText(historyState.getComment());
final AlertDialog.Builder builder = new AlertDialog.Builder(context) final AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setTitle(save ? R.string.c_save_history : R.string.c_edit_history) .setTitle(save ? R.string.c_save_history : R.string.c_edit_history)
.setCancelable(true) .setCancelable(true)
.setNegativeButton(R.string.c_cancel, null) .setNegativeButton(R.string.c_cancel, null)
.setPositiveButton(R.string.c_save, new DialogInterface.OnClickListener() { .setPositiveButton(R.string.c_save, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (save) { if (save) {
final CalculatorHistoryState savedHistoryItem = CalculatorHistory.instance.addSavedState(historyState); final CalculatorHistoryState savedHistoryItem = AndroidCalculatorHistoryImpl.instance.addSavedState(historyState);
savedHistoryItem.setComment(comment.getText().toString()); savedHistoryItem.setComment(comment.getText().toString());
CalculatorHistory.instance.save(context); AndroidCalculatorHistoryImpl.instance.save(context);
// we don't need to add element to the adapter as adapter of another activity must be updated and not this // we don't need to add element to the adapter as adapter of another activity must be updated and not this
//data.getAdapter().add(savedHistoryItem); //data.getAdapter().add(savedHistoryItem);
} else { } else {
historyState.setComment(comment.getText().toString()); historyState.setComment(comment.getText().toString());
CalculatorHistory.instance.save(context); AndroidCalculatorHistoryImpl.instance.save(context);
} }
data.getAdapter().notifyDataSetChanged(); data.getAdapter().notifyDataSetChanged();
Toast.makeText(context, context.getText(R.string.c_history_saved), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getText(R.string.c_history_saved), Toast.LENGTH_LONG).show();
} }
}) })
.setView(editView); .setView(editView);
builder.create().show(); builder.create().show();
} }
private final int captionId; private final int captionId;
private HistoryItemMenuItem(int captionId) { private HistoryItemMenuItem(int captionId) {
this.captionId = captionId; this.captionId = captionId;
} }
@NotNull @NotNull
@Override @Override
public String getCaption(@NotNull Context context) { public String getCaption(@NotNull Context context) {
return context.getString(captionId); return context.getString(captionId);
} }
} }

View File

@ -1,37 +1,37 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* User: serso * User: serso
* Date: 12/18/11 * Date: 12/18/11
* Time: 7:40 PM * Time: 7:40 PM
*/ */
public class SavedHistoryActivityTab extends AbstractHistoryActivity { public class SavedHistoryActivityTab extends AbstractHistoryActivity {
@Override @Override
protected int getLayoutId() { protected int getLayoutId() {
return R.layout.saved_history; return R.layout.saved_history;
} }
@NotNull @NotNull
@Override @Override
protected List<CalculatorHistoryState> getHistoryItems() { protected List<CalculatorHistoryState> getHistoryItems() {
return new ArrayList<CalculatorHistoryState>(CalculatorHistory.instance.getSavedHistory()); return new ArrayList<CalculatorHistoryState>(AndroidCalculatorHistoryImpl.instance.getSavedHistory());
} }
@Override @Override
protected void clearHistory() { protected void clearHistory() {
CalculatorHistory.instance.clearSavedHistory(this); AndroidCalculatorHistoryImpl.instance.clearSavedHistory(this);
getAdapter().clear(); getAdapter().clear();
} }
} }

View File

@ -15,10 +15,7 @@ import jscl.math.operator.Operator;
import jscl.text.ParseInterruptedException; import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CalculatorApplication; import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.JCalculatorEngine;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.msg.AndroidMessage; import org.solovyev.android.msg.AndroidMessage;

View File

@ -36,8 +36,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.CalculatorParseException; import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.model.PreparedExpression; import org.solovyev.android.calculator.PreparedExpression;
import org.solovyev.android.calculator.model.ToJsclTextProcessor; import org.solovyev.android.calculator.ToJsclTextProcessor;
import org.solovyev.common.MutableObject; import org.solovyev.common.MutableObject;
import java.io.Serializable; import java.io.Serializable;

View File

@ -13,7 +13,7 @@ import org.solovyev.android.calculator.CalculatorModel;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.model.CalculatorEngine; import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.CalculatorParseException; import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.model.ToJsclTextProcessor; import org.solovyev.android.calculator.ToJsclTextProcessor;
import org.solovyev.common.MutableObject; import org.solovyev.common.MutableObject;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.text.StringUtils;

View File

@ -9,7 +9,10 @@ package org.solovyev.android.calculator.view;
import jscl.MathContext; import jscl.MathContext;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.AbstractNumberBuilder;
import org.solovyev.android.calculator.CalculatorParseException; import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.LiteNumberBuilder;
import org.solovyev.android.calculator.NumberBuilder;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.*; import org.solovyev.android.calculator.model.*;
import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.text.TextProcessor;

View File

@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.junit.Test; import org.junit.Test;
import org.solovyev.android.calculator.Editor; import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.ICalculatorDisplay; import org.solovyev.android.calculator.JCalculatorDisplay;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.equals.CollectionEqualizer; import org.solovyev.common.equals.CollectionEqualizer;
import org.solovyev.common.equals.EqualsTool; import org.solovyev.common.equals.EqualsTool;
@ -125,7 +125,7 @@ public class HistoryUtilsTest {
HistoryHelper<CalculatorHistoryState> history = new SimpleHistoryHelper<CalculatorHistoryState>(); HistoryHelper<CalculatorHistoryState> history = new SimpleHistoryHelper<CalculatorHistoryState>();
ICalculatorDisplay calculatorDisplay = new TestCalculatorDisplay(); JCalculatorDisplay calculatorDisplay = new TestCalculatorDisplay();
calculatorDisplay.setErrorMessage("error_msg1"); calculatorDisplay.setErrorMessage("error_msg1");
calculatorDisplay.setText("Error"); calculatorDisplay.setText("Error");
calculatorDisplay.setSelection(1); calculatorDisplay.setSelection(1);
@ -215,7 +215,7 @@ public class HistoryUtilsTest {
} }
private static class TestCalculatorDisplay implements ICalculatorDisplay { private static class TestCalculatorDisplay implements JCalculatorDisplay {
@NotNull @NotNull
private final TestEditor testEditor = new TestEditor(); private final TestEditor testEditor = new TestEditor();

View File

@ -15,6 +15,7 @@ import jscl.math.function.CustomFunction;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.solovyev.android.calculator.CalculatorEvalException;
import org.solovyev.android.calculator.CalculatorParseException; import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;

View File

@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.solovyev.android.calculator.CalculatorEvalException;
import org.solovyev.android.calculator.CalculatorParseException; import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.Converter; import org.solovyev.common.Converter;

View File

@ -12,6 +12,8 @@ import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.solovyev.android.calculator.CalculatorParseException; import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.PreparedExpression;
import org.solovyev.android.calculator.ToJsclTextProcessor;
import org.solovyev.android.calculator.text.TextProcessor; import org.solovyev.android.calculator.text.TextProcessor;
/** /**