Conversion

This commit is contained in:
serso 2012-09-24 17:20:16 +04:00
parent b2fe1d43c9
commit 4b08fa133e
25 changed files with 2036 additions and 1783 deletions

View File

@ -1,58 +1,68 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import jscl.NumeralBase; import jscl.NumeralBase;
import jscl.math.Generic; import jscl.math.Generic;
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.history.CalculatorHistoryState; import org.solovyev.android.calculator.history.CalculatorHistoryState;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.history.HistoryControl; import org.solovyev.common.history.HistoryControl;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 20.09.12 * Date: 20.09.12
* Time: 16:38 * Time: 16:38
*/ */
public interface Calculator extends CalculatorEventContainer, HistoryControl<CalculatorHistoryState> { public interface Calculator extends CalculatorEventContainer, HistoryControl<CalculatorHistoryState> {
void init(); void init();
/* /*
********************************************************************** **********************************************************************
* *
* CALCULATIONS * CALCULATIONS
* *
********************************************************************** **********************************************************************
*/ */
void evaluate(); void evaluate();
void evaluate(@NotNull Long sequenceId); void evaluate(@NotNull Long sequenceId);
void simplify(); void simplify();
@NotNull @NotNull
CalculatorEventDataId evaluate(@NotNull JsclOperation operation, CalculatorEventData evaluate(@NotNull JsclOperation operation,
@NotNull String expression); @NotNull String expression);
@NotNull @NotNull
CalculatorEventDataId evaluate(@NotNull JsclOperation operation, CalculatorEventData evaluate(@NotNull JsclOperation operation,
@NotNull String expression, @NotNull String expression,
@NotNull Long sequenceId); @NotNull Long sequenceId);
@NotNull /*
CalculatorEventDataId convert(@NotNull Generic generic, @NotNull NumeralBase to); **********************************************************************
*
/* * CONVERSION
********************************************************************** *
* **********************************************************************
* EVENTS */
*
********************************************************************** boolean isConversionPossible(@NotNull Generic generic, @NotNull NumeralBase from, @NotNull NumeralBase to);
*/
@NotNull @NotNull
CalculatorEventDataId fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data); CalculatorEventData convert(@NotNull Generic generic, @NotNull NumeralBase to);
@NotNull /*
CalculatorEventDataId fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data, @NotNull Long sequenceId); **********************************************************************
} *
* EVENTS
*
**********************************************************************
*/
@NotNull
CalculatorEventData fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data);
@NotNull
CalculatorEventData fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data, @NotNull Long sequenceId);
}

View File

@ -0,0 +1,26 @@
package org.solovyev.android.calculator;
import jscl.NumeralBase;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
/**
* User: Solovyev_S
* Date: 24.09.12
* Time: 16:45
*/
public interface CalculatorConversionEventData extends CalculatorEventData {
// display state on the moment of conversion
@NotNull
CalculatorDisplayViewState getDisplayState();
@NotNull
NumeralBase getFromNumeralBase();
@NotNull
NumeralBase getToNumeralBase();
@NotNull
Generic getValue();
}

View File

@ -0,0 +1,98 @@
package org.solovyev.android.calculator;
import jscl.NumeralBase;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
/**
* User: Solovyev_S
* Date: 24.09.12
* Time: 16:48
*/
public class CalculatorConversionEventDataImpl implements CalculatorConversionEventData {
@NotNull
private CalculatorEventData calculatorEventData;
@NotNull
private NumeralBase fromNumeralBase;
@NotNull
private NumeralBase toNumeralBase;
@NotNull
private Generic value;
@NotNull
private CalculatorDisplayViewState displayState;
private CalculatorConversionEventDataImpl() {
}
@NotNull
public static CalculatorConversionEventData newInstance(@NotNull CalculatorEventData calculatorEventData,
@NotNull Generic value,
@NotNull NumeralBase from,
@NotNull NumeralBase to,
@NotNull CalculatorDisplayViewState displayViewState) {
final CalculatorConversionEventDataImpl result = new CalculatorConversionEventDataImpl();
result.calculatorEventData = calculatorEventData;
result.value = value;
result.displayState = displayViewState;
result.fromNumeralBase = from;
result.toNumeralBase = to;
return result;
}
@Override
public long getEventId() {
return calculatorEventData.getEventId();
}
@Override
@NotNull
public Long getSequenceId() {
return calculatorEventData.getSequenceId();
}
@Override
public boolean isAfter(@NotNull CalculatorEventData that) {
return calculatorEventData.isAfter(that);
}
@Override
public boolean isSameSequence(@NotNull CalculatorEventData that) {
return calculatorEventData.isSameSequence(that);
}
@Override
public boolean isAfterSequence(@NotNull CalculatorEventData that) {
return calculatorEventData.isAfterSequence(that);
}
@NotNull
@Override
public CalculatorDisplayViewState getDisplayState() {
return this.displayState;
}
@Override
@NotNull
public NumeralBase getFromNumeralBase() {
return fromNumeralBase;
}
@Override
@NotNull
public NumeralBase getToNumeralBase() {
return toNumeralBase;
}
@Override
@NotNull
public Generic getValue() {
return value;
}
}

View File

@ -1,148 +1,170 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import static org.solovyev.android.calculator.CalculatorEventType.*; import static org.solovyev.android.calculator.CalculatorEventType.*;
/** /**
* User: serso * User: serso
* Date: 9/20/12 * Date: 9/20/12
* Time: 8:24 PM * Time: 8:24 PM
*/ */
public class CalculatorDisplayImpl implements CalculatorDisplay { public class CalculatorDisplayImpl implements CalculatorDisplay {
@NotNull @NotNull
private CalculatorEventData lastCalculatorEventData; private CalculatorEventData lastCalculatorEventData;
@Nullable @Nullable
private CalculatorDisplayView view; private CalculatorDisplayView view;
@NotNull @NotNull
private final Object viewLock = new Object(); private final Object viewLock = new Object();
@NotNull @NotNull
private CalculatorDisplayViewState viewState = CalculatorDisplayViewStateImpl.newDefaultInstance(); private CalculatorDisplayViewState viewState = CalculatorDisplayViewStateImpl.newDefaultInstance();
@NotNull @NotNull
private final Calculator calculator; private final Calculator calculator;
public CalculatorDisplayImpl(@NotNull Calculator calculator) { public CalculatorDisplayImpl(@NotNull Calculator calculator) {
this.calculator = calculator; this.calculator = calculator;
this.lastCalculatorEventData = CalculatorEventDataImpl.newInstance(CalculatorUtils.createFirstEventDataId()); this.lastCalculatorEventData = CalculatorUtils.createFirstEventDataId();
this.calculator.addCalculatorEventListener(this); this.calculator.addCalculatorEventListener(this);
} }
@Override @Override
public void setView(@Nullable CalculatorDisplayView view) { public void setView(@Nullable CalculatorDisplayView view) {
synchronized (viewLock) { synchronized (viewLock) {
this.view = view; this.view = view;
if (view != null) { if (view != null) {
this.view.setState(viewState); this.view.setState(viewState);
} }
} }
} }
@Nullable @Nullable
@Override @Override
public CalculatorDisplayView getView() { public CalculatorDisplayView getView() {
return this.view; return this.view;
} }
@NotNull @NotNull
@Override @Override
public CalculatorDisplayViewState getViewState() { public CalculatorDisplayViewState getViewState() {
return this.viewState; return this.viewState;
} }
@Override @Override
public void setViewState(@NotNull CalculatorDisplayViewState newViewState) { public void setViewState(@NotNull CalculatorDisplayViewState newViewState) {
synchronized (viewLock) { synchronized (viewLock) {
final CalculatorDisplayViewState oldViewState = setViewState0(newViewState); final CalculatorDisplayViewState oldViewState = setViewState0(newViewState);
this.calculator.fireCalculatorEvent(display_state_changed, new CalculatorDisplayChangeEventDataImpl(oldViewState, newViewState)); this.calculator.fireCalculatorEvent(display_state_changed, new CalculatorDisplayChangeEventDataImpl(oldViewState, newViewState));
} }
} }
private void setViewStateForSequence(@NotNull CalculatorDisplayViewState newViewState, @NotNull Long sequenceId) { private void setViewStateForSequence(@NotNull CalculatorDisplayViewState newViewState, @NotNull Long sequenceId) {
synchronized (viewLock) { synchronized (viewLock) {
final CalculatorDisplayViewState oldViewState = setViewState0(newViewState); final CalculatorDisplayViewState oldViewState = setViewState0(newViewState);
this.calculator.fireCalculatorEvent(display_state_changed, new CalculatorDisplayChangeEventDataImpl(oldViewState, newViewState), sequenceId); this.calculator.fireCalculatorEvent(display_state_changed, new CalculatorDisplayChangeEventDataImpl(oldViewState, newViewState), sequenceId);
} }
} }
// must be synchronized with viewLock // must be synchronized with viewLock
@NotNull @NotNull
private CalculatorDisplayViewState setViewState0(@NotNull CalculatorDisplayViewState newViewState) { private CalculatorDisplayViewState setViewState0(@NotNull CalculatorDisplayViewState newViewState) {
final CalculatorDisplayViewState oldViewState = this.viewState; final CalculatorDisplayViewState oldViewState = this.viewState;
this.viewState = newViewState; this.viewState = newViewState;
if (this.view != null) { if (this.view != null) {
this.view.setState(newViewState); this.view.setState(newViewState);
} }
return oldViewState; return oldViewState;
} }
@Override @Override
@NotNull @NotNull
public CalculatorEventData getLastEventData() { public CalculatorEventData getLastEventData() {
return lastCalculatorEventData; return lastCalculatorEventData;
} }
@Override @Override
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData,
@NotNull CalculatorEventType calculatorEventType, @NotNull CalculatorEventType calculatorEventType,
@Nullable Object data) { @Nullable Object data) {
if (calculatorEventType.isOfType(calculation_result, calculation_failed, calculation_cancelled)) { if (calculatorEventType.isOfType(calculation_result, calculation_failed, calculation_cancelled, conversion_result, conversion_failed)) {
if (calculatorEventData.isAfter(lastCalculatorEventData)) { if (calculatorEventData.isAfter(lastCalculatorEventData)) {
lastCalculatorEventData = calculatorEventData; lastCalculatorEventData = calculatorEventData;
} }
switch (calculatorEventType) { switch (calculatorEventType) {
case calculation_result: case conversion_failed:
processCalculationResult((CalculatorEvaluationEventData)calculatorEventData, (CalculatorOutput) data); processConversationFailed((CalculatorConversionEventData) calculatorEventData, (ConversionFailure) data);
break; break;
case calculation_cancelled: case conversion_result:
processCalculationCancelled((CalculatorEvaluationEventData)calculatorEventData); processConversationResult((CalculatorConversionEventData)calculatorEventData, (String)data);
break; break;
case calculation_failed: case calculation_result:
processCalculationFailed((CalculatorEvaluationEventData)calculatorEventData, (CalculatorFailure) data); processCalculationResult((CalculatorEvaluationEventData) calculatorEventData, (CalculatorOutput) data);
break; break;
} case calculation_cancelled:
processCalculationCancelled((CalculatorEvaluationEventData)calculatorEventData);
} break;
} case calculation_failed:
processCalculationFailed((CalculatorEvaluationEventData)calculatorEventData, (CalculatorFailure) data);
private void processCalculationFailed(@NotNull CalculatorEvaluationEventData calculatorEventData, @NotNull CalculatorFailure data) { break;
}
final CalculatorEvalException calculatorEvalException = data.getCalculationEvalException();
}
final String errorMessage; }
if (calculatorEvalException != null) {
errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error); private void processConversationFailed(@NotNull CalculatorConversionEventData calculatorEventData,
} else { @NotNull ConversionFailure data) {
final CalculatorParseException calculationParseException = data.getCalculationParseException(); this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getDisplayState().getOperation(), CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error)), calculatorEventData.getSequenceId());
if (calculationParseException != null) {
errorMessage = calculationParseException.getLocalizedMessage(); }
} else {
errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error); private void processCalculationFailed(@NotNull CalculatorEvaluationEventData calculatorEventData, @NotNull CalculatorFailure data) {
}
} final CalculatorEvalException calculatorEvalException = data.getCalculationEvalException();
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage), calculatorEventData.getSequenceId()); final String errorMessage;
} if (calculatorEvalException != null) {
errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
private void processCalculationCancelled(@NotNull CalculatorEvaluationEventData calculatorEventData) { } else {
final String errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error); final CalculatorParseException calculationParseException = data.getCalculationParseException();
if (calculationParseException != null) {
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage), calculatorEventData.getSequenceId()); errorMessage = calculationParseException.getLocalizedMessage();
} } else {
errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
private void processCalculationResult(@NotNull CalculatorEvaluationEventData calculatorEventData, @NotNull CalculatorOutput data) { }
final String stringResult = data.getStringResult(); }
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newValidState(calculatorEventData.getOperation(), data.getResult(), stringResult, 0), calculatorEventData.getSequenceId());
} this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage), calculatorEventData.getSequenceId());
} }
private void processCalculationCancelled(@NotNull CalculatorEvaluationEventData calculatorEventData) {
final String errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage), calculatorEventData.getSequenceId());
}
private void processCalculationResult(@NotNull CalculatorEvaluationEventData calculatorEventData, @NotNull CalculatorOutput data) {
final String stringResult = data.getStringResult();
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newValidState(calculatorEventData.getOperation(), data.getResult(), stringResult, 0), calculatorEventData.getSequenceId());
}
private void processConversationResult(@NotNull CalculatorConversionEventData calculatorEventData, @NotNull String result) {
// add prefix
if (calculatorEventData.getFromNumeralBase() != calculatorEventData.getToNumeralBase()) {
result = calculatorEventData.getToNumeralBase().getJsclPrefix() + result;
}
final CalculatorDisplayViewState displayState = calculatorEventData.getDisplayState();
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newValidState(displayState.getOperation(), displayState.getResult(), result, 0), calculatorEventData.getSequenceId());
}
}

