Error messages added

This commit is contained in:
Sergey Solovyev 2011-11-25 14:41:09 +04:00
parent 5576b7a6db
commit fdfa3c16b7
13 changed files with 331 additions and 74 deletions

View File

@ -269,5 +269,26 @@ Check the \'Round result\' preference in application settings - it should be tur
</string> </string>
<string name="msg_msg_1">Arithmetic error occurred: {0}</string>
<string name="msg_msg_2">Too complex expression</string>
<string name="msg_msg_3">Too long execution time - check the expression</string>
<string name="msg_msg_4">Evaluation was cancelled</string>
<string name="msg_msg_5">No parameters are specified for function: {0}</string>
<string name="msg_msg_6">Infinite loop is detected in expression</string>
<string name="msg_jscl_msg_1">Premature end of processing</string>
<string name="msg_jscl_msg_2">There is no operator with name: {0}</string>
<string name="msg_jscl_msg_3">Operator name is not valid: {0}</string>
<string name="msg_jscl_msg_4">Postfix function with name {0} doesn\'\'t exist</string>
<string name="msg_jscl_msg_5">Constant name must start with character</string>
<string name="msg_jscl_msg_6">Cannot be implicit function - usual function or operator with same name is defined: {0}</string>
<string name="msg_jscl_msg_7">Digit is expected</string>
<string name="msg_jscl_msg_8">Invalid number: {0}</string>
<string name="msg_jscl_msg_9">First letter of number must be digit</string>
<string name="msg_jscl_msg_10">Expected characters are {0} or {1}</string>
<string name="msg_jscl_msg_11">Expected characters are {0}</string>
<string name="msg_jscl_msg_12">Expected character is {0}</string>
<string name="msg_jscl_msg_13">Function name is not valid: {0}</string>
<string name="msg_jscl_msg_14">Expected number of parameters differs from actual {0}</string>
</resources> </resources>

View File