View File

@ -1,18 +1,18 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
/** /**
* User: serso * User: serso
* Date: 9/20/12 * Date: 9/20/12
* Time: 10:00 PM * Time: 10:00 PM
*/ */
public interface CalculatorEvaluationEventData extends CalculatorEventData{ public interface CalculatorEvaluationEventData extends CalculatorEventData {
@NotNull @NotNull
JsclOperation getOperation(); JsclOperation getOperation();
@NotNull @NotNull
String getExpression(); String getExpression();
} }

View File

@ -1,67 +1,67 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
/** /**
* User: serso * User: serso
* Date: 9/20/12 * Date: 9/20/12
* Time: 10:01 PM * Time: 10:01 PM
*/ */
public class CalculatorEvaluationEventDataImpl implements CalculatorEvaluationEventData { public class CalculatorEvaluationEventDataImpl implements CalculatorEvaluationEventData {
@NotNull @NotNull
private final CalculatorEventData calculatorEventData; private final CalculatorEventData calculatorEventData;
@NotNull @NotNull
private final JsclOperation operation; private final JsclOperation operation;
@NotNull @NotNull
private final String expression; private final String expression;
public CalculatorEvaluationEventDataImpl(@NotNull CalculatorEventData calculatorEventData, public CalculatorEvaluationEventDataImpl(@NotNull CalculatorEventData calculatorEventData,
@NotNull JsclOperation operation, @NotNull JsclOperation operation,
@NotNull String expression) { @NotNull String expression) {
this.calculatorEventData = calculatorEventData; this.calculatorEventData = calculatorEventData;
this.operation = operation; this.operation = operation;
this.expression = expression; this.expression = expression;
} }
@NotNull @NotNull
@Override @Override
public JsclOperation getOperation() { public JsclOperation getOperation() {
return this.operation; return this.operation;
} }
@NotNull @NotNull
@Override @Override
public String getExpression() { public String getExpression() {
return this.expression; return this.expression;
} }
@Override @Override
public long getEventId() { public long getEventId() {
return calculatorEventData.getEventId(); return calculatorEventData.getEventId();
} }
@NotNull @NotNull
@Override @Override
public Long getSequenceId() { public Long getSequenceId() {
return calculatorEventData.getSequenceId(); return calculatorEventData.getSequenceId();
} }
@Override @Override
public boolean isAfter(@NotNull CalculatorEventDataId that) { public boolean isAfter(@NotNull CalculatorEventData that) {
return calculatorEventData.isAfter(that); return calculatorEventData.isAfter(that);
} }
@Override @Override
public boolean isSameSequence(@NotNull CalculatorEventDataId that) { public boolean isSameSequence(@NotNull CalculatorEventData that) {
return this.calculatorEventData.isSameSequence(that); return this.calculatorEventData.isSameSequence(that);
} }
@Override @Override
public boolean isAfterSequence(@NotNull CalculatorEventDataId that) { public boolean isAfterSequence(@NotNull CalculatorEventData that) {
return this.calculatorEventData.isAfterSequence(that); return this.calculatorEventData.isAfterSequence(that);
} }
} }

View File

@ -1,10 +1,24 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
/** import org.jetbrains.annotations.NotNull;
* User: Solovyev_S
* Date: 20.09.12 /**
* Time: 16:51 * User: Solovyev_S
*/ * Date: 20.09.12
public interface CalculatorEventData extends CalculatorEventDataId { * Time: 18:18
*/
} public interface CalculatorEventData {
// the higher id => the later event
long getEventId();
// the higher id => the later event
@NotNull
Long getSequenceId();
boolean isAfter(@NotNull CalculatorEventData that);
boolean isSameSequence(@NotNull CalculatorEventData that);
boolean isAfterSequence(@NotNull CalculatorEventData that);
}

View File

@ -1,24 +0,0 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 18:18
*/
public interface CalculatorEventDataId {
// the higher id => the later event
long getEventId();
// the higher id => the later event
@NotNull
Long getSequenceId();
boolean isAfter(@NotNull CalculatorEventDataId that);
boolean isSameSequence(@NotNull CalculatorEventDataId that);
boolean isAfterSequence(@NotNull CalculatorEventDataId that);
}

View File

@ -1,75 +0,0 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
/**
* User: Solovyev_S
* Date: 20.09.12
* Time: 18:18
*/
class CalculatorEventDataIdImpl implements CalculatorEventDataId {
private static final long NO_SEQUENCE = -1L;
private final long eventId;
@NotNull
private Long sequenceId = NO_SEQUENCE;
private CalculatorEventDataIdImpl(long id, @NotNull Long sequenceId) {
this.eventId = id;
this.sequenceId = sequenceId;
}
@NotNull
static CalculatorEventDataId newInstance(long id, @NotNull Long sequenceId) {
return new CalculatorEventDataIdImpl(id, sequenceId);
}
@Override
public long getEventId() {
return this.eventId;
}
@NotNull
@Override
public Long getSequenceId() {
return this.sequenceId;
}
@Override
public boolean isAfter(@NotNull CalculatorEventDataId that) {
return this.eventId > that.getEventId();
}
@Override
public boolean isSameSequence(@NotNull CalculatorEventDataId that) {
return !this.sequenceId.equals(NO_SEQUENCE) && this.sequenceId.equals(that.getSequenceId());
}
@Override
public boolean isAfterSequence(@NotNull CalculatorEventDataId that) {
return !this.sequenceId.equals(NO_SEQUENCE) && this.sequenceId > that.getSequenceId();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CalculatorEventDataIdImpl)) return false;
CalculatorEventDataIdImpl that = (CalculatorEventDataIdImpl) o;
if (eventId != that.eventId) return false;
if (!sequenceId.equals(that.sequenceId))
return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (eventId ^ (eventId >>> 32));
result = 31 * result + (sequenceId.hashCode());
return result;
}
}

View File

@ -1,66 +1,75 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 20.09.12 * Date: 20.09.12
* Time: 16:54 * Time: 18:18
*/ */
class CalculatorEventDataImpl implements CalculatorEventData { class CalculatorEventDataImpl implements CalculatorEventData {
@NotNull private static final long NO_SEQUENCE = -1L;
private CalculatorEventDataId calculatorEventDataId;
private final long eventId;
private CalculatorEventDataImpl(@NotNull CalculatorEventDataId calculatorEventDataId) {
this.calculatorEventDataId = calculatorEventDataId; @NotNull
} private Long sequenceId = NO_SEQUENCE;
@NotNull private CalculatorEventDataImpl(long id, @NotNull Long sequenceId) {
public static CalculatorEventData newInstance(@NotNull CalculatorEventDataId calculatorEventDataId) { this.eventId = id;
return new CalculatorEventDataImpl(calculatorEventDataId); this.sequenceId = sequenceId;
} }
@Override @NotNull
public long getEventId() { static CalculatorEventData newInstance(long id, @NotNull Long sequenceId) {
return calculatorEventDataId.getEventId(); return new CalculatorEventDataImpl(id, sequenceId);
} }
@NotNull @Override
@Override public long getEventId() {
public Long getSequenceId() { return this.eventId;
return calculatorEventDataId.getSequenceId(); }
}
@NotNull
@Override @Override
public boolean isAfter(@NotNull CalculatorEventDataId that) { public Long getSequenceId() {
return this.calculatorEventDataId.isAfter(that); return this.sequenceId;
} }
@Override @Override
public boolean isSameSequence(@NotNull CalculatorEventDataId that) { public boolean isAfter(@NotNull CalculatorEventData that) {
return this.calculatorEventDataId.isSameSequence(that); return this.eventId > that.getEventId();
} }
@Override @Override
public boolean isAfterSequence(@NotNull CalculatorEventDataId that) { public boolean isSameSequence(@NotNull CalculatorEventData that) {
return this.calculatorEventDataId.isAfterSequence(that); return !this.sequenceId.equals(NO_SEQUENCE) && this.sequenceId.equals(that.getSequenceId());
} }
@Override @Override
public boolean equals(Object o) { public boolean isAfterSequence(@NotNull CalculatorEventData that) {
if (this == o) return true; return !this.sequenceId.equals(NO_SEQUENCE) && this.sequenceId > that.getSequenceId();
if (!(o instanceof CalculatorEventDataImpl)) return false; }
CalculatorEventDataImpl that = (CalculatorEventDataImpl) o; @Override
public boolean equals(Object o) {
if (!calculatorEventDataId.equals(that.calculatorEventDataId)) return false; if (this == o) return true;
if (!(o instanceof CalculatorEventDataImpl)) return false;
return true;
} CalculatorEventDataImpl that = (CalculatorEventDataImpl) o;
@Override if (eventId != that.eventId) return false;
public int hashCode() { if (!sequenceId.equals(that.sequenceId))
return calculatorEventDataId.hashCode(); return false;
}
} return true;
}
@Override
public int hashCode() {
int result = (int) (eventId ^ (eventId >>> 32));
result = 31 * result + (sequenceId.hashCode());
return result;
}
}

View File

@ -1,83 +1,90 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 20.09.12 * Date: 20.09.12
* Time: 16:40 * Time: 16:40
*/ */
public enum CalculatorEventType { public enum CalculatorEventType {
/* /*
********************************************************************** **********************************************************************
* *
* org.solovyev.android.calculator.CalculatorEvaluationEventData * CALCULATION
* * org.solovyev.android.calculator.CalculatorEvaluationEventData
********************************************************************** *
*/ **********************************************************************
*/
// @NotNull CalculatorEditorViewState
manual_calculation_requested, // @NotNull CalculatorEditorViewState
manual_calculation_requested,
// @NotNull org.solovyev.android.calculator.CalculatorInput
calculation_started, // @NotNull org.solovyev.android.calculator.CalculatorInput
calculation_started,
// @NotNull org.solovyev.android.calculator.CalculatorOutput
calculation_result, // @NotNull org.solovyev.android.calculator.CalculatorOutput
calculation_result,
calculation_cancelled,
calculation_cancelled,
calculation_finished,
// @NotNull org.solovyev.android.calculator.CalculatorFailure
// @NotNull org.solovyev.android.calculator.CalculatorFailure calculation_failed,
calculation_failed,
calculation_finished,
/*
********************************************************************** /*
* **********************************************************************
* CONVERSION *
* * CONVERSION
********************************************************************** * CalculatorConversionEventData
*/ *
conversion_started, **********************************************************************
*/
// @NotNull String conversion result conversion_started,
conversion_finished,
// @NotNull String conversion result
/* conversion_result,
**********************************************************************
* // @NotNull ConversionFailure
* EDITOR conversion_failed,
*
********************************************************************** conversion_finished,
*/
/*
// @NotNull org.solovyev.android.calculator.CalculatorEditorChangeEventData **********************************************************************
editor_state_changed, *
* EDITOR
// @NotNull CalculatorDisplayChangeEventData *
display_state_changed, **********************************************************************
*/
/*
********************************************************************** // @NotNull org.solovyev.android.calculator.CalculatorEditorChangeEventData
* editor_state_changed,
* ENGINE
* // @NotNull CalculatorDisplayChangeEventData
********************************************************************** display_state_changed,
*/
/*
engine_preferences_changed; **********************************************************************
*
public boolean isOfType(@NotNull CalculatorEventType... types) { * ENGINE
for (CalculatorEventType type : types) { *
if ( this == type ) { **********************************************************************
return true; */
}
} engine_preferences_changed;
return false; public boolean isOfType(@NotNull CalculatorEventType... types) {
} for (CalculatorEventType type : types) {
if ( this == type ) {
} return true;
}
}
return false;
}
}

View File

@ -1,405 +1,433 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import jscl.AbstractJsclArithmeticException; import jscl.AbstractJsclArithmeticException;
import jscl.NumeralBase; import jscl.NumeralBase;
import jscl.NumeralBaseException; import jscl.NumeralBaseException;
import jscl.math.Generic; import jscl.math.Generic;
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.history.CalculatorHistory; import org.solovyev.android.calculator.history.CalculatorHistory;
import org.solovyev.android.calculator.history.CalculatorHistoryState; import org.solovyev.android.calculator.history.CalculatorHistoryState;
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.common.history.HistoryAction; import org.solovyev.android.calculator.units.CalculatorNumeralBase;
import org.solovyev.common.msg.MessageRegistry; import org.solovyev.common.history.HistoryAction;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageRegistry;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.msg.MessageType;
import org.solovyev.math.units.UnitConverter; import org.solovyev.common.text.StringUtils;
import org.solovyev.math.units.UnitImpl; import org.solovyev.math.units.*;
import org.solovyev.math.units.UnitType;
import java.util.List;
import java.util.List; import java.util.concurrent.Executor;
import java.util.concurrent.Executor; import java.util.concurrent.Executors;
import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLong;
/**
/** * User: Solovyev_S
* User: Solovyev_S * Date: 20.09.12
* Date: 20.09.12 * Time: 16:42
* Time: 16:42 */
*/ public class CalculatorImpl implements Calculator, CalculatorEventListener {
public class CalculatorImpl implements Calculator, CalculatorEventListener {
@NotNull
@NotNull private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer();
private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer();
@NotNull
@NotNull private final AtomicLong counter = new AtomicLong(CalculatorUtils.FIRST_ID);
private final AtomicLong counter = new AtomicLong(CalculatorUtils.FIRST_ID);
@NotNull
@NotNull private final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
private final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
@NotNull
@NotNull private final Executor threadPoolExecutor = Executors.newFixedThreadPool(10);
private final Executor threadPoolExecutor = Executors.newFixedThreadPool(10);
public CalculatorImpl() {
public CalculatorImpl() { this.addCalculatorEventListener(this);
this.addCalculatorEventListener(this); }
}
@NotNull
@NotNull private CalculatorEventData nextEventData() {
public static String doConversion(@NotNull UnitConverter<String> converter, long eventId = counter.incrementAndGet();
@Nullable String from, return CalculatorEventDataImpl.newInstance(eventId, eventId);
@NotNull UnitType<String> fromUnitType, }
@NotNull UnitType<String> toUnitType) throws ConversionException {
final String result; @NotNull
private CalculatorEventData nextEventData(@NotNull Long sequenceId) {
if (StringUtils.isEmpty(from)) { long eventId = counter.incrementAndGet();
result = ""; return CalculatorEventDataImpl.newInstance(eventId, sequenceId);
} else { }
String to = null; /*
try { **********************************************************************
if (converter.isSupported(fromUnitType, toUnitType)) { *
to = converter.convert(UnitImpl.newInstance(from, fromUnitType), toUnitType).getValue(); * CALCULATION
} *
} catch (RuntimeException e) { **********************************************************************
throw new ConversionException(e); */
}
@Override
result = to; public void evaluate() {
} final CalculatorEditorViewState viewState = getEditor().getViewState();
fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState);
return result; this.evaluate(JsclOperation.numeric, viewState.getText());
} }
@NotNull @Override
private CalculatorEventDataId nextEventDataId() { public void evaluate(@NotNull Long sequenceId) {
long eventId = counter.incrementAndGet(); final CalculatorEditorViewState viewState = getEditor().getViewState();
return CalculatorEventDataIdImpl.newInstance(eventId, eventId); fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState, sequenceId);
} this.evaluate(JsclOperation.numeric, viewState.getText(), sequenceId);
}
@NotNull
private CalculatorEventDataId nextEventDataId(@NotNull Long sequenceId) { @Override
long eventId = counter.incrementAndGet(); public void simplify() {
return CalculatorEventDataIdImpl.newInstance(eventId, sequenceId); final CalculatorEditorViewState viewState = getEditor().getViewState();
} fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState);
this.evaluate(JsclOperation.simplify, viewState.getText());
/* }
**********************************************************************
* @NotNull
* CALCULATION @Override
* public CalculatorEventData evaluate(@NotNull final JsclOperation operation,
********************************************************************** @NotNull final String expression) {
*/
final CalculatorEventData eventDataId = nextEventData();
@Override
public void evaluate() { threadPoolExecutor.execute(new Runnable() {
final CalculatorEditorViewState viewState = getEditor().getViewState(); @Override
fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState); public void run() {
this.evaluate(JsclOperation.numeric, viewState.getText()); CalculatorImpl.this.evaluate(eventDataId.getSequenceId(), operation, expression, null);
} }
});
@Override
public void evaluate(@NotNull Long sequenceId) { return eventDataId;
final CalculatorEditorViewState viewState = getEditor().getViewState(); }
fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState, sequenceId);
this.evaluate(JsclOperation.numeric, viewState.getText(), sequenceId); @NotNull
} @Override
public CalculatorEventData evaluate(@NotNull final JsclOperation operation, @NotNull final String expression, @NotNull Long sequenceId) {
@Override final CalculatorEventData eventDataId = nextEventData(sequenceId);
public void simplify() {
final CalculatorEditorViewState viewState = getEditor().getViewState(); threadPoolExecutor.execute(new Runnable() {
fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState); @Override
this.evaluate(JsclOperation.simplify, viewState.getText()); public void run() {
} CalculatorImpl.this.evaluate(eventDataId.getSequenceId(), operation, expression, null);
}
@NotNull });
@Override
public CalculatorEventDataId evaluate(@NotNull final JsclOperation operation, return eventDataId;
@NotNull final String expression) { }
final CalculatorEventDataId eventDataId = nextEventDataId(); @Override
public void init() {
threadPoolExecutor.execute(new Runnable() { CalculatorLocatorImpl.getInstance().getEngine().init();
@Override CalculatorLocatorImpl.getInstance().getHistory().load();
public void run() { }
CalculatorImpl.this.evaluate(eventDataId.getSequenceId(), operation, expression, null);
} @NotNull
}); private CalculatorConversionEventData newConversionEventData(@NotNull Long sequenceId,
@NotNull Generic value,
return eventDataId; @NotNull NumeralBase from,
} @NotNull NumeralBase to,
@NotNull CalculatorDisplayViewState displayViewState) {
@NotNull return CalculatorConversionEventDataImpl.newInstance(nextEventData(sequenceId), value, from, to, displayViewState);
@Override }
public CalculatorEventDataId evaluate(@NotNull final JsclOperation operation, @NotNull final String expression, @NotNull Long sequenceId) {
final CalculatorEventDataId eventDataId = nextEventDataId(sequenceId); private void evaluate(@NotNull Long sequenceId,
@NotNull JsclOperation operation,
threadPoolExecutor.execute(new Runnable() { @NotNull String expression,
@Override @Nullable MessageRegistry mr) {
public void run() {
CalculatorImpl.this.evaluate(eventDataId.getSequenceId(), operation, expression, null); PreparedExpression preparedExpression = null;
}
}); fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_started, new CalculatorInputImpl(expression, operation));
return eventDataId; try {
}
expression = expression.trim();
@NotNull
@Override if (StringUtils.isEmpty(expression)) {
public CalculatorEventDataId convert(@NotNull final Generic generic, fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, CalculatorOutputImpl.newEmptyOutput(operation));
@NotNull final NumeralBase to) { } else {
final CalculatorEventDataId eventDataId = nextEventDataId(); preparedExpression = preprocessor.process(expression);
threadPoolExecutor.execute(new Runnable() { final String jsclExpression = preparedExpression.toString();
@Override
public void run() { try {
final Long sequenceId = eventDataId.getSequenceId();
final Generic result = operation.evaluateGeneric(jsclExpression, CalculatorLocatorImpl.getInstance().getEngine().getMathEngine());
fireCalculatorEvent(newConversionEventData(sequenceId), CalculatorEventType.conversion_started, null);
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!)
final NumeralBase from = CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase(); result.toString();
if (from != to) { final CalculatorOutput data = CalculatorOutputImpl.newOutput(operation.getFromProcessor().process(result), operation, result);
String fromString = generic.toString(); fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, data);
if (!StringUtils.isEmpty(fromString)) {
try { } catch (AbstractJsclArithmeticException e) {
fromString = ToJsclTextProcessor.getInstance().process(fromString).getExpression(); handleException(sequenceId, operation, expression, mr, new CalculatorEvalException(e, e, jsclExpression));
} catch (CalculatorParseException e) { }
// ok, problems while processing occurred }
}
} } catch (ArithmeticException e) {
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_001, MessageType.error, e.getMessage())));
// todo serso: continue } catch (StackOverflowError e) {
//doConversion(AndroidNumeralBase.getConverter(), fromString, AndroidNumeralBase.valueOf(fromString), AndroidNumeralBase.valueOf(to)); handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_002, MessageType.error)));
} else { } catch (jscl.text.ParseException e) {
fireCalculatorEvent(newConversionEventData(sequenceId), CalculatorEventType.conversion_finished, generic.toString()); handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(e));
} } catch (ParseInterruptedException e) {
}
}); // do nothing - we ourselves interrupt the calculations
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_cancelled, null);
return eventDataId;
} } catch (CalculatorParseException e) {
handleException(sequenceId, operation, expression, mr, preparedExpression, e);
@NotNull } finally {
@Override fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_finished, null);
public CalculatorEventDataId fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data) { }
final CalculatorEventDataId eventDataId = nextEventDataId(); }
threadPoolExecutor.execute(new Runnable() { @NotNull
@Override private CalculatorEventData newCalculationEventData(@NotNull JsclOperation operation,
public void run() { @NotNull String expression,
fireCalculatorEvent(CalculatorEventDataImpl.newInstance(eventDataId), calculatorEventType, data); @NotNull Long calculationId) {
} return new CalculatorEvaluationEventDataImpl(nextEventData(calculationId), operation, expression);
}); }
return eventDataId; private void handleException(@NotNull Long sequenceId,
} @NotNull JsclOperation operation,
@NotNull String expression,
@NotNull @Nullable MessageRegistry mr,
@Override @Nullable PreparedExpression preparedExpression,
public CalculatorEventDataId fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data, @NotNull Long sequenceId) { @NotNull CalculatorParseException parseException) {
final CalculatorEventDataId eventDataId = nextEventDataId(sequenceId);
if (operation == JsclOperation.numeric
threadPoolExecutor.execute(new Runnable() { && preparedExpression != null
@Override && preparedExpression.isExistsUndefinedVar()) {
public void run() {
fireCalculatorEvent(CalculatorEventDataImpl.newInstance(eventDataId), calculatorEventType, data); evaluate(sequenceId, JsclOperation.simplify, expression, mr);
} } else {
});
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(parseException));
return eventDataId; }
} }
@Override private void handleException(@NotNull Long calculationId,
public void init() { @NotNull JsclOperation operation,
CalculatorLocatorImpl.getInstance().getEngine().init(); @NotNull String expression,
CalculatorLocatorImpl.getInstance().getHistory().load(); @Nullable MessageRegistry mr,
} @NotNull CalculatorEvalException evalException) {
@NotNull if (operation == JsclOperation.numeric && evalException.getCause() instanceof NumeralBaseException) {
private CalculatorEventData newConversionEventData(@NotNull Long sequenceId) { evaluate(calculationId, JsclOperation.simplify, expression, mr);
return CalculatorEventDataImpl.newInstance(nextEventDataId(sequenceId)); }
}
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(evalException));
private void evaluate(@NotNull Long sequenceId, }
@NotNull JsclOperation operation,
@NotNull String expression, /*
@Nullable MessageRegistry mr) { **********************************************************************
*
PreparedExpression preparedExpression = null; * CONVERSION
*
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_started, new CalculatorInputImpl(expression, operation)); **********************************************************************
*/
try {
@NotNull
expression = expression.trim(); @Override
public CalculatorEventData convert(@NotNull final Generic value,
if (StringUtils.isEmpty(expression)) { @NotNull final NumeralBase to) {
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, CalculatorOutputImpl.newEmptyOutput(operation)); final CalculatorEventData eventDataId = nextEventData();
} else {
preparedExpression = preprocessor.process(expression); final CalculatorDisplayViewState displayViewState = CalculatorLocatorImpl.getInstance().getDisplay().getViewState();
final NumeralBase from = CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase();
final String jsclExpression = preparedExpression.toString();
threadPoolExecutor.execute(new Runnable() {
try { @Override
public void run() {
final Generic result = operation.evaluateGeneric(jsclExpression, CalculatorLocatorImpl.getInstance().getEngine().getMathEngine()); final Long sequenceId = eventDataId.getSequenceId();
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!) fireCalculatorEvent(newConversionEventData(sequenceId, value, from, to, displayViewState), CalculatorEventType.conversion_started, null);
result.toString(); try {
final CalculatorOutput data = CalculatorOutputImpl.newOutput(operation.getFromProcessor().process(result), operation, result); final String result = doConversion(value, from, to);
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, data);
fireCalculatorEvent(newConversionEventData(sequenceId, value, from, to, displayViewState), CalculatorEventType.conversion_result, result);
} catch (AbstractJsclArithmeticException e) {
handleException(sequenceId, operation, expression, mr, new CalculatorEvalException(e, e, jsclExpression)); } catch (ConversionException e) {
} fireCalculatorEvent(newConversionEventData(sequenceId, value, from, to, displayViewState), CalculatorEventType.conversion_failed, new ConversionFailureImpl(e));
} }
}
} catch (ArithmeticException e) { });
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_001, MessageType.error, e.getMessage())));
} catch (StackOverflowError e) { return eventDataId;
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_002, MessageType.error))); }
} catch (jscl.text.ParseException e) {
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(e)); @NotNull
} catch (ParseInterruptedException e) { private static String doConversion(@NotNull Generic generic,
@NotNull NumeralBase from,
// do nothing - we ourselves interrupt the calculations @NotNull NumeralBase to) throws ConversionException {
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_cancelled, null); final String result;
} catch (CalculatorParseException e) { if (from != to) {
handleException(sequenceId, operation, expression, mr, preparedExpression, e); String fromString = generic.toString();
} finally { if (!StringUtils.isEmpty(fromString)) {
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_finished, null); try {
} fromString = ToJsclTextProcessor.getInstance().process(fromString).getExpression();
} } catch (CalculatorParseException e) {
// ok, problems while processing occurred
@NotNull }
private CalculatorEventData newCalculationEventData(@NotNull JsclOperation operation, }
@NotNull String expression,
@NotNull Long calculationId) { result = ConversionUtils.doConversion(CalculatorNumeralBase.getConverter(), fromString, CalculatorNumeralBase.valueOf(from), CalculatorNumeralBase.valueOf(to));
return new CalculatorEvaluationEventDataImpl(CalculatorEventDataImpl.newInstance(nextEventDataId(calculationId)), operation, expression); } else {
} result = generic.toString();
}
private void handleException(@NotNull Long sequenceId,
@NotNull JsclOperation operation, return result;
@NotNull String expression, }
@Nullable MessageRegistry mr,
@Nullable PreparedExpression preparedExpression, @Override
@NotNull CalculatorParseException parseException) { public boolean isConversionPossible(@NotNull Generic generic, NumeralBase from, @NotNull NumeralBase to) {
try {
if (operation == JsclOperation.numeric doConversion(generic, from, to);
&& preparedExpression != null return true;
&& preparedExpression.isExistsUndefinedVar()) { } catch (ConversionException e) {
return false;
evaluate(sequenceId, JsclOperation.simplify, expression, mr); }
} else { }
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(parseException)); /*
} **********************************************************************
} *
* EVENTS
private void handleException(@NotNull Long calculationId, *
@NotNull JsclOperation operation, **********************************************************************
@NotNull String expression, */
@Nullable MessageRegistry mr,
@NotNull CalculatorEvalException evalException) { @Override
public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
if (operation == JsclOperation.numeric && evalException.getCause() instanceof NumeralBaseException) { calculatorEventContainer.addCalculatorEventListener(calculatorEventListener);
evaluate(calculationId, JsclOperation.simplify, expression, mr); }
}
@Override
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(evalException)); public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
} calculatorEventContainer.removeCalculatorEventListener(calculatorEventListener);
}
/*
********************************************************************** @Override
* public void fireCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
* EVENTS calculatorEventContainer.fireCalculatorEvent(calculatorEventData, calculatorEventType, data);
* }
**********************************************************************
*/ @Override
public void fireCalculatorEvents(@NotNull List<CalculatorEvent> calculatorEvents) {
@Override calculatorEventContainer.fireCalculatorEvents(calculatorEvents);
public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) { }
calculatorEventContainer.addCalculatorEventListener(calculatorEventListener);
} @NotNull
@Override
@Override public CalculatorEventData fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data) {
public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) { final CalculatorEventData eventData = nextEventData();
calculatorEventContainer.removeCalculatorEventListener(calculatorEventListener);
} threadPoolExecutor.execute(new Runnable() {
@Override
@Override public void run() {
public void fireCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) { fireCalculatorEvent(eventData, calculatorEventType, data);
calculatorEventContainer.fireCalculatorEvent(calculatorEventData, calculatorEventType, data); }
} });
@Override return eventData;
public void fireCalculatorEvents(@NotNull List<CalculatorEvent> calculatorEvents) { }
calculatorEventContainer.fireCalculatorEvents(calculatorEvents);
} @NotNull
@Override
@Override public CalculatorEventData fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data, @NotNull Long sequenceId) {
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) { final CalculatorEventData eventData = nextEventData(sequenceId);
switch (calculatorEventType) { threadPoolExecutor.execute(new Runnable() {
case editor_state_changed: @Override
final CalculatorEditorChangeEventData changeEventData = (CalculatorEditorChangeEventData) data; public void run() {
fireCalculatorEvent(eventData, calculatorEventType, data);
final String newText = changeEventData.getNewState().getText(); }
final String oldText = changeEventData.getOldState().getText(); });
if (!newText.equals(oldText)) { return eventData;
evaluate(JsclOperation.numeric, changeEventData.getNewState().getText(), calculatorEventData.getSequenceId()); }
}
break; /*
case engine_preferences_changed: **********************************************************************
evaluate(calculatorEventData.getSequenceId()); *
break; * EVENTS HANDLER
} *
} **********************************************************************
*/
@Override
public void doHistoryAction(@NotNull HistoryAction historyAction) { @Override
final CalculatorHistory history = CalculatorLocatorImpl.getInstance().getHistory(); public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
if (history.isActionAvailable(historyAction)) {
final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState()); switch (calculatorEventType) {
if (newState != null) { case editor_state_changed:
setCurrentHistoryState(newState); final CalculatorEditorChangeEventData changeEventData = (CalculatorEditorChangeEventData) data;
}
} final String newText = changeEventData.getNewState().getText();
} final String oldText = changeEventData.getOldState().getText();
@Override if (!newText.equals(oldText)) {
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) { evaluate(JsclOperation.numeric, changeEventData.getNewState().getText(), calculatorEventData.getSequenceId());
editorHistoryState.setValuesFromHistory(getEditor(), getDisplay()); }
} break;
case engine_preferences_changed:
@NotNull evaluate(calculatorEventData.getSequenceId());
private CalculatorEditor getEditor() { break;
return CalculatorLocatorImpl.getInstance().getEditor(); }
} }
@NotNull /*
@Override **********************************************************************
public CalculatorHistoryState getCurrentHistoryState() { *
return CalculatorHistoryState.newInstance(getEditor(), getDisplay()); * HISTORY
} *
**********************************************************************
@NotNull */
private CalculatorDisplay getDisplay() {
return CalculatorLocatorImpl.getInstance().getDisplay(); @Override
} public void doHistoryAction(@NotNull HistoryAction historyAction) {
final CalculatorHistory history = CalculatorLocatorImpl.getInstance().getHistory();
public static final class ConversionException extends Exception { if (history.isActionAvailable(historyAction)) {
private ConversionException() { final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState());
} if (newState != null) {
setCurrentHistoryState(newState);
private ConversionException(Throwable throwable) { }
super(throwable); }
} }
}
} @Override
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
editorHistoryState.setValuesFromHistory(getEditor(), getDisplay());
}
@NotNull
@Override
public CalculatorHistoryState getCurrentHistoryState() {
return CalculatorHistoryState.newInstance(getEditor(), getDisplay());
}
/*
**********************************************************************
*
* OTHER
*
**********************************************************************
*/
@NotNull
private CalculatorEditor getEditor() {
return CalculatorLocatorImpl.getInstance().getEditor();
}
@NotNull
private CalculatorDisplay getDisplay() {
return CalculatorLocatorImpl.getInstance().getDisplay();
}
}