@ -22,13 +22,14 @@ import android.view.*;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import jscl.AngleUnits; import jscl.AngleUnit;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.CalculatorEngine; import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.msg.AndroidMessageRegistry; import org.solovyev.android.msg.AndroidMessageRegistry;
import org.solovyev.android.view.FontSizeAdjuster; import org.solovyev.android.view.FontSizeAdjuster;
import org.solovyev.android.view.prefs.ResourceCache;
import org.solovyev.android.view.widgets.*; import org.solovyev.android.view.widgets.*;
import org.solovyev.common.BooleanMapper; import org.solovyev.common.BooleanMapper;
import org.solovyev.common.utils.Announcer; import org.solovyev.common.utils.Announcer;
@ -38,7 +39,10 @@ import org.solovyev.common.utils.history.HistoryAction;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class CalculatorActivity extends Activity implements FontSizeAdjuster, SharedPreferences.OnSharedPreferenceChangeListener { public class CalculatorActivity extends Activity implements FontSizeAdjuster, SharedPreferences.OnSharedPreferenceChangeListener {
@ -58,12 +62,6 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
@NotNull @NotNull
private String layoutName; private String layoutName;
// ids of drag buttons in R.class
private List<Integer> dragButtonIds = null;
// ids of buttons in R.class
private List<Integer> buttonIds = null;
@Nullable @Nullable
private Vibrator vibrator; private Vibrator vibrator;
@ -82,6 +80,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setLayout(preferences); setLayout(preferences);
ResourceCache.instance.initCaptions(R.string.class, this);
firstTimeInit(preferences); firstTimeInit(preferences);
vibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE); vibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
@ -150,7 +149,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
if ( directionText != null ) { if ( directionText != null ) {
try { try {
final AngleUnits angleUnits = AngleUnits.valueOf(directionText); final AngleUnit angleUnits = AngleUnit.valueOf(directionText);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CalculatorActivity.this); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CalculatorActivity.this);
final SharedPreferences.Editor editor = preferences.edit(); final SharedPreferences.Editor editor = preferences.edit();
@ -214,7 +213,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
private synchronized void setOnDragListeners(@NotNull SimpleOnDragListener.Preferences dragPreferences, @NotNull SharedPreferences preferences) { private synchronized void setOnDragListeners(@NotNull SimpleOnDragListener.Preferences dragPreferences, @NotNull SharedPreferences preferences) {
final OnDragListener onDragListener = new OnDragListenerVibrator(newOnDragListener(new DigitButtonDragProcessor(calculatorModel), dragPreferences), vibrator, preferences); final OnDragListener onDragListener = new OnDragListenerVibrator(newOnDragListener(new DigitButtonDragProcessor(calculatorModel), dragPreferences), vibrator, preferences);
for (Integer dragButtonId : dragButtonIds) { for (Integer dragButtonId : ResourceCache.instance.getDragButtonIds()) {
((DragButton) findViewById(dragButtonId)).setOnDragListener(onDragListener); ((DragButton) findViewById(dragButtonId)).setOnDragListener(onDragListener);
} }
} }
@ -288,26 +287,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
private synchronized void firstTimeInit(@NotNull SharedPreferences preferences) { private synchronized void firstTimeInit(@NotNull SharedPreferences preferences) {
if (!initialized) { if (!initialized) {
dragButtonIds = new ArrayList<Integer>(); ResourceCache.instance.init(R.id.class, this);
buttonIds = new ArrayList<Integer>();
for (Field field : R.id.class.getDeclaredFields()) {
int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
try {
int viewId = field.getInt(R.id.class);
final View view = findViewById(viewId);
if (view instanceof DragButton) {
dragButtonIds.add(viewId);
}
if (view instanceof Button) {
buttonIds.add(viewId);
}
} catch (IllegalAccessException e) {
Log.e(CalculatorActivity.class.getName(), e.getMessage());
}
}
}
CalculatorEngine.instance.init(this, preferences); CalculatorEngine.instance.init(this, preferences);
initialized = true; initialized = true;

View File

@ -11,6 +11,7 @@ import android.text.Html;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.model.ParseException; import org.solovyev.android.calculator.model.ParseException;
import org.solovyev.android.calculator.model.TextProcessor; import org.solovyev.android.calculator.model.TextProcessor;
@ -25,6 +26,9 @@ public class CalculatorDisplay extends AutoResizeTextView {
private boolean valid = true; private boolean valid = true;
@Nullable
private String errorMessage;
@NotNull @NotNull
private JsclOperation jsclOperation = JsclOperation.numeric; private JsclOperation jsclOperation = JsclOperation.numeric;
@ -49,6 +53,18 @@ public class CalculatorDisplay extends AutoResizeTextView {
public void setValid(boolean valid) { public void setValid(boolean valid) {
this.valid = valid; this.valid = valid;
if (valid) {
errorMessage = null;
}
}
@Nullable
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(@Nullable String errorMessage) {
this.errorMessage = errorMessage;
} }
public void setJsclOperation(@NotNull JsclOperation jsclOperation) { public void setJsclOperation(@NotNull JsclOperation jsclOperation) {

View File

@ -6,6 +6,7 @@
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.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
/** /**
@ -17,6 +18,9 @@ public class CalculatorDisplayHistoryState {
private boolean valid = true; private boolean valid = true;
@Nullable
private String errorMessage = null;
@NotNull @NotNull
private EditorHistoryState editorHistoryState; private EditorHistoryState editorHistoryState;
@ -33,6 +37,7 @@ public class CalculatorDisplayHistoryState {
result.editorHistoryState = EditorHistoryState.newInstance(display); result.editorHistoryState = EditorHistoryState.newInstance(display);
result.valid = display.isValid(); result.valid = display.isValid();
result.jsclOperation = display.getJsclOperation(); result.jsclOperation = display.getJsclOperation();
result.errorMessage = display.getErrorMessage();
return result; return result;
} }
@ -51,6 +56,11 @@ public class CalculatorDisplayHistoryState {
return jsclOperation; return jsclOperation;
} }
@Nullable
public String getErrorMessage() {
return errorMessage;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
@ -60,6 +70,7 @@ public class CalculatorDisplayHistoryState {
if (valid != that.valid) return false; if (valid != that.valid) return false;
if (!editorHistoryState.equals(that.editorHistoryState)) return false; if (!editorHistoryState.equals(that.editorHistoryState)) return false;
if (errorMessage != null ? !errorMessage.equals(that.errorMessage) : that.errorMessage != null) return false;
if (jsclOperation != that.jsclOperation) return false; if (jsclOperation != that.jsclOperation) return false;
return true; return true;
@ -68,6 +79,7 @@ public class CalculatorDisplayHistoryState {
@Override @Override
public int hashCode() { public int hashCode() {
int result = (valid ? 1 : 0); int result = (valid ? 1 : 0);
result = 31 * result + (errorMessage != null ? errorMessage.hashCode() : 0);
result = 31 * result + editorHistoryState.hashCode(); result = 31 * result + editorHistoryState.hashCode();
result = 31 * result + jsclOperation.hashCode(); result = 31 * result + jsclOperation.hashCode();
return result; return result;
@ -77,8 +89,9 @@ public class CalculatorDisplayHistoryState {
public String toString() { public String toString() {
return "CalculatorDisplayHistoryState{" + return "CalculatorDisplayHistoryState{" +
"valid=" + valid + "valid=" + valid +
"jsclOperation=" + jsclOperation + ", errorMessage='" + errorMessage + '\'' +
", editorHistoryState=" + editorHistoryState + ", editorHistoryState=" + editorHistoryState +
", jsclOperation=" + jsclOperation +
'}'; '}';
} }
} }

View File

@ -6,6 +6,7 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Handler; import android.os.Handler;
@ -63,7 +64,17 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
this.display.setOnClickListener(new View.OnClickListener() { this.display.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
copyResult(activity); if (v instanceof CalculatorDisplay) {
final CalculatorDisplay cd = (CalculatorDisplay)v;
if (cd.isValid()) {
copyResult(activity, cd);
} else {
final String errorMessage = cd.getErrorMessage();
if ( errorMessage != null ) {
showEvaluationError(activity, errorMessage);
}
}
}
} }
}); });
@ -79,9 +90,23 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
return this; return this;
} }
private static void showEvaluationError(@NotNull Activity activity, @NotNull final String errorMessage) {
final TextView errorMessageTextView = new TextView(activity);
errorMessageTextView.setText(errorMessage);
final AlertDialog.Builder builder = new AlertDialog.Builder(activity)
.setPositiveButton(R.string.c_cancel, null)
.setView(errorMessageTextView);
builder.create().show();
}
public void copyResult(@NotNull Context context) { public void copyResult(@NotNull Context context) {
copyResult(context, display);
}
private void copyResult(@NotNull Context context, @NotNull final CalculatorDisplay display) {
if (display.isValid()) { if (display.isValid()) {
final CharSequence text = display.getText(); final CharSequence text = this.display.getText();
if (!StringUtils.isEmpty(text)) { if (!StringUtils.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text.toString()); clipboard.setText(text.toString());
@ -229,11 +254,12 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
private void handleEvaluationException(@NotNull String expression, private void handleEvaluationException(@NotNull String expression,
@NotNull CalculatorDisplay localDisplay, @NotNull CalculatorDisplay localDisplay,
@NotNull JsclOperation operation, @NotNull JsclOperation operation,
@NotNull Exception e) { @NotNull ParseException e) {
Log.d(CalculatorModel.class.getName(), "Evaluation failed for : " + expression + ". Error message: " + e.getMessage()); Log.d(CalculatorModel.class.getName(), "Evaluation failed for : " + expression + ". Error message: " + e.getMessage());
localDisplay.setText(R.string.c_syntax_error); localDisplay.setText(R.string.c_syntax_error);
localDisplay.setJsclOperation(operation); localDisplay.setJsclOperation(operation);
localDisplay.setValid(false); localDisplay.setValid(false);
localDisplay.setErrorMessage(e.getLocalizedMessage());
} }
public void clear() { public void clear() {
@ -327,6 +353,7 @@ public enum CalculatorModel implements CursorControl, HistoryControl<CalculatorH
private void setValuesFromHistory(@NotNull CalculatorDisplay display, CalculatorDisplayHistoryState editorHistoryState) { private void setValuesFromHistory(@NotNull CalculatorDisplay display, CalculatorDisplayHistoryState editorHistoryState) {
setValuesFromHistory(display, editorHistoryState.getEditorHistoryState()); setValuesFromHistory(display, editorHistoryState.getEditorHistoryState());
display.setValid(editorHistoryState.isValid()); display.setValid(editorHistoryState.isValid());
display.setErrorMessage(editorHistoryState.getErrorMessage());
display.setJsclOperation(editorHistoryState.getJsclOperation()); display.setJsclOperation(editorHistoryState.getJsclOperation());
} }

View File

@ -6,6 +6,7 @@
package org.solovyev.android.calculator.jscl; package org.solovyev.android.calculator.jscl;
import jscl.text.Messages;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.math.MathType;
@ -38,7 +39,7 @@ class FromJsclNumericTextProcessor implements TextProcessor<String> {
result = createResultForComplexNumber(result.replace(MathType.IMAGINARY_NUMBER_JSCL, MathType.IMAGINARY_NUMBER)); result = createResultForComplexNumber(result.replace(MathType.IMAGINARY_NUMBER_JSCL, MathType.IMAGINARY_NUMBER));
} catch (NumberFormatException e1) { } catch (NumberFormatException e1) {
// throw original one // throw original one
throw new ParseException(e); throw new ParseException(new jscl.text.ParseException(Messages.msg_8, 0, result, result));
} }
} }

View File

@ -7,7 +7,7 @@ package org.solovyev.android.calculator.model;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import jscl.AngleUnits; import jscl.AngleUnit;
import jscl.JsclMathEngine; import jscl.JsclMathEngine;
import jscl.MathEngine; import jscl.MathEngine;
import jscl.math.function.Function; import jscl.math.function.Function;
@ -191,13 +191,13 @@ public enum CalculatorEngine {
calculationResult.setObject(finalOperation.evaluate(jsclExpression)); calculationResult.setObject(finalOperation.evaluate(jsclExpression));
} catch (ArithmeticException e) { } catch (ArithmeticException e) {
//System.out.println(e.getMessage()); //System.out.println(e.getMessage());
exception.setObject(new ParseException(e.getMessage(), e)); exception.setObject(new ParseException(Messages.msg_1, jsclExpression, e.getMessage()));
} catch (StackOverflowError e) { } catch (StackOverflowError e) {
//System.out.println(StringUtils.fromStackTrace(e.getStackTrace())); //System.out.println(StringUtils.fromStackTrace(e.getStackTrace()));
exception.setObject(new ParseException(e.getMessage(), e)); exception.setObject(new ParseException(Messages.msg_2, jsclExpression));
} catch (jscl.text.ParseException e) { } catch (jscl.text.ParseException e) {
//System.out.println(e.getMessage()); //System.out.println(e.getMessage());
exception.setObject(new ParseException(e.getMessage(), e)); exception.setObject(new ParseException(e));
} catch (ParseInterruptedException e) { } catch (ParseInterruptedException e) {
//System.out.println(e.getMessage()); //System.out.println(e.getMessage());
// do nothing - we ourselves interrupt the calculations // do nothing - we ourselves interrupt the calculations
@ -232,11 +232,11 @@ public enum CalculatorEngine {
} }
if (calculationResultLocal == null) { if (calculationResultLocal == null) {
throw new ParseException("Too long calculation for: " + jsclExpression); throw new ParseException(Messages.msg_3, jsclExpression);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new ParseException(e); throw new ParseException(Messages.msg_4, jsclExpression);
} }
result = String.valueOf(calculationResult.getObject()).trim(); result = String.valueOf(calculationResult.getObject()).trim();
@ -274,7 +274,7 @@ public enum CalculatorEngine {
//noinspection ConstantConditions //noinspection ConstantConditions
this.setPrecision(integerNumberMapper.parseValue(preferences.getString(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT))); this.setPrecision(integerNumberMapper.parseValue(preferences.getString(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT)));
this.setRoundResult(preferences.getBoolean(ROUND_RESULT_P_KEY, ROUND_RESULT_DEFAULT)); this.setRoundResult(preferences.getBoolean(ROUND_RESULT_P_KEY, ROUND_RESULT_DEFAULT));
this.setDefaultAngleUnits(AngleUnits.valueOf(preferences.getString(ANGLE_UNITS_P_KEY, ANGLE_UNITS_DEFAULT))); this.setDefaultAngleUnits(AngleUnit.valueOf(preferences.getString(ANGLE_UNITS_P_KEY, ANGLE_UNITS_DEFAULT)));
final String groupingSeparator = preferences.getString(GROUPING_SEPARATOR_P_KEY, GROUPING_SEPARATOR_DEFAULT); final String groupingSeparator = preferences.getString(GROUPING_SEPARATOR_P_KEY, GROUPING_SEPARATOR_DEFAULT);
if (StringUtils.isEmpty(groupingSeparator)) { if (StringUtils.isEmpty(groupingSeparator)) {
@ -326,8 +326,8 @@ public enum CalculatorEngine {
this.timeout = timeout; this.timeout = timeout;
} }
public void setDefaultAngleUnits(@NotNull AngleUnits angleUnits) { public void setDefaultAngleUnits(@NotNull AngleUnit angleUnits) {
getEngine().setDefaultAngleUnits(angleUnits); getEngine().setDefaultAngleUnit(angleUnits);
} }
// for tests only // for tests only

View File

@ -0,0 +1,34 @@
package org.solovyev.android.calculator.model;
/**
* User: serso
* Date: 11/25/11
* Time: 1:40 PM
*/
public final class Messages {
// not intended for instantiation
private Messages() {
throw new AssertionError();
}
/** Arithmetic error occurred: {0} */
public static final String msg_1 = "msg_1";
/** Too complex expression */
public static final String msg_2 = "msg_2";
/** Too long execution time - check the expression */
public static final String msg_3 = "msg_3";
/** Evaluation was cancelled */
public static final String msg_4 = "msg_4";
/** No parameters are specified for function: {0} */
public static final String msg_5 = "msg_5";
/** Infinite loop is detected in expression */
public static final String msg_6 = "msg_6";
}

View File

@ -6,27 +6,94 @@
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import android.content.Context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.view.prefs.ResourceCache;
import org.solovyev.common.exceptions.SersoException; import org.solovyev.common.exceptions.SersoException;
import org.solovyev.common.utils.CollectionsUtils;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/** /**
* User: serso * User: serso
* Date: 10/6/11 * Date: 10/6/11
* Time: 9:25 PM * Time: 9:25 PM
*/ */
public class ParseException extends SersoException { public class ParseException extends SersoException {
public ParseException() { @NotNull
private final String messageId;
@NotNull
private final List<Object> parameters;
@NotNull
private final String expression;
@Nullable
private final Integer position;
public ParseException(@NotNull jscl.text.ParseException jsclParseException) {
this.messageId = "jscl_" + jsclParseException.getMessageId();
this.expression = jsclParseException.getExpression();
this.position = jsclParseException.getPosition();
this.parameters = jsclParseException.getParameters();
} }
public ParseException(String message) { public ParseException(@NotNull String messageId, @Nullable Integer position, @NotNull String expression, Object... parameters) {
super(message); this.messageId = messageId;
this.expression = expression;
this.position = position;
if (CollectionsUtils.isEmpty(parameters)) {
this.parameters = Collections.emptyList();
} else {
this.parameters = Arrays.asList(parameters);
}
} }
public ParseException(String message, Throwable cause) { public ParseException(@NotNull String messageId, @NotNull String expression, Object... parameters) {
super(message, cause); this(messageId, null, expression, parameters);
} }
public ParseException(Throwable cause) { @NotNull
super(cause); public String getMessageId() {
return messageId;
}
@NotNull
public List<Object> getParameters() {
return parameters;
}
@NotNull
public String getExpression() {
return expression;
}
@Nullable
public Integer getPosition() {
return position;
}
@Override
@Nullable
public String getLocalizedMessage() {
String result = null;
final String message = ResourceCache.instance.getCaption("msg_" + getMessageId());
if (message != null) {
if ( parameters.size() > 0 ) {
result = MessageFormat.format(message, parameters.toArray(new Object[parameters.size()]));
} else {
result = message;
}
}
return result;
} }
} }

View File

@ -55,7 +55,7 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
} }
if ((mathTypeBefore == MathType.function || mathTypeBefore == MathType.operator) && CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) { if ((mathTypeBefore == MathType.function || mathTypeBefore == MathType.operator) && CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) {
throw new ParseException("Empty function: " + mathTypeResult.getMatch()); throw new ParseException(Messages.msg_5, i, s, mathTypeResult.getMatch());
} }
i = mathTypeResult.processToJscl(result, i); i = mathTypeResult.processToJscl(result, i);
@ -66,7 +66,7 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
@NotNull @NotNull
private static PreparedExpression replaceVariables(@NotNull final String s, int depth, @NotNull List<Var> undefinedVars) throws ParseException { private static PreparedExpression replaceVariables(@NotNull final String s, int depth, @NotNull List<Var> undefinedVars) throws ParseException {
if (depth >= MAX_DEPTH) { if (depth >= MAX_DEPTH) {
throw new ParseException("Infinite loop in expression: " + s); throw new ParseException(Messages.msg_6, s);
} else { } else {
depth++; depth++;
} }

View File

@ -0,0 +1,98 @@
package org.solovyev.android.view.prefs;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
import org.solovyev.android.view.widgets.DragButton;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
/**
* User: serso
* Date: 11/25/11
* Time: 1:52 PM
*/
public enum ResourceCache {
instance;
// ids of drag buttons in R.class
private List<Integer> dragButtonIds = null;
// ids of buttons in R.class
private List<Integer> buttonIds = null;
private static final Map<String, Map<String, String>> captions = new HashMap<String, Map<String, String>>();
public List<Integer> getDragButtonIds() {
return dragButtonIds;
}
public List<Integer> getButtonIds() {
return buttonIds;
}
public void initCaptions(@NotNull Class<?> resourceClass, @NotNull Activity activity) {
final Locale locale = Locale.getDefault();
if (!captions.containsKey(locale.getLanguage())) {
final Map<String, String> captionsByLanguage = new HashMap<String, String>();
for (Field field : resourceClass.getDeclaredFields()) {
int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
try {
int captionId = field.getInt(resourceClass);
captionsByLanguage.put(field.getName(), activity.getString(captionId));
} catch (IllegalAccessException e) {
Log.e(ResourceCache.class.getName(), e.getMessage());
}
}
}
captions.put(locale.getLanguage(), captionsByLanguage);
}
}
@Nullable
public String getCaption(@NotNull String captionId) {
final Locale locale = Locale.getDefault();
final Map<String, String> captionsByLanguage = captions.get(locale.getLanguage());
if (captionsByLanguage != null) {
return captionsByLanguage.get(captionId);
}
return null;
}
public void init(@NotNull Class<?> resourceClass, @NotNull Activity activity) {
dragButtonIds = new ArrayList<Integer>();
buttonIds = new ArrayList<Integer>();
for (Field field : resourceClass.getDeclaredFields()) {
int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
try {
int viewId = field.getInt(resourceClass);
final View view = activity.findViewById(viewId);
if (view instanceof DragButton) {
dragButtonIds.add(viewId);
}
if (view instanceof Button) {
buttonIds.add(viewId);
}
} catch (IllegalAccessException e) {
Log.e(ResourceCache.class.getName(), e.getMessage());
}
}
}
}
}

View File

@ -34,7 +34,7 @@ public class AngleUnitsButton extends DirectionDragButton {
if (result != null) { if (result != null) {
final Resources resources = getResources(); final Resources resources = getResources();
if ( CalculatorEngine.instance.getEngine().getDefaultAngleUnits().name().equals(getDirectionText(direction)) ) { if ( CalculatorEngine.instance.getEngine().getDefaultAngleUnit().name().equals(getDirectionText(direction)) ) {
result.setColor(resources.getColor(R.color.selected_angle_unit_text_color)); result.setColor(resources.getColor(R.color.selected_angle_unit_text_color));
} else { } else {
result.setColor(resources.getColor(R.color.default_text_color)); result.setColor(resources.getColor(R.color.default_text_color));

View File

@ -5,7 +5,7 @@
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import jscl.AngleUnits; import jscl.AngleUnit;
import jscl.math.Expression; import jscl.math.Expression;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -40,7 +40,7 @@ public class CalculatorEngineTest {
cm.evaluate(JsclOperation.numeric, "3^10^10^10"); cm.evaluate(JsclOperation.numeric, "3^10^10^10");
Assert.fail(); Assert.fail();
} catch (ParseException e) { } catch (ParseException e) {
if (e.getMessage().startsWith("Too long calculation")) { if (e.getMessageId().equals(Messages.msg_3)) {
} else { } else {
System.out.print(e.getCause().getMessage()); System.out.print(e.getCause().getMessage());
@ -52,7 +52,7 @@ public class CalculatorEngineTest {
cm.evaluate(JsclOperation.numeric, "9999999!"); cm.evaluate(JsclOperation.numeric, "9999999!");
Assert.fail(); Assert.fail();
} catch (ParseException e) { } catch (ParseException e) {
if (e.getMessage().startsWith("Too long calculation")) { if (e.getMessageId().equals(Messages.msg_3)) {
} else { } else {
System.out.print(e.getCause().getMessage()); System.out.print(e.getCause().getMessage());
@ -85,27 +85,27 @@ public class CalculatorEngineTest {
Assert.assertEquals("1", cm.evaluate(JsclOperation.simplify, "eq( 1, 1)").getResult()); Assert.assertEquals("1", cm.evaluate(JsclOperation.simplify, "eq( 1, 1)").getResult());
Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "lg(10)").getResult()); Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "lg(10)").getResult());
Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "2+2").getResult()); Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "2+2").getResult());
final AngleUnits defaultAngleUnits = cm.getEngine().getDefaultAngleUnits(); final AngleUnit defaultAngleUnit = cm.getEngine().getDefaultAngleUnit();
try { try {
cm.getEngine().setDefaultAngleUnits(AngleUnits.rad); cm.getEngine().setDefaultAngleUnit(AngleUnit.rad);
Assert.assertEquals("-0.757", cm.evaluate(JsclOperation.numeric, "sin(4)").getResult()); Assert.assertEquals("-0.757", cm.evaluate(JsclOperation.numeric, "sin(4)").getResult());
Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "asin(0.5)").getResult()); Assert.assertEquals("0.524", cm.evaluate(JsclOperation.numeric, "asin(0.5)").getResult());
Assert.assertEquals("-0.396", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)").getResult()); Assert.assertEquals("-0.396", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)").getResult());
Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)").getResult()); Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)").getResult());
Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)").getResult()); Assert.assertEquals("-0.56", cm.evaluate(JsclOperation.numeric, "sin(4)asin(0.5)√(2)").getResult());
} finally { } finally {
cm.getEngine().setDefaultAngleUnits(defaultAngleUnits); cm.getEngine().setDefaultAngleUnit(defaultAngleUnit);
} }
Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "e^2").getResult()); Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "e^2").getResult());
Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(1)^2").getResult()); Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(1)^2").getResult());
Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(2)").getResult()); Assert.assertEquals("7.389", cm.evaluate(JsclOperation.numeric, "exp(2)").getResult());
Assert.assertEquals("2+i", cm.evaluate(JsclOperation.numeric, "2*1+√(-1)").getResult()); Assert.assertEquals("2+i", cm.evaluate(JsclOperation.numeric, "2*1+√(-1)").getResult());
try { try {
cm.getEngine().setDefaultAngleUnits(AngleUnits.rad); cm.getEngine().setDefaultAngleUnit(AngleUnit.rad);
Assert.assertEquals("0.921+3.142i", cm.evaluate(JsclOperation.numeric, "ln(5cosh(38π√(2cos(2))))").getResult()); Assert.assertEquals("0.921+3.142i", cm.evaluate(JsclOperation.numeric, "ln(5cosh(38π√(2cos(2))))").getResult());
Assert.assertEquals("-3.41+3.41i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)").getResult()); Assert.assertEquals("-3.41+3.41i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)").getResult());
} finally { } finally {
cm.getEngine().setDefaultAngleUnits(defaultAngleUnits); cm.getEngine().setDefaultAngleUnit(defaultAngleUnit);
} }
Assert.assertEquals("7.389i", cm.evaluate(JsclOperation.numeric, "iexp(2)").getResult()); Assert.assertEquals("7.389i", cm.evaluate(JsclOperation.numeric, "iexp(2)").getResult());
Assert.assertEquals("2+7.389i", cm.evaluate(JsclOperation.numeric, "2+iexp(2)").getResult()); Assert.assertEquals("2+7.389i", cm.evaluate(JsclOperation.numeric, "2+iexp(2)").getResult());
@ -143,14 +143,14 @@ public class CalculatorEngineTest {
CalculatorEngine.instance.getVarsRegister().add(new Var.Builder("si", 5d)); CalculatorEngine.instance.getVarsRegister().add(new Var.Builder("si", 5d));
try { try {
cm.getEngine().setDefaultAngleUnits(AngleUnits.rad); cm.getEngine().setDefaultAngleUnit(AngleUnit.rad);
Assert.assertEquals("-0.959", cm.evaluate(JsclOperation.numeric, "sin(5)").getResult()); Assert.assertEquals("-0.959", cm.evaluate(JsclOperation.numeric, "sin(5)").getResult());
Assert.assertEquals("-4.795", cm.evaluate(JsclOperation.numeric, "sin(5)si").getResult()); Assert.assertEquals("-4.795", cm.evaluate(JsclOperation.numeric, "sin(5)si").getResult());
Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "sisin(5)si").getResult()); Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "sisin(5)si").getResult());
Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "si*sin(5)si").getResult()); Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "si*sin(5)si").getResult());
Assert.assertEquals("-3.309", cm.evaluate(JsclOperation.numeric, "sisin(5si)si").getResult()); Assert.assertEquals("-3.309", cm.evaluate(JsclOperation.numeric, "sisin(5si)si").getResult());
} finally { } finally {
cm.getEngine().setDefaultAngleUnits(defaultAngleUnits); cm.getEngine().setDefaultAngleUnit(defaultAngleUnit);
} }
CalculatorEngine.instance.getVarsRegister().add(new Var.Builder("s", 1d)); CalculatorEngine.instance.getVarsRegister().add(new Var.Builder("s", 1d));
@ -242,12 +242,12 @@ public class CalculatorEngineTest {
} catch (ParseException e) { } catch (ParseException e) {
} }
final AngleUnits defaultAngleUnits = cm.getEngine().getDefaultAngleUnits(); final AngleUnit defaultAngleUnit = cm.getEngine().getDefaultAngleUnit();
try { try {
cm.getEngine().setDefaultAngleUnits(AngleUnits.rad); cm.getEngine().setDefaultAngleUnit(AngleUnit.rad);
Assert.assertEquals("0.739", cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(1))))))))))))))))))))))))))))))))))))").getResult()); Assert.assertEquals("0.739", cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(1))))))))))))))))))))))))))))))))))))").getResult());
} finally { } finally {
cm.getEngine().setDefaultAngleUnits(defaultAngleUnits); cm.getEngine().setDefaultAngleUnit(defaultAngleUnit);
} }
CalculatorEngine.instance.getVarsRegister().add(new Var.Builder("si", 5d)); CalculatorEngine.instance.getVarsRegister().add(new Var.Builder("si", 5d));
@ -317,9 +317,9 @@ public class CalculatorEngineTest {
public void testDegrees() throws Exception { public void testDegrees() throws Exception {
final CalculatorEngine cm = CalculatorEngine.instance; final CalculatorEngine cm = CalculatorEngine.instance;
final AngleUnits defaultAngleUnits = cm.getEngine().getDefaultAngleUnits(); final AngleUnit defaultAngleUnit = cm.getEngine().getDefaultAngleUnit();
try { try {
cm.getEngine().setDefaultAngleUnits(AngleUnits.rad); cm.getEngine().setDefaultAngleUnit(AngleUnit.rad);
cm.setPrecision(3); cm.setPrecision(3);
try { try {
Assert.assertEquals("0.017", cm.evaluate(JsclOperation.numeric, "°")); Assert.assertEquals("0.017", cm.evaluate(JsclOperation.numeric, "°"));
@ -340,7 +340,7 @@ public class CalculatorEngineTest {
Assert.assertEquals("∂(cos(t), t, t,1°)", cm.evaluate(JsclOperation.simplify, "∂(cos(t),t,t,1°)").getResult()); Assert.assertEquals("∂(cos(t), t, t,1°)", cm.evaluate(JsclOperation.simplify, "∂(cos(t),t,t,1°)").getResult());
} finally { } finally {
cm.getEngine().setDefaultAngleUnits(defaultAngleUnits); cm.getEngine().setDefaultAngleUnit(defaultAngleUnit);
} }
} }
} }