View File

@ -1,22 +1,22 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* User: serso * User: serso
* Date: 9/22/12 * Date: 9/22/12
* Time: 7:13 PM * Time: 7:13 PM
*/ */
public final class CalculatorUtils { public final class CalculatorUtils {
static final long FIRST_ID = 0; static final long FIRST_ID = 0;
private CalculatorUtils() { private CalculatorUtils() {
throw new AssertionError(); throw new AssertionError();
} }
@NotNull @NotNull
public static CalculatorEventDataId createFirstEventDataId() { public static CalculatorEventData createFirstEventDataId() {
return CalculatorEventDataIdImpl.newInstance(FIRST_ID, FIRST_ID); return CalculatorEventDataImpl.newInstance(FIRST_ID, FIRST_ID);
} }
} }

View File

@ -0,0 +1,14 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
/**
* User: Solovyev_S
* Date: 24.09.12
* Time: 16:12
*/
public interface ConversionFailure {
@NotNull
Exception getException();
}

View File

@ -0,0 +1,24 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
/**
* User: Solovyev_S
* Date: 24.09.12
* Time: 16:12
*/
public class ConversionFailureImpl implements ConversionFailure {
@NotNull
private Exception exception;
public ConversionFailureImpl(@NotNull Exception exception) {
this.exception = exception;
}
@NotNull
@Override
public Exception getException() {
return this.exception;
}
}

View File

@ -1,216 +1,216 @@
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
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.*; import org.solovyev.android.calculator.*;
import org.solovyev.common.history.HistoryAction; import org.solovyev.common.history.HistoryAction;
import org.solovyev.common.history.HistoryHelper; import org.solovyev.common.history.HistoryHelper;
import org.solovyev.common.history.SimpleHistoryHelper; import org.solovyev.common.history.SimpleHistoryHelper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static org.solovyev.android.calculator.CalculatorEventType.display_state_changed; import static org.solovyev.android.calculator.CalculatorEventType.display_state_changed;
import static org.solovyev.android.calculator.CalculatorEventType.editor_state_changed; import static org.solovyev.android.calculator.CalculatorEventType.editor_state_changed;
import static org.solovyev.android.calculator.CalculatorEventType.manual_calculation_requested; import static org.solovyev.android.calculator.CalculatorEventType.manual_calculation_requested;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 20.09.12 * Date: 20.09.12
* Time: 16:12 * Time: 16:12
*/ */
public class CalculatorHistoryImpl implements CalculatorHistory { public class CalculatorHistoryImpl implements CalculatorHistory {
private final AtomicInteger counter = new AtomicInteger(0); private final AtomicInteger counter = new AtomicInteger(0);
@NotNull @NotNull
private final HistoryHelper<CalculatorHistoryState> history = new SimpleHistoryHelper<CalculatorHistoryState>(); private final HistoryHelper<CalculatorHistoryState> history = new SimpleHistoryHelper<CalculatorHistoryState>();
@NotNull @NotNull
private final List<CalculatorHistoryState> savedHistory = new ArrayList<CalculatorHistoryState>(); private final List<CalculatorHistoryState> savedHistory = new ArrayList<CalculatorHistoryState>();
@NotNull @NotNull
private volatile CalculatorEventDataId lastEventDataId = CalculatorUtils.createFirstEventDataId(); private volatile CalculatorEventData lastEventDataId = CalculatorUtils.createFirstEventDataId();
@Nullable @Nullable
private volatile CalculatorEditorViewState lastEditorViewState; private volatile CalculatorEditorViewState lastEditorViewState;
public CalculatorHistoryImpl(@NotNull Calculator calculator) { public CalculatorHistoryImpl(@NotNull Calculator calculator) {
calculator.addCalculatorEventListener(this); calculator.addCalculatorEventListener(this);
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
synchronized (history) { synchronized (history) {
return this.history.isEmpty(); return this.history.isEmpty();
} }
} }
@Override @Override
public CalculatorHistoryState getLastHistoryState() { public CalculatorHistoryState getLastHistoryState() {
synchronized (history) { synchronized (history) {
return this.history.getLastHistoryState(); return this.history.getLastHistoryState();
} }
} }
@Override @Override
public boolean isUndoAvailable() { public boolean isUndoAvailable() {
synchronized (history) { synchronized (history) {
return history.isUndoAvailable(); return history.isUndoAvailable();
} }
} }
@Override @Override
public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) { public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) {
synchronized (history) { synchronized (history) {
return history.undo(currentState); return history.undo(currentState);
} }
} }
@Override @Override
public boolean isRedoAvailable() { public boolean isRedoAvailable() {
return history.isRedoAvailable(); return history.isRedoAvailable();
} }
@Override @Override
public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) { public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) {
synchronized (history) { synchronized (history) {
return history.redo(currentState); return history.redo(currentState);
} }
} }
@Override @Override
public boolean isActionAvailable(@NotNull HistoryAction historyAction) { public boolean isActionAvailable(@NotNull HistoryAction historyAction) {
synchronized (history) { synchronized (history) {
return history.isActionAvailable(historyAction); return history.isActionAvailable(historyAction);
} }
} }
@Override @Override
public CalculatorHistoryState doAction(@NotNull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) { public CalculatorHistoryState doAction(@NotNull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) {
synchronized (history) { synchronized (history) {
return history.doAction(historyAction, currentState); return history.doAction(historyAction, currentState);
} }
} }
@Override @Override
public void addState(@Nullable CalculatorHistoryState currentState) { public void addState(@Nullable CalculatorHistoryState currentState) {
synchronized (history) { synchronized (history) {
history.addState(currentState); history.addState(currentState);
} }
} }
@NotNull @NotNull
@Override @Override
public List<CalculatorHistoryState> getStates() { public List<CalculatorHistoryState> getStates() {
synchronized (history) { synchronized (history) {
return history.getStates(); return history.getStates();
} }
} }
@Override @Override
public void clear() { public void clear() {
synchronized (history) { synchronized (history) {
this.history.clear(); this.history.clear();
} }
} }
@Override @Override
@NotNull @NotNull
public List<CalculatorHistoryState> getSavedHistory() { public List<CalculatorHistoryState> getSavedHistory() {
return Collections.unmodifiableList(savedHistory); return Collections.unmodifiableList(savedHistory);
} }
@Override @Override
@NotNull @NotNull
public CalculatorHistoryState addSavedState(@NotNull CalculatorHistoryState historyState) { public CalculatorHistoryState addSavedState(@NotNull CalculatorHistoryState historyState) {
if (historyState.isSaved()) { if (historyState.isSaved()) {
return historyState; return historyState;
} else { } else {
final CalculatorHistoryState savedState = historyState.clone(); final CalculatorHistoryState savedState = historyState.clone();
savedState.setId(counter.incrementAndGet()); savedState.setId(counter.incrementAndGet());
savedState.setSaved(true); savedState.setSaved(true);
savedHistory.add(savedState); savedHistory.add(savedState);
return savedState; return savedState;
} }
} }
@Override @Override
public void load() { public void load() {
// todo serso: create saved/loader class // todo serso: create saved/loader class
} }
@Override @Override
public void save() { public void save() {
// todo serso: create saved/loader class // todo serso: create saved/loader class
} }
@Override @Override
public void fromXml(@NotNull String xml) { public void fromXml(@NotNull String xml) {
clearSavedHistory(); clearSavedHistory();
HistoryUtils.fromXml(xml, this.savedHistory); HistoryUtils.fromXml(xml, this.savedHistory);
for (CalculatorHistoryState historyState : savedHistory) { for (CalculatorHistoryState historyState : savedHistory) {
historyState.setSaved(true); historyState.setSaved(true);
historyState.setId(counter.incrementAndGet()); historyState.setId(counter.incrementAndGet());
} }
} }
@Override @Override
public String toXml() { public String toXml() {
return HistoryUtils.toXml(this.savedHistory); return HistoryUtils.toXml(this.savedHistory);
} }
@Override @Override
public void clearSavedHistory() { public void clearSavedHistory() {
this.savedHistory.clear(); this.savedHistory.clear();
} }
@Override @Override
public void removeSavedHistory(@NotNull CalculatorHistoryState historyState) { public void removeSavedHistory(@NotNull CalculatorHistoryState historyState) {
this.savedHistory.remove(historyState); this.savedHistory.remove(historyState);
} }
@Override @Override
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData,
@NotNull CalculatorEventType calculatorEventType, @NotNull CalculatorEventType calculatorEventType,
@Nullable Object data) { @Nullable Object data) {
if (calculatorEventType.isOfType(editor_state_changed, display_state_changed, manual_calculation_requested)) { if (calculatorEventType.isOfType(editor_state_changed, display_state_changed, manual_calculation_requested)) {
if (calculatorEventData.isAfter(this.lastEventDataId)) { if (calculatorEventData.isAfter(this.lastEventDataId)) {
final boolean sameSequence = calculatorEventData.isSameSequence(this.lastEventDataId); final boolean sameSequence = calculatorEventData.isSameSequence(this.lastEventDataId);
if (sameSequence || calculatorEventData.isAfterSequence(this.lastEventDataId)) { if (sameSequence || calculatorEventData.isAfterSequence(this.lastEventDataId)) {
this.lastEventDataId = calculatorEventData; this.lastEventDataId = calculatorEventData;
switch (calculatorEventType) { switch (calculatorEventType) {
case manual_calculation_requested: case manual_calculation_requested:
lastEditorViewState = (CalculatorEditorViewState) data; lastEditorViewState = (CalculatorEditorViewState) data;
break; break;
case editor_state_changed: case editor_state_changed:
final CalculatorEditorChangeEventData editorChangeData = (CalculatorEditorChangeEventData) data; final CalculatorEditorChangeEventData editorChangeData = (CalculatorEditorChangeEventData) data;
lastEditorViewState = editorChangeData.getNewState(); lastEditorViewState = editorChangeData.getNewState();
break; break;
case display_state_changed: case display_state_changed:
if (sameSequence) { if (sameSequence) {
if (lastEditorViewState != null) { if (lastEditorViewState != null) {
final CalculatorEditorViewState editorViewState = lastEditorViewState; final CalculatorEditorViewState editorViewState = lastEditorViewState;
final CalculatorDisplayChangeEventData displayChangeData = (CalculatorDisplayChangeEventData) data; final CalculatorDisplayChangeEventData displayChangeData = (CalculatorDisplayChangeEventData) data;
final CalculatorDisplayViewState displayViewState = displayChangeData.getNewState(); final CalculatorDisplayViewState displayViewState = displayChangeData.getNewState();
addState(CalculatorHistoryState.newInstance(editorViewState, displayViewState)); addState(CalculatorHistoryState.newInstance(editorViewState, displayViewState));
} }
} else { } else {
lastEditorViewState = null; lastEditorViewState = null;
} }
break; break;
} }
} }
} }
} }
} }
} }

View File

@ -0,0 +1,99 @@
package org.solovyev.android.calculator.units;
import jscl.NumeralBase;
import org.jetbrains.annotations.NotNull;
import org.solovyev.math.units.Unit;
import org.solovyev.math.units.UnitConverter;
import org.solovyev.math.units.UnitImpl;
import org.solovyev.math.units.UnitType;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* User: Solovyev_S
* Date: 24.09.12
* Time: 16:05
*/
public enum CalculatorNumeralBase implements UnitType<String> {
bin(NumeralBase.bin),
oct(NumeralBase.oct),
dec(NumeralBase.dec),
hex(NumeralBase.hex);
@NotNull
private final NumeralBase numeralBase;
private CalculatorNumeralBase(@NotNull NumeralBase numeralBase) {
this.numeralBase = numeralBase;
}
@NotNull
public NumeralBase getNumeralBase() {
return numeralBase;
}
@NotNull
private static final CalculatorNumeralBase.Converter converter = new CalculatorNumeralBase.Converter();
@NotNull
public static CalculatorNumeralBase.Converter getConverter() {
return converter;
}
@NotNull
@Override
public Class<String> getUnitValueClass() {
return String.class;
}
@NotNull
public Unit<String> createUnit(@NotNull String value) {
return UnitImpl.newInstance(value, this);
}
public static class Converter implements UnitConverter<String> {
private Converter() {
}
@Override
public boolean isSupported(@NotNull UnitType<?> from, @NotNull UnitType<String> to) {
return CalculatorNumeralBase.class.isAssignableFrom(from.getClass()) && CalculatorNumeralBase.class.isAssignableFrom(to.getClass());
}
@NotNull
@Override
public Unit<String> convert(@NotNull Unit<?> from, @NotNull UnitType<String> toType) {
if (!isSupported(from.getUnitType(), toType)) {
throw new IllegalArgumentException("Types are not supported!");
}
final CalculatorNumeralBase fromTypeAndroid = (CalculatorNumeralBase) from.getUnitType();
final NumeralBase fromNumeralBase = fromTypeAndroid.numeralBase;
final NumeralBase toNumeralBase = ((CalculatorNumeralBase) toType).numeralBase;
final String fromValue = (String) from.getValue();
final BigInteger decBigInteger = fromNumeralBase.toBigInteger(fromValue);
return UnitImpl.newInstance(toNumeralBase.toString(decBigInteger), toType);
}
}
@NotNull
public static CalculatorNumeralBase valueOf(@NotNull NumeralBase nb) {
for (CalculatorNumeralBase calculatorNumeralBase : values()) {
if (calculatorNumeralBase.numeralBase == nb) {
return calculatorNumeralBase;
}
}
throw new IllegalArgumentException(nb + " is not supported numeral base!");
}
}

View File

@ -0,0 +1,15 @@
package org.solovyev.math.units;
/**
* User: Solovyev_S
* Date: 24.09.12
* Time: 16:01
*/
public final class ConversionException extends Exception {
public ConversionException() {
}
public ConversionException(Throwable throwable) {
super(throwable);
}
}

View File

@ -0,0 +1,38 @@
package org.solovyev.math.units;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.text.StringUtils;
/**
* User: Solovyev_S
* Date: 24.09.12
* Time: 16:01
*/
public class ConversionUtils {
@NotNull
public static String doConversion(@NotNull UnitConverter<String> converter,
@Nullable String from,
@NotNull UnitType<String> fromUnitType,
@NotNull UnitType<String> toUnitType) throws ConversionException {
final String result;
if (StringUtils.isEmpty(from)) {
result = "";
} else {
String to = null;
try {
if (converter.isSupported(fromUnitType, toUnitType)) {
to = converter.convert(UnitImpl.newInstance(from, fromUnitType), toUnitType).getValue();
}
} catch (RuntimeException e) {
throw new ConversionException(e);
}
result = to;
}
return result;
}
}

View File

@ -1,131 +1,136 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import jscl.NumeralBase; import jscl.NumeralBase;
import jscl.math.Generic; import jscl.math.Generic;
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.history.CalculatorHistoryState; import org.solovyev.android.calculator.history.CalculatorHistoryState;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.history.HistoryAction; import org.solovyev.common.history.HistoryAction;
import java.util.List; import java.util.List;
/** /**
* User: serso * User: serso
* Date: 9/22/12 * Date: 9/22/12
* Time: 5:42 PM * Time: 5:42 PM
*/ */
public class AndroidCalculator implements Calculator { public class AndroidCalculator implements Calculator {
@NotNull @NotNull
private final Calculator calculator = new CalculatorImpl(); private final Calculator calculator = new CalculatorImpl();
public void init(@NotNull final Activity activity, @NotNull SharedPreferences preferences) { public void init(@NotNull final Activity activity, @NotNull SharedPreferences preferences) {
final AndroidCalculatorEditorView editorView = (AndroidCalculatorEditorView) activity.findViewById(R.id.calculatorEditor); final AndroidCalculatorEditorView editorView = (AndroidCalculatorEditorView) activity.findViewById(R.id.calculatorEditor);
editorView.init(preferences); editorView.init(preferences);
preferences.registerOnSharedPreferenceChangeListener(editorView); preferences.registerOnSharedPreferenceChangeListener(editorView);
CalculatorLocatorImpl.getInstance().getEditor().setView(editorView); CalculatorLocatorImpl.getInstance().getEditor().setView(editorView);
final AndroidCalculatorDisplayView displayView = (AndroidCalculatorDisplayView) activity.findViewById(R.id.calculatorDisplay); final AndroidCalculatorDisplayView displayView = (AndroidCalculatorDisplayView) activity.findViewById(R.id.calculatorDisplay);
displayView.setOnClickListener(new CalculatorDisplayOnClickListener(activity)); displayView.setOnClickListener(new CalculatorDisplayOnClickListener(activity));
CalculatorLocatorImpl.getInstance().getDisplay().setView(displayView); CalculatorLocatorImpl.getInstance().getDisplay().setView(displayView);
} }
/* /*
********************************************************************** **********************************************************************
* *
* DELEGATED TO CALCULATOR * DELEGATED TO CALCULATOR
* *
********************************************************************** **********************************************************************
*/ */
@Override @Override
@NotNull @NotNull
public CalculatorEventDataId evaluate(@NotNull JsclOperation operation, @NotNull String expression) { public CalculatorEventData evaluate(@NotNull JsclOperation operation, @NotNull String expression) {
return calculator.evaluate(operation, expression); return calculator.evaluate(operation, expression);
} }
@Override @Override
@NotNull @NotNull
public CalculatorEventDataId evaluate(@NotNull JsclOperation operation, @NotNull String expression, @NotNull Long sequenceId) { public CalculatorEventData evaluate(@NotNull JsclOperation operation, @NotNull String expression, @NotNull Long sequenceId) {
return calculator.evaluate(operation, expression, sequenceId); return calculator.evaluate(operation, expression, sequenceId);
} }
@Override @Override
@NotNull public boolean isConversionPossible(@NotNull Generic generic, @NotNull NumeralBase from, @NotNull NumeralBase to) {
public CalculatorEventDataId convert(@NotNull Generic generic, @NotNull NumeralBase to) { return calculator.isConversionPossible(generic, from, to);
return calculator.convert(generic, to); }
}
@Override
@Override @NotNull
@NotNull public CalculatorEventData convert(@NotNull Generic generic, @NotNull NumeralBase to) {
public CalculatorEventDataId fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data) { return calculator.convert(generic, to);
return calculator.fireCalculatorEvent(calculatorEventType, data); }
}
@Override
@Override @NotNull
@NotNull public CalculatorEventData fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
public CalculatorEventDataId fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data, @NotNull Long sequenceId) { return calculator.fireCalculatorEvent(calculatorEventType, data);
return calculator.fireCalculatorEvent(calculatorEventType, data, sequenceId); }
}
@Override
@Override @NotNull
public void init() { public CalculatorEventData fireCalculatorEvent(@NotNull CalculatorEventType calculatorEventType, @Nullable Object data, @NotNull Long sequenceId) {
this.calculator.init(); return calculator.fireCalculatorEvent(calculatorEventType, data, sequenceId);
} }
@Override @Override
public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) { public void init() {
calculator.addCalculatorEventListener(calculatorEventListener); this.calculator.init();
} }
@Override @Override
public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) { public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
calculator.removeCalculatorEventListener(calculatorEventListener); calculator.addCalculatorEventListener(calculatorEventListener);
} }
@Override @Override
public void fireCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) { public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) {
calculator.fireCalculatorEvent(calculatorEventData, calculatorEventType, data); calculator.removeCalculatorEventListener(calculatorEventListener);
} }
@Override @Override
public void fireCalculatorEvents(@NotNull List<CalculatorEvent> calculatorEvents) { public void fireCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
calculator.fireCalculatorEvents(calculatorEvents); calculator.fireCalculatorEvent(calculatorEventData, calculatorEventType, data);
} }
@Override @Override
public void doHistoryAction(@NotNull HistoryAction historyAction) { public void fireCalculatorEvents(@NotNull List<CalculatorEvent> calculatorEvents) {
calculator.doHistoryAction(historyAction); calculator.fireCalculatorEvents(calculatorEvents);
} }
@Override @Override
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) { public void doHistoryAction(@NotNull HistoryAction historyAction) {
calculator.setCurrentHistoryState(editorHistoryState); calculator.doHistoryAction(historyAction);
} }
@Override @Override
@NotNull public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
public CalculatorHistoryState getCurrentHistoryState() { calculator.setCurrentHistoryState(editorHistoryState);
return calculator.getCurrentHistoryState(); }
}
@Override
@Override @NotNull
public void evaluate() { public CalculatorHistoryState getCurrentHistoryState() {
calculator.evaluate(); return calculator.getCurrentHistoryState();
} }
@Override @Override
public void evaluate(@NotNull Long sequenceId) { public void evaluate() {
calculator.evaluate(sequenceId); calculator.evaluate();
} }
@Override @Override
public void simplify() { public void evaluate(@NotNull Long sequenceId) {
calculator.simplify(); calculator.evaluate(sequenceId);
} }
} @Override
public void simplify() {
calculator.simplify();
}
}

View File

@ -3,14 +3,10 @@ package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import jscl.NumeralBase; import jscl.NumeralBase;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.math.units.Unit; import org.solovyev.android.calculator.units.CalculatorNumeralBase;
import org.solovyev.math.units.UnitConverter;
import org.solovyev.math.units.UnitImpl;
import org.solovyev.math.units.UnitType;
import org.solovyev.android.view.drag.DirectionDragButton; import org.solovyev.android.view.drag.DirectionDragButton;
import org.solovyev.android.view.drag.DragDirection; import org.solovyev.android.view.drag.DragDirection;
import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -20,9 +16,9 @@ import java.util.List;
* Date: 4/21/12 * Date: 4/21/12
* Time: 8:00 PM * Time: 8:00 PM
*/ */
public enum AndroidNumeralBase implements UnitType<String> { public enum AndroidNumeralBase {
bin(NumeralBase.bin) { bin(CalculatorNumeralBase.bin) {
@NotNull @NotNull
@Override @Override
public List<Integer> getButtonIds() { public List<Integer> getButtonIds() {
@ -30,7 +26,7 @@ public enum AndroidNumeralBase implements UnitType<String> {
} }
}, },
oct(NumeralBase.oct) { oct(CalculatorNumeralBase.oct) {
@NotNull @NotNull
@Override @Override
public List<Integer> getButtonIds() { public List<Integer> getButtonIds() {
@ -40,7 +36,7 @@ public enum AndroidNumeralBase implements UnitType<String> {
} }
}, },
dec(NumeralBase.dec) { dec(CalculatorNumeralBase.dec) {
@NotNull @NotNull
@Override @Override
public List<Integer> getButtonIds() { public List<Integer> getButtonIds() {
@ -50,7 +46,7 @@ public enum AndroidNumeralBase implements UnitType<String> {
} }
}, },
hex(NumeralBase.hex) { hex(CalculatorNumeralBase.hex) {
@NotNull @NotNull
private List<Integer> specialHexButtonIds = Arrays.asList(R.id.oneDigitButton, R.id.twoDigitButton, R.id.threeDigitButton, R.id.fourDigitButton, R.id.fiveDigitButton, R.id.sixDigitButton); private List<Integer> specialHexButtonIds = Arrays.asList(R.id.oneDigitButton, R.id.twoDigitButton, R.id.threeDigitButton, R.id.fourDigitButton, R.id.fiveDigitButton, R.id.sixDigitButton);
@ -72,15 +68,10 @@ public enum AndroidNumeralBase implements UnitType<String> {
}; };
@NotNull @NotNull
private final NumeralBase numeralBase; private final CalculatorNumeralBase calculatorNumeralBase;
private AndroidNumeralBase(@NotNull NumeralBase numeralBase) { private AndroidNumeralBase(@NotNull CalculatorNumeralBase calculatorNumeralBase) {
this.numeralBase = numeralBase; this.calculatorNumeralBase = calculatorNumeralBase;
}
@NotNull
public Unit<String> createUnit(@NotNull String value) {
return UnitImpl.newInstance(value, this);
} }
@NotNull @NotNull
@ -101,54 +92,13 @@ public enum AndroidNumeralBase implements UnitType<String> {
@NotNull @NotNull
public NumeralBase getNumeralBase() { public NumeralBase getNumeralBase() {
return numeralBase; return calculatorNumeralBase.getNumeralBase();
}
@NotNull
@Override
public Class<String> getUnitValueClass() {
return String.class;
}
@NotNull
private static final Converter converter = new Converter();
@NotNull
public static Converter getConverter() {
return converter;
}
public static class Converter implements UnitConverter<String> {
private Converter() {
}
@Override
public boolean isSupported(@NotNull UnitType<?> from, @NotNull UnitType<String> to) {
return AndroidNumeralBase.class.isAssignableFrom(from.getClass()) && AndroidNumeralBase.class.isAssignableFrom(to.getClass());
}
@NotNull
@Override
public Unit<String> convert(@NotNull Unit<?> from, @NotNull UnitType<String> toType) {
if (!isSupported(from.getUnitType(), toType)) {
throw new IllegalArgumentException("Types are not supported!");
}
final AndroidNumeralBase fromTypeAndroid = (AndroidNumeralBase) from.getUnitType();
final NumeralBase fromNumeralBase = fromTypeAndroid.numeralBase;
final NumeralBase toNumeralBase = ((AndroidNumeralBase) toType).numeralBase;
final String fromValue = (String) from.getValue();
final BigInteger decBigInteger = fromNumeralBase.toBigInteger(fromValue);
return UnitImpl.newInstance(toNumeralBase.toString(decBigInteger), (AndroidNumeralBase) toType);
}
} }
@NotNull @NotNull
public static AndroidNumeralBase valueOf(@NotNull NumeralBase nb) { public static AndroidNumeralBase valueOf(@NotNull NumeralBase nb) {
for (AndroidNumeralBase androidNumeralBase : values()) { for (AndroidNumeralBase androidNumeralBase : values()) {
if (androidNumeralBase.numeralBase == nb) { if (androidNumeralBase.calculatorNumeralBase.getNumeralBase() == nb) {
return androidNumeralBase; return androidNumeralBase;
} }
} }

View File

@ -1,57 +1,52 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.content.Context; import android.content.Context;
import jscl.NumeralBase; import jscl.NumeralBase;
import jscl.math.Generic; import jscl.math.Generic;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.menu.AMenuItem; import org.solovyev.android.menu.AMenuItem;
/** /**
* User: serso * User: serso
* Date: 9/21/12 * Date: 9/21/12
* Time: 12:11 AM * Time: 12:11 AM
*/ */
enum ConversionMenuItem implements AMenuItem<CalculatorDisplayViewState> { enum ConversionMenuItem implements AMenuItem<CalculatorDisplayViewState> {
convert_to_bin(NumeralBase.bin), convert_to_bin(NumeralBase.bin),
convert_to_dec(NumeralBase.dec), convert_to_dec(NumeralBase.dec),
convert_to_hex(NumeralBase.hex); convert_to_hex(NumeralBase.hex);
@NotNull @NotNull
private final NumeralBase toNumeralBase; private final NumeralBase toNumeralBase;
ConversionMenuItem(@NotNull NumeralBase toNumeralBase) { ConversionMenuItem(@NotNull NumeralBase toNumeralBase) {
this.toNumeralBase = toNumeralBase; this.toNumeralBase = toNumeralBase;
} }
protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) { protected boolean isItemVisibleFor(@NotNull Generic generic, @NotNull JsclOperation operation) {
boolean result = false; boolean result = false;
if (operation == JsclOperation.numeric) { if (operation == JsclOperation.numeric) {
if (generic.getConstants().isEmpty()) { if (generic.getConstants().isEmpty()) {
convert(generic); // conversion possible => return true
final NumeralBase fromNumeralBase = CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase();
// conversion possible => return true if (fromNumeralBase != toNumeralBase) {
result = true; result = CalculatorLocatorImpl.getInstance().getCalculator().isConversionPossible(generic, fromNumeralBase, this.toNumeralBase);
} }
} }
}
return result;
} return result;
}
@Override
public void onClick(@NotNull CalculatorDisplayViewState data, @NotNull Context context) { @Override
final NumeralBase fromNumeralBase = CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase(); public void onClick(@NotNull CalculatorDisplayViewState data, @NotNull Context context) {
final Generic result = data.getResult();
final Generic lastResult = data.getResult();
if (result != null) {
if (lastResult != null) { CalculatorLocatorImpl.getInstance().getCalculator().convert(result, this.toNumeralBase);
convert(lastResult); }
} }
} }
private void convert(@NotNull Generic generic) {
CalculatorLocatorImpl.getInstance().getCalculator().convert(generic, this.toNumeralBase);
}
}

View File

@ -1,94 +1,95 @@
package org.solovyev.android.calculator.view; package org.solovyev.android.calculator.view;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.view.View; import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
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.*; import org.solovyev.android.calculator.*;
import org.solovyev.math.units.Unit; import org.solovyev.android.calculator.units.CalculatorNumeralBase;
import org.solovyev.math.units.UnitImpl; import org.solovyev.math.units.Unit;
import org.solovyev.common.MutableObject; import org.solovyev.math.units.UnitImpl;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.MutableObject;
import org.solovyev.common.text.StringUtils;
import java.util.Arrays;
import java.util.Arrays;
/**
* User: serso /**
* Date: 4/22/12 * User: serso
* Time: 12:20 AM * Date: 4/22/12
*/ * Time: 12:20 AM
public class NumeralBaseConverterDialog { */
public class NumeralBaseConverterDialog {
@Nullable
private String initialFromValue; @Nullable
private String initialFromValue;
public NumeralBaseConverterDialog(String initialFromValue) {
this.initialFromValue = initialFromValue; public NumeralBaseConverterDialog(String initialFromValue) {
} this.initialFromValue = initialFromValue;
}
public void show(@NotNull Context context) {
final UnitConverterViewBuilder b = new UnitConverterViewBuilder(); public void show(@NotNull Context context) {
b.setFromUnitTypes(Arrays.asList(AndroidNumeralBase.values())); final UnitConverterViewBuilder b = new UnitConverterViewBuilder();
b.setToUnitTypes(Arrays.asList(AndroidNumeralBase.values())); b.setFromUnitTypes(Arrays.asList(CalculatorNumeralBase.values()));
b.setToUnitTypes(Arrays.asList(CalculatorNumeralBase.values()));
if (!StringUtils.isEmpty(initialFromValue)) {
String value = initialFromValue; if (!StringUtils.isEmpty(initialFromValue)) {
try { String value = initialFromValue;
value = ToJsclTextProcessor.getInstance().process(value).getExpression(); try {
b.setFromValue(UnitImpl.newInstance(value, AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase()))); value = ToJsclTextProcessor.getInstance().process(value).getExpression();
} catch (CalculatorParseException e) { b.setFromValue(UnitImpl.newInstance(value, CalculatorNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase())));
b.setFromValue(UnitImpl.newInstance(value, AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase()))); } catch (CalculatorParseException e) {
} b.setFromValue(UnitImpl.newInstance(value, CalculatorNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase())));
} else { }
b.setFromValue(UnitImpl.newInstance("", AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase()))); } else {
} b.setFromValue(UnitImpl.newInstance("", CalculatorNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase())));
}
b.setConverter(AndroidNumeralBase.getConverter());
b.setConverter(CalculatorNumeralBase.getConverter());
final MutableObject<AlertDialog> alertDialogHolder = new MutableObject<AlertDialog>();
b.setOkButtonOnClickListener(new View.OnClickListener() { final MutableObject<AlertDialog> alertDialogHolder = new MutableObject<AlertDialog>();
@Override b.setOkButtonOnClickListener(new View.OnClickListener() {
public void onClick(View v) { @Override
final AlertDialog alertDialog = alertDialogHolder.getObject(); public void onClick(View v) {
if (alertDialog != null) { final AlertDialog alertDialog = alertDialogHolder.getObject();
alertDialog.dismiss(); if (alertDialog != null) {
} alertDialog.dismiss();
} }
}); }
});
b.setCustomButtonData(new UnitConverterViewBuilder.CustomButtonData(context.getString(R.string.c_use_short), new UnitConverterViewBuilder.CustomButtonOnClickListener() {
@Override b.setCustomButtonData(new UnitConverterViewBuilder.CustomButtonData(context.getString(R.string.c_use_short), new UnitConverterViewBuilder.CustomButtonOnClickListener() {
public void onClick(@NotNull Unit<String> fromUnits, @NotNull Unit<String> toUnits) { @Override
String toUnitsValue = toUnits.getValue(); public void onClick(@NotNull Unit<String> fromUnits, @NotNull Unit<String> toUnits) {
String toUnitsValue = toUnits.getValue();
if (!toUnits.getUnitType().equals(AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase()))) {
toUnitsValue = ((AndroidNumeralBase) toUnits.getUnitType()).getNumeralBase().getJsclPrefix() + toUnitsValue; if (!toUnits.getUnitType().equals(AndroidNumeralBase.valueOf(CalculatorLocatorImpl.getInstance().getEngine().getNumeralBase()))) {
} toUnitsValue = ((AndroidNumeralBase) toUnits.getUnitType()).getNumeralBase().getJsclPrefix() + toUnitsValue;
}
CalculatorLocatorImpl.getInstance().getKeyboard().digitButtonPressed(toUnitsValue);
final AlertDialog alertDialog = alertDialogHolder.getObject(); CalculatorLocatorImpl.getInstance().getKeyboard().digitButtonPressed(toUnitsValue);
if (alertDialog != null) { final AlertDialog alertDialog = alertDialogHolder.getObject();
alertDialog.dismiss(); if (alertDialog != null) {
} alertDialog.dismiss();
} }
})); }
}));
final AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
alertBuilder.setView(b.build(context)); final AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
alertBuilder.setTitle(R.string.c_conversion_tool); alertBuilder.setView(b.build(context));
alertBuilder.setTitle(R.string.c_conversion_tool);
final AlertDialog alertDialog = alertBuilder.create();
final AlertDialog alertDialog = alertBuilder.create();
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(alertDialog.getWindow().getAttributes()); final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(alertDialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.FILL_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT; lp.width = WindowManager.LayoutParams.FILL_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
alertDialogHolder.setObject(alertDialog);
alertDialog.show(); alertDialogHolder.setObject(alertDialog);
alertDialog.getWindow().setAttributes(lp); alertDialog.show();
} alertDialog.getWindow().setAttributes(lp);
} }
}

View File

@ -1,224 +1,221 @@
package org.solovyev.android.calculator.view; package org.solovyev.android.calculator.view;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.text.ClipboardManager; import android.text.ClipboardManager;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.*; import android.widget.*;
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.CalculatorImpl; import org.solovyev.android.calculator.CalculatorImpl;
import org.solovyev.math.units.Unit; import org.solovyev.math.units.*;
import org.solovyev.math.units.UnitConverter; import org.solovyev.android.calculator.R;
import org.solovyev.math.units.UnitImpl; import org.solovyev.android.view.ViewBuilder;
import org.solovyev.math.units.UnitType; import org.solovyev.android.view.ViewFromLayoutBuilder;
import org.solovyev.android.calculator.R;
import org.solovyev.android.view.ViewBuilder; import java.util.Collections;
import org.solovyev.android.view.ViewFromLayoutBuilder; import java.util.List;
import java.util.Collections; /**
import java.util.List; * User: serso
* Date: 4/20/12
/** * Time: 4:50 PM
* User: serso */
* Date: 4/20/12 public class UnitConverterViewBuilder implements ViewBuilder<View> {
* Time: 4:50 PM
*/ @NotNull
public class UnitConverterViewBuilder implements ViewBuilder<View> { private List<? extends UnitType<String>> fromUnitTypes = Collections.emptyList();
@NotNull @NotNull
private List<? extends UnitType<String>> fromUnitTypes = Collections.emptyList(); private List<? extends UnitType<String>> toUnitTypes = Collections.emptyList();
@NotNull @Nullable
private List<? extends UnitType<String>> toUnitTypes = Collections.emptyList(); private Unit<String> fromValue;
@Nullable @NotNull
private Unit<String> fromValue; private UnitConverter<String> converter = UnitConverter.Dummy.getInstance();
@NotNull @Nullable
private UnitConverter<String> converter = UnitConverter.Dummy.getInstance(); private View.OnClickListener okButtonOnClickListener;
@Nullable @Nullable
private View.OnClickListener okButtonOnClickListener; private CustomButtonData customButtonData;
@Nullable public void setFromUnitTypes(@NotNull List<? extends UnitType<String>> fromUnitTypes) {
private CustomButtonData customButtonData; this.fromUnitTypes = fromUnitTypes;
}
public void setFromUnitTypes(@NotNull List<? extends UnitType<String>> fromUnitTypes) {
this.fromUnitTypes = fromUnitTypes; public void setToUnitTypes(@NotNull List<? extends UnitType<String>> toUnitTypes) {
} this.toUnitTypes = toUnitTypes;
}
public void setToUnitTypes(@NotNull List<? extends UnitType<String>> toUnitTypes) {
this.toUnitTypes = toUnitTypes; public void setFromValue(@Nullable Unit<String> fromValue) {
} this.fromValue = fromValue;
}
public void setFromValue(@Nullable Unit<String> fromValue) {
this.fromValue = fromValue; public void setConverter(@NotNull UnitConverter<String> converter) {
} this.converter = converter;
}
public void setConverter(@NotNull UnitConverter<String> converter) {
this.converter = converter; public void setOkButtonOnClickListener(@Nullable View.OnClickListener okButtonOnClickListener) {
} this.okButtonOnClickListener = okButtonOnClickListener;
}
public void setOkButtonOnClickListener(@Nullable View.OnClickListener okButtonOnClickListener) {
this.okButtonOnClickListener = okButtonOnClickListener; public void setCustomButtonData(@Nullable CustomButtonData customButtonData) {
} this.customButtonData = customButtonData;
}
public void setCustomButtonData(@Nullable CustomButtonData customButtonData) {
this.customButtonData = customButtonData; @NotNull
} @Override
public View build(@NotNull final Context context) {
@NotNull final View main = ViewFromLayoutBuilder.newInstance(R.layout.unit_converter).build(context);
@Override
public View build(@NotNull final Context context) { final Spinner fromSpinner = (Spinner) main.findViewById(R.id.unit_types_from);
final View main = ViewFromLayoutBuilder.newInstance(R.layout.unit_converter).build(context); final EditText fromEditText = (EditText) main.findViewById(R.id.units_from);
fromEditText.addTextChangedListener(new TextWatcher() {
final Spinner fromSpinner = (Spinner) main.findViewById(R.id.unit_types_from); @Override
final EditText fromEditText = (EditText) main.findViewById(R.id.units_from); public void beforeTextChanged(CharSequence s, int start, int count, int after) {
fromEditText.addTextChangedListener(new TextWatcher() { }
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { @Override
} public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) { @Override
} public void afterTextChanged(Editable s) {
doConversion(main, context, UnitConverterViewBuilder.this.converter);
@Override }
public void afterTextChanged(Editable s) { });
doConversion(main, context, UnitConverterViewBuilder.this.converter);
} fillSpinner(main, context, R.id.unit_types_from, fromUnitTypes);
}); fillSpinner(main, context, R.id.unit_types_to, toUnitTypes);
fillSpinner(main, context, R.id.unit_types_from, fromUnitTypes); if (fromValue != null) {
fillSpinner(main, context, R.id.unit_types_to, toUnitTypes); fromEditText.setText(fromValue.getValue());
if (fromValue != null) { int i = fromUnitTypes.indexOf(fromValue.getUnitType());
fromEditText.setText(fromValue.getValue()); if ( i >= 0 ) {
fromSpinner.setSelection(i);
int i = fromUnitTypes.indexOf(fromValue.getUnitType()); }
if ( i >= 0 ) { }
fromSpinner.setSelection(i);
} final Button copyButton = (Button) main.findViewById(R.id.unit_converter_copy_button);
} copyButton.setOnClickListener(new View.OnClickListener() {
@Override
final Button copyButton = (Button) main.findViewById(R.id.unit_converter_copy_button); public void onClick(View v) {
copyButton.setOnClickListener(new View.OnClickListener() { final EditText toEditText = (EditText) main.findViewById(R.id.units_to);
@Override
public void onClick(View v) { final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
final EditText toEditText = (EditText) main.findViewById(R.id.units_to); clipboard.setText(toEditText.getText().toString());
Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show();
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); }
clipboard.setText(toEditText.getText().toString()); });
Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show();
} final Button okButton = (Button) main.findViewById(R.id.unit_converter_ok_button);
}); if ( okButtonOnClickListener == null ) {
((ViewGroup) okButton.getParent()).removeView(okButton);
final Button okButton = (Button) main.findViewById(R.id.unit_converter_ok_button); } else {
if ( okButtonOnClickListener == null ) { okButton.setOnClickListener(this.okButtonOnClickListener);
((ViewGroup) okButton.getParent()).removeView(okButton); }
} else {
okButton.setOnClickListener(this.okButtonOnClickListener); final Button customButton = (Button) main.findViewById(R.id.unit_converter_custom_button);
} if ( customButtonData == null ) {
((ViewGroup) customButton.getParent()).removeView(customButton);
final Button customButton = (Button) main.findViewById(R.id.unit_converter_custom_button); } else {
if ( customButtonData == null ) { customButton.setText(customButtonData.text);
((ViewGroup) customButton.getParent()).removeView(customButton); customButton.setOnClickListener(new View.OnClickListener() {
} else { @Override
customButton.setText(customButtonData.text); public void onClick(View v) {
customButton.setOnClickListener(new View.OnClickListener() { customButtonData.clickListener.onClick(getFromUnit(main), getToUnit(main));
@Override }
public void onClick(View v) { });
customButtonData.clickListener.onClick(getFromUnit(main), getToUnit(main)); }
}
});
}
return main;
}
return main; private void fillSpinner(@NotNull final View main,
} @NotNull final Context context,
final int spinnerId,
private void fillSpinner(@NotNull final View main, @NotNull List<? extends UnitType<String>> unitTypes) {
@NotNull final Context context, final Spinner spinner = (Spinner) main.findViewById(spinnerId);
final int spinnerId,
@NotNull List<? extends UnitType<String>> unitTypes) { final ArrayAdapter<UnitType<String>> adapter = new ArrayAdapter<UnitType<String>>(context, android.R.layout.simple_spinner_item);
final Spinner spinner = (Spinner) main.findViewById(spinnerId); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
for (UnitType<String> fromUnitType : unitTypes) {
final ArrayAdapter<UnitType<String>> adapter = new ArrayAdapter<UnitType<String>>(context, android.R.layout.simple_spinner_item); adapter.add(fromUnitType);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); }
for (UnitType<String> fromUnitType : unitTypes) { spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
adapter.add(fromUnitType); @Override
} public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { doConversion(main, context, UnitConverterViewBuilder.this.converter);
@Override }
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
doConversion(main, context, UnitConverterViewBuilder.this.converter); @Override
} public void onNothingSelected(AdapterView<?> parent) {
}
@Override });
public void onNothingSelected(AdapterView<?> parent) { spinner.setAdapter(adapter);
} }
});
spinner.setAdapter(adapter); private static void doConversion(@NotNull View main, @NotNull Context context, @NotNull UnitConverter<String> converter) {
} final EditText fromEditText = (EditText) main.findViewById(R.id.units_from);
private static void doConversion(@NotNull View main, @NotNull Context context, @NotNull UnitConverter<String> converter) { final EditText toEditText = (EditText) main.findViewById(R.id.units_to);
final EditText fromEditText = (EditText) main.findViewById(R.id.units_from);
final String from = fromEditText.getText().toString();
final EditText toEditText = (EditText) main.findViewById(R.id.units_to); try {
toEditText.setText(ConversionUtils.doConversion(converter, from, getFromUnitType(main), getToUnitType(main)));
final String from = fromEditText.getText().toString(); } catch (ConversionException e) {
try { toEditText.setText(context.getString(R.string.c_error));
toEditText.setText(CalculatorImpl.doConversion(converter, from, getFromUnitType(main), getToUnitType(main))); }
} catch (CalculatorImpl.ConversionException e) { }
toEditText.setText(context.getString(R.string.c_error));
} @NotNull
} private static Unit<String> getToUnit(@NotNull View main) {
final EditText toUnits = (EditText) main.findViewById(R.id.units_to);
@NotNull return UnitImpl.newInstance(toUnits.getText().toString(), getToUnitType(main));
private static Unit<String> getToUnit(@NotNull View main) { }
final EditText toUnits = (EditText) main.findViewById(R.id.units_to);
return UnitImpl.newInstance(toUnits.getText().toString(), getToUnitType(main)); @NotNull
} private static UnitType<String> getToUnitType(@NotNull View main) {
final Spinner toSpinner = (Spinner) main.findViewById(R.id.unit_types_to);
@NotNull return (UnitType<String>) toSpinner.getSelectedItem();
private static UnitType<String> getToUnitType(@NotNull View main) { }
final Spinner toSpinner = (Spinner) main.findViewById(R.id.unit_types_to);
return (UnitType<String>) toSpinner.getSelectedItem(); @NotNull
} private static Unit<String> getFromUnit(@NotNull View main) {
final EditText fromUnits = (EditText) main.findViewById(R.id.units_from);
@NotNull return UnitImpl.newInstance(fromUnits.getText().toString(), getFromUnitType(main));
private static Unit<String> getFromUnit(@NotNull View main) { }
final EditText fromUnits = (EditText) main.findViewById(R.id.units_from);
return UnitImpl.newInstance(fromUnits.getText().toString(), getFromUnitType(main)); @NotNull
} private static UnitType<String> getFromUnitType(@NotNull View main) {
final Spinner fromSpinner = (Spinner) main.findViewById(R.id.unit_types_from);
@NotNull return (UnitType<String>) fromSpinner.getSelectedItem();
private static UnitType<String> getFromUnitType(@NotNull View main) { }
final Spinner fromSpinner = (Spinner) main.findViewById(R.id.unit_types_from);
return (UnitType<String>) fromSpinner.getSelectedItem(); public static class CustomButtonData {
}
@NotNull
public static class CustomButtonData { private String text;
@NotNull @NotNull
private String text; private CustomButtonOnClickListener clickListener;
@NotNull
private CustomButtonOnClickListener clickListener; public CustomButtonData(@NotNull String text, @NotNull CustomButtonOnClickListener clickListener) {
this.text = text;
this.clickListener = clickListener;
public CustomButtonData(@NotNull String text, @NotNull CustomButtonOnClickListener clickListener) { }
this.text = text; }
this.clickListener = clickListener;
} public static interface CustomButtonOnClickListener {
} void onClick(@NotNull Unit<String> fromUnits, @NotNull Unit<String> toUnits);
}
public static interface CustomButtonOnClickListener { }
void onClick(@NotNull Unit<String> fromUnits, @NotNull Unit<String> toUnits);
}
}

View File

@ -3,7 +3,7 @@ package org.solovyev.android;
import junit.framework.Assert; import junit.framework.Assert;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.junit.Test; import org.junit.Test;
import org.solovyev.android.calculator.AndroidNumeralBase; import org.solovyev.android.calculator.units.CalculatorNumeralBase;
import org.solovyev.math.units.Unit; import org.solovyev.math.units.Unit;
import org.solovyev.math.units.UnitConverter; import org.solovyev.math.units.UnitConverter;
@ -18,32 +18,32 @@ import java.util.Random;
public class AndroidNumeralBaseTest { public class AndroidNumeralBaseTest {
@NotNull @NotNull
private final UnitConverter c = AndroidNumeralBase.getConverter(); private final UnitConverter c = CalculatorNumeralBase.getConverter();
@Test @Test
public void testIsSupported() throws Exception { public void testIsSupported() throws Exception {
Assert.assertTrue(c.isSupported(AndroidNumeralBase.bin, AndroidNumeralBase.dec)); Assert.assertTrue(c.isSupported(CalculatorNumeralBase.bin, CalculatorNumeralBase.dec));
} }
@Test @Test
public void testConvertFromDec() throws Exception { public void testConvertFromDec() throws Exception {
Assert.assertEquals("101", c.convert(AndroidNumeralBase.dec.createUnit("5"), AndroidNumeralBase.bin).getValue()); Assert.assertEquals("101", c.convert(CalculatorNumeralBase.dec.createUnit("5"), CalculatorNumeralBase.bin).getValue());
Assert.assertEquals("1", c.convert(AndroidNumeralBase.dec.createUnit("1"), AndroidNumeralBase.bin).getValue()); Assert.assertEquals("1", c.convert(CalculatorNumeralBase.dec.createUnit("1"), CalculatorNumeralBase.bin).getValue());
Assert.assertEquals("0", c.convert(AndroidNumeralBase.dec.createUnit("0"), AndroidNumeralBase.bin).getValue()); Assert.assertEquals("0", c.convert(CalculatorNumeralBase.dec.createUnit("0"), CalculatorNumeralBase.bin).getValue());
Assert.assertEquals("1111100111", c.convert(AndroidNumeralBase.dec.createUnit("999"), AndroidNumeralBase.bin).getValue()); Assert.assertEquals("1111100111", c.convert(CalculatorNumeralBase.dec.createUnit("999"), CalculatorNumeralBase.bin).getValue());
Assert.assertEquals("A23", c.convert(AndroidNumeralBase.dec.createUnit("2595"), AndroidNumeralBase.hex).getValue()); Assert.assertEquals("A23", c.convert(CalculatorNumeralBase.dec.createUnit("2595"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("AEE", c.convert(AndroidNumeralBase.dec.createUnit("2798"), AndroidNumeralBase.hex).getValue()); Assert.assertEquals("AEE", c.convert(CalculatorNumeralBase.dec.createUnit("2798"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("15", c.convert(AndroidNumeralBase.dec.createUnit("21"), AndroidNumeralBase.hex).getValue()); Assert.assertEquals("15", c.convert(CalculatorNumeralBase.dec.createUnit("21"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("0", c.convert(AndroidNumeralBase.dec.createUnit("0"), AndroidNumeralBase.hex).getValue()); Assert.assertEquals("0", c.convert(CalculatorNumeralBase.dec.createUnit("0"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("3E7", c.convert(AndroidNumeralBase.dec.createUnit("999"), AndroidNumeralBase.hex).getValue()); Assert.assertEquals("3E7", c.convert(CalculatorNumeralBase.dec.createUnit("999"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("76", c.convert(AndroidNumeralBase.dec.createUnit("62"), AndroidNumeralBase.oct).getValue()); Assert.assertEquals("76", c.convert(CalculatorNumeralBase.dec.createUnit("62"), CalculatorNumeralBase.oct).getValue());
Assert.assertEquals("12", c.convert(AndroidNumeralBase.dec.createUnit("10"), AndroidNumeralBase.oct).getValue()); Assert.assertEquals("12", c.convert(CalculatorNumeralBase.dec.createUnit("10"), CalculatorNumeralBase.oct).getValue());
Assert.assertEquals("15", c.convert(AndroidNumeralBase.dec.createUnit("13"), AndroidNumeralBase.oct).getValue()); Assert.assertEquals("15", c.convert(CalculatorNumeralBase.dec.createUnit("13"), CalculatorNumeralBase.oct).getValue());
Assert.assertEquals("0", c.convert(AndroidNumeralBase.dec.createUnit("0"), AndroidNumeralBase.oct).getValue()); Assert.assertEquals("0", c.convert(CalculatorNumeralBase.dec.createUnit("0"), CalculatorNumeralBase.oct).getValue());
Assert.assertEquals("10445", c.convert(AndroidNumeralBase.dec.createUnit("4389"), AndroidNumeralBase.oct).getValue()); Assert.assertEquals("10445", c.convert(CalculatorNumeralBase.dec.createUnit("4389"), CalculatorNumeralBase.oct).getValue());
} }
@Test @Test
@ -51,20 +51,20 @@ public class AndroidNumeralBaseTest {
final Random random = new Random(new Date().getTime()); final Random random = new Random(new Date().getTime());
for (int i = 0; i < 100000; i++) { for (int i = 0; i < 100000; i++) {
final String value = String.valueOf(random.nextInt()); final String value = String.valueOf(random.nextInt());
Assert.assertEquals(value, convertChain(value, AndroidNumeralBase.dec, AndroidNumeralBase.oct, AndroidNumeralBase.oct, AndroidNumeralBase.bin, AndroidNumeralBase.dec)); Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.oct, CalculatorNumeralBase.oct, CalculatorNumeralBase.bin, CalculatorNumeralBase.dec));
Assert.assertEquals(value, convertChain(value, AndroidNumeralBase.dec, AndroidNumeralBase.bin, AndroidNumeralBase.hex, AndroidNumeralBase.dec, AndroidNumeralBase.dec)); Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.bin, CalculatorNumeralBase.hex, CalculatorNumeralBase.dec, CalculatorNumeralBase.dec));
Assert.assertEquals(value, convertChain(value, AndroidNumeralBase.dec, AndroidNumeralBase.dec, AndroidNumeralBase.hex, AndroidNumeralBase.oct, AndroidNumeralBase.dec)); Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.dec, CalculatorNumeralBase.hex, CalculatorNumeralBase.oct, CalculatorNumeralBase.dec));
Assert.assertEquals(value, convertChain(value, AndroidNumeralBase.dec, AndroidNumeralBase.hex, AndroidNumeralBase.bin, AndroidNumeralBase.oct, AndroidNumeralBase.dec)); Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.hex, CalculatorNumeralBase.bin, CalculatorNumeralBase.oct, CalculatorNumeralBase.dec));
} }
} }
@NotNull @NotNull
private String convertChain(@NotNull String value, @NotNull AndroidNumeralBase baseAndroid, @NotNull AndroidNumeralBase... typeAndroids) { private String convertChain(@NotNull String value, @NotNull CalculatorNumeralBase baseAndroid, @NotNull CalculatorNumeralBase... typeAndroids) {
Unit<String> unit = baseAndroid.createUnit(value); Unit<String> unit = baseAndroid.createUnit(value);
for (AndroidNumeralBase typeAndroid : typeAndroids) { for (CalculatorNumeralBase typeAndroid : typeAndroids) {
unit = AndroidNumeralBase.getConverter().convert(unit, typeAndroid); unit = CalculatorNumeralBase.getConverter().convert(unit, typeAndroid);
} }
return unit.getValue(); return unit.getValue();