Module separation

This commit is contained in:
serso
2012-09-20 12:59:21 +04:00
parent 33db715776
commit 417cf88912
23 changed files with 1567 additions and 1448 deletions

View File

@@ -1,92 +1,94 @@
package org.solovyev.android.calculator;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import net.robotmedia.billing.BillingController;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.ads.AdsController;
import org.solovyev.android.calculator.model.CalculatorEngine;
/**
* User: serso
* Date: 12/1/11
* Time: 1:21 PM
*/
public class CalculatorApplication extends android.app.Application {
private static final String paypalDonateUrl = "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=se%2esolovyev%40gmail%2ecom&lc=RU&item_name=Android%20Calculator&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted";
public static final String AD_FREE_PRODUCT_ID = "ad_free";
public static final String AD_FREE_P_KEY = "org.solovyev.android.calculator_ad_free";
public static final String ADMOB_USER_ID = "a14f02cf9c80cbc";
public static final String REMOTE_STACK_TRACE_URL = "http://calculatorpp.com/crash_reports/upload.php";
@NotNull
private static CalculatorApplication instance;
public CalculatorApplication() {
instance = this;
}
@NotNull
public static CalculatorApplication getInstance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
AdsController.getInstance().init(ADMOB_USER_ID, AD_FREE_PRODUCT_ID, new BillingController.IConfiguration() {
@Override
public byte[] getObfuscationSalt() {
return new byte[]{81, -114, 32, -127, -32, -104, -40, -15, -47, 57, -13, -41, -33, 67, -114, 7, -11, 53, 126, 82};
}
@Override
public String getPublicKey() {
return CalculatorSecurity.getPK();
}
});
CalculatorEngine.instance.init(this, PreferenceManager.getDefaultSharedPreferences(this));
}
public static void showDonationDialog(@NotNull final Context context) {
final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
final View view = layoutInflater.inflate(R.layout.donate, null);
final TextView donate = (TextView) view.findViewById(R.id.donateText);
donate.setMovementMethod(LinkMovementMethod.getInstance());
final AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setCancelable(true)
.setNegativeButton(R.string.c_cancel, null)
.setPositiveButton(R.string.c_donate, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
final Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(paypalDonateUrl));
context.startActivity(i);
}
})
.setView(view);
builder.create().show();
}
public static void registerOnRemoteStackTrace() {
//Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(null, REMOTE_STACK_TRACE_URL));
}
}
package org.solovyev.android.calculator;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import net.robotmedia.billing.BillingController;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.ads.AdsController;
import org.solovyev.android.calculator.model.CalculatorEngine;
/**
* User: serso
* Date: 12/1/11
* Time: 1:21 PM
*/
public class CalculatorApplication extends android.app.Application {
private static final String paypalDonateUrl = "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=se%2esolovyev%40gmail%2ecom&lc=RU&item_name=Android%20Calculator&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted";
public static final String AD_FREE_PRODUCT_ID = "ad_free";
public static final String AD_FREE_P_KEY = "org.solovyev.android.calculator_ad_free";
public static final String ADMOB_USER_ID = "a14f02cf9c80cbc";
public static final String REMOTE_STACK_TRACE_URL = "http://calculatorpp.com/crash_reports/upload.php";
@NotNull
private static CalculatorApplication instance;
public CalculatorApplication() {
instance = this;
}
@NotNull
public static CalculatorApplication getInstance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
CalculatorLocatorImpl.getInstance().setCalculatorEngine(CalculatorEngine.instance);
AdsController.getInstance().init(ADMOB_USER_ID, AD_FREE_PRODUCT_ID, new BillingController.IConfiguration() {
@Override
public byte[] getObfuscationSalt() {
return new byte[]{81, -114, 32, -127, -32, -104, -40, -15, -47, 57, -13, -41, -33, 67, -114, 7, -11, 53, 126, 82};
}
@Override
public String getPublicKey() {
return CalculatorSecurity.getPK();
}
});
CalculatorEngine.instance.init(this, PreferenceManager.getDefaultSharedPreferences(this));
}
public static void showDonationDialog(@NotNull final Context context) {
final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
final View view = layoutInflater.inflate(R.layout.donate, null);
final TextView donate = (TextView) view.findViewById(R.id.donateText);
donate.setMovementMethod(LinkMovementMethod.getInstance());
final AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setCancelable(true)
.setNegativeButton(R.string.c_cancel, null)
.setPositiveButton(R.string.c_donate, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
final Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(paypalDonateUrl));
context.startActivity(i);
}
})
.setView(view);
builder.create().show();
}
public static void registerOnRemoteStackTrace() {
//Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(null, REMOTE_STACK_TRACE_URL));
}
}

View File

@@ -1,19 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator;
/**
* User: serso
* Date: 10/24/11
* Time: 9:55 PM
*/
public interface CalculatorEngineControl {
void evaluate();
void simplify();
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.history.Editor;
import org.solovyev.android.calculator.jscl.JsclOperation;
/**
* User: serso
* Date: 12/17/11
* Time: 9:45 PM
*/
public interface ICalculatorDisplay extends Editor{
boolean isValid();
void setValid(boolean valid);
@Nullable
String getErrorMessage();
void setErrorMessage(@Nullable String errorMessage);
void setJsclOperation(@NotNull JsclOperation jsclOperation);
@NotNull
JsclOperation getJsclOperation();
void setGenericResult(@Nullable Generic genericResult);
@Nullable
Generic getGenericResult();
}

View File

@@ -1,110 +1,111 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
import org.solovyev.android.calculator.ICalculatorDisplay;
/**
* User: serso
* Date: 9/11/11
* Time: 12:16 AM
*/
@Root
public class CalculatorHistoryState extends AbstractHistoryState {
@Element
@NotNull
private EditorHistoryState editorState;
@Element
@NotNull
private CalculatorDisplayHistoryState displayState;
private CalculatorHistoryState() {
// for xml
}
private CalculatorHistoryState(@NotNull EditorHistoryState editorState,
@NotNull CalculatorDisplayHistoryState displayState) {
this.editorState = editorState;
this.displayState = displayState;
}
public static CalculatorHistoryState newInstance(@NotNull Editor editor, @NotNull ICalculatorDisplay display) {
final EditorHistoryState editorHistoryState = EditorHistoryState.newInstance(editor);
final CalculatorDisplayHistoryState displayHistoryState = CalculatorDisplayHistoryState.newInstance(display);
return new CalculatorHistoryState(editorHistoryState, displayHistoryState);
}
@NotNull
public EditorHistoryState getEditorState() {
return editorState;
}
public void setEditorState(@NotNull EditorHistoryState editorState) {
this.editorState = editorState;
}
@NotNull
public CalculatorDisplayHistoryState getDisplayState() {
return displayState;
}
public void setDisplayState(@NotNull CalculatorDisplayHistoryState displayState) {
this.displayState = displayState;
}
@Override
public String toString() {
return "CalculatorHistoryState{" +
"editorState=" + editorState +
", displayState=" + displayState +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CalculatorHistoryState that = (CalculatorHistoryState) o;
if (this.isSaved() != that.isSaved()) return false;
if (this.getId() != that.getId()) return false;
if (!displayState.equals(that.displayState)) return false;
if (!editorState.equals(that.editorState)) return false;
return true;
}
@Override
public int hashCode() {
int result = Boolean.valueOf(isSaved()).hashCode();
result = 31 * result + getId();
result = 31 * result + editorState.hashCode();
result = 31 * result + displayState.hashCode();
return result;
}
public void setValuesFromHistory(@NotNull Editor editor, @NotNull ICalculatorDisplay display) {
this.getEditorState().setValuesFromHistory(editor);
this.getDisplayState().setValuesFromHistory(display);
}
@Override
protected CalculatorHistoryState clone() {
final CalculatorHistoryState clone = (CalculatorHistoryState)super.clone();
clone.editorState = this.editorState.clone();
clone.displayState = this.displayState.clone();
return clone;
}
}
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.ICalculatorDisplay;
/**
* User: serso
* Date: 9/11/11
* Time: 12:16 AM
*/
@Root
public class CalculatorHistoryState extends AbstractHistoryState {
@Element
@NotNull
private EditorHistoryState editorState;
@Element
@NotNull
private CalculatorDisplayHistoryState displayState;
private CalculatorHistoryState() {
// for xml
}
private CalculatorHistoryState(@NotNull EditorHistoryState editorState,
@NotNull CalculatorDisplayHistoryState displayState) {
this.editorState = editorState;
this.displayState = displayState;
}
public static CalculatorHistoryState newInstance(@NotNull Editor editor, @NotNull ICalculatorDisplay display) {
final EditorHistoryState editorHistoryState = EditorHistoryState.newInstance(editor);
final CalculatorDisplayHistoryState displayHistoryState = CalculatorDisplayHistoryState.newInstance(display);
return new CalculatorHistoryState(editorHistoryState, displayHistoryState);
}
@NotNull
public EditorHistoryState getEditorState() {
return editorState;
}
public void setEditorState(@NotNull EditorHistoryState editorState) {
this.editorState = editorState;
}
@NotNull
public CalculatorDisplayHistoryState getDisplayState() {
return displayState;
}
public void setDisplayState(@NotNull CalculatorDisplayHistoryState displayState) {
this.displayState = displayState;
}
@Override
public String toString() {
return "CalculatorHistoryState{" +
"editorState=" + editorState +
", displayState=" + displayState +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CalculatorHistoryState that = (CalculatorHistoryState) o;
if (this.isSaved() != that.isSaved()) return false;
if (this.getId() != that.getId()) return false;
if (!displayState.equals(that.displayState)) return false;
if (!editorState.equals(that.editorState)) return false;
return true;
}
@Override
public int hashCode() {
int result = Boolean.valueOf(isSaved()).hashCode();
result = 31 * result + getId();
result = 31 * result + editorState.hashCode();
result = 31 * result + displayState.hashCode();
return result;
}
public void setValuesFromHistory(@NotNull Editor editor, @NotNull ICalculatorDisplay display) {
this.getEditorState().setValuesFromHistory(editor);
this.getDisplayState().setValuesFromHistory(display);
}
@Override
protected CalculatorHistoryState clone() {
final CalculatorHistoryState clone = (CalculatorHistoryState)super.clone();
clone.editorState = this.editorState.clone();
clone.displayState = this.displayState.clone();
return clone;
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/17/11
* Time: 9:37 PM
*/
public interface Editor {
@Nullable
CharSequence getText();
void setText(@Nullable CharSequence text);
int getSelection();
void setSelection(int selection);
}

View File

@@ -1,87 +1,88 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
@Root
public class EditorHistoryState implements Cloneable{
@Element
private int cursorPosition;
@Element(required = false)
@Nullable
private String text;
private EditorHistoryState() {
// for xml
}
@NotNull
public static EditorHistoryState newInstance(@NotNull Editor editor) {
final EditorHistoryState result = new EditorHistoryState();
result.text = String.valueOf(editor.getText());
result.cursorPosition = editor.getSelection();
return result;
}
public void setValuesFromHistory(@NotNull Editor editor) {
editor.setText(this.getText());
editor.setSelection(this.getCursorPosition());
}
@Nullable
public String getText() {
return text;
}
public int getCursorPosition() {
return cursorPosition;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EditorHistoryState)) return false;
EditorHistoryState that = (EditorHistoryState) o;
if (cursorPosition != that.cursorPosition) return false;
if (text != null ? !text.equals(that.text) : that.text != null) return false;
return true;
}
@Override
public int hashCode() {
int result = cursorPosition;
result = 31 * result + (text != null ? text.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "EditorHistoryState{" +
"cursorPosition=" + cursorPosition +
", text='" + text + '\'' +
'}';
}
@Override
protected EditorHistoryState clone() {
try {
return (EditorHistoryState)super.clone();
} catch (CloneNotSupportedException e) {
throw new UnsupportedOperationException(e);
}
}
}
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator.history;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
import org.solovyev.android.calculator.Editor;
@Root
public class EditorHistoryState implements Cloneable{
@Element
private int cursorPosition;
@Element(required = false)
@Nullable
private String text;
private EditorHistoryState() {
// for xml
}
@NotNull
public static EditorHistoryState newInstance(@NotNull Editor editor) {
final EditorHistoryState result = new EditorHistoryState();
result.text = String.valueOf(editor.getText());
result.cursorPosition = editor.getSelection();
return result;
}
public void setValuesFromHistory(@NotNull Editor editor) {
editor.setText(this.getText());
editor.setSelection(this.getCursorPosition());
}
@Nullable
public String getText() {
return text;
}
public int getCursorPosition() {
return cursorPosition;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EditorHistoryState)) return false;
EditorHistoryState that = (EditorHistoryState) o;
if (cursorPosition != that.cursorPosition) return false;
if (text != null ? !text.equals(that.text) : that.text != null) return false;
return true;
}
@Override
public int hashCode() {
int result = cursorPosition;
result = 31 * result + (text != null ? text.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "EditorHistoryState{" +
"cursorPosition=" + cursorPosition +
", text='" + text + '\'' +
'}';
}
@Override
protected EditorHistoryState clone() {
try {
return (EditorHistoryState)super.clone();
} catch (CloneNotSupportedException e) {
throw new UnsupportedOperationException(e);
}
}
}

View File

@@ -1,49 +1,50 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import android.widget.EditText;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 12/17/11
* Time: 9:39 PM
*/
public class TextViewEditorAdapter implements Editor {
@NotNull
private final TextView textView;
public TextViewEditorAdapter(@NotNull TextView textView) {
this.textView = textView;
}
@Override
public CharSequence getText() {
return textView.getText().toString();
}
@Override
public void setText(@Nullable CharSequence text) {
textView.setText(text);
}
@Override
public int getSelection() {
return textView.getSelectionStart();
}
@Override
public void setSelection(int selection) {
if ( textView instanceof EditText ) {
((EditText) textView).setSelection(selection);
}
}
}
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import android.widget.EditText;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.Editor;
/**
* User: serso
* Date: 12/17/11
* Time: 9:39 PM
*/
public class TextViewEditorAdapter implements Editor {
@NotNull
private final TextView textView;
public TextViewEditorAdapter(@NotNull TextView textView) {
this.textView = textView;
}
@Override
public CharSequence getText() {
return textView.getText().toString();
}
@Override
public void setText(@Nullable CharSequence text) {
textView.setText(text);
}
@Override
public int getSelection() {
return textView.getSelectionStart();
}
@Override
public void setSelection(int selection) {
if ( textView instanceof EditText ) {
((EditText) textView).setSelection(selection);
}
}
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.jscl;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.model.CalculatorParseException;
import org.solovyev.android.calculator.model.TextProcessor;
/**
* User: serso
* Date: 10/6/11
* Time: 9:48 PM
*/
class FromJsclNumericTextProcessor implements TextProcessor<String, Generic> {
public static final FromJsclNumericTextProcessor instance = new FromJsclNumericTextProcessor();
@NotNull
@Override
public String process(@NotNull Generic numeric) throws CalculatorParseException {
return numeric.toString().replace("*", "");
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator.jscl;
import jscl.math.Generic;
import jscl.text.ParseException;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.model.DummyTextProcessor;
import org.solovyev.android.calculator.model.FromJsclSimplifyTextProcessor;
import org.solovyev.android.calculator.model.TextProcessor;
public enum JsclOperation {
simplify,
elementary,
numeric;
JsclOperation() {
}
@NotNull
public TextProcessor<String, Generic> getFromProcessor() {
switch (this) {
case simplify:
return FromJsclSimplifyTextProcessor.instance;
case elementary:
return DummyTextProcessor.instance;
case numeric:
return FromJsclNumericTextProcessor.instance;
default:
throw new UnsupportedOperationException();
}
}
@NotNull
public final String evaluate(@NotNull String expression) throws ParseException {
switch (this) {
case simplify:
return CalculatorEngine.instance.getEngine().simplify(expression);
case elementary:
return CalculatorEngine.instance.getEngine().elementary(expression);
case numeric:
return CalculatorEngine.instance.getEngine().evaluate(expression);
default:
throw new UnsupportedOperationException();
}
}
@NotNull
public final Generic evaluateGeneric(@NotNull String expression) throws ParseException {
switch (this) {
case simplify:
return CalculatorEngine.instance.getEngine().simplifyGeneric(expression);
case elementary:
return CalculatorEngine.instance.getEngine().elementaryGeneric(expression);
case numeric:
return CalculatorEngine.instance.getEngine().evaluateGeneric(expression);
default:
throw new UnsupportedOperationException();
}
}
}

View File

@@ -1,448 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
*/
package org.solovyev.android.calculator.math;
import jscl.JsclMathEngine;
import jscl.NumeralBase;
import jscl.math.function.Constants;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.JPredicate;
import org.solovyev.common.StartsWithFinder;
import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.model.CalculatorParseException;
import org.solovyev.common.collections.CollectionsUtils;
import java.util.*;
public enum MathType {
numeral_base(50, true, false, MathGroupType.number) {
private final List<String> tokens = new ArrayList<String>(10);
{
for (NumeralBase numeralBase : NumeralBase.values()) {
final String jsclPrefix = numeralBase.getJsclPrefix();
if (jsclPrefix != null) {
tokens.add(jsclPrefix);
}
}
}
@NotNull
@Override
public List<String> getTokens() {
return tokens;
}
},
dot(200, true, true, MathGroupType.number, ".") {
@Override
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit;
}
},
grouping_separator(250, false, false, MathGroupType.number, "'", " "){
@Override
public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws CalculatorParseException {
return i;
}
},
power_10(300, false, false, MathGroupType.number, "E"),
postfix_function(400, false, true, MathGroupType.function) {
@NotNull
@Override
public List<String> getTokens() {
return CalculatorEngine.instance.getPostfixFunctionsRegistry().getNames();
}
},
unary_operation(500, false, false, MathGroupType.operation, "-", "="),
binary_operation(600, false, false, MathGroupType.operation, "-", "+", "*", "×", "", "/", "^") {
@Override
protected String getSubstituteToJscl(@NotNull String match) {
if (match.equals("×") || match.equals("")) {
return "*";
} else {
return null;
}
}
},
open_group_symbol(800, true, false, MathGroupType.other, "[", "(", "{") {
@Override
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function && mathTypeBefore != operator;
}
@Override
protected String getSubstituteToJscl(@NotNull String match) {
return "(";
}
},
close_group_symbol(900, false, true, MathGroupType.other, "]", ")", "}") {
@Override
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
return false;
}
@Override
protected String getSubstituteToJscl(@NotNull String match) {
return ")";
}
},
function(1000, true, true, MathGroupType.function) {
@NotNull
@Override
public List<String> getTokens() {
return CalculatorEngine.instance.getFunctionsRegistry().getNames();
}
},
operator(1050, true, true, MathGroupType.function) {
@NotNull
@Override
public List<String> getTokens() {
return CalculatorEngine.instance.getOperatorsRegistry().getNames();
}
},
constant(1100, true, true, MathGroupType.other) {
@NotNull
@Override
public List<String> getTokens() {
return CalculatorEngine.instance.getVarsRegistry().getNames();
}
@Override
protected String getSubstituteFromJscl(@NotNull String match) {
return Constants.INF_2.getName().equals(match) ? MathType.INFINITY : super.getSubstituteFromJscl(match);
}
},
digit(1125, true, true, MathGroupType.number) {
private final List<String> tokens = new ArrayList<String>(16);
{
for (Character character : NumeralBase.hex.getAcceptableCharacters()) {
tokens.add(character.toString());
}
}
@Override
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != digit && mathTypeBefore != dot /*&& mathTypeBefore != numeral_base*/;
}
@NotNull
@Override
public List<String> getTokens() {
return tokens;
}
},
comma(1150, false, false, MathGroupType.other, ","),
text(1200, false, false, MathGroupType.other) {
@Override
public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) {
if (match.length() > 0) {
result.append(match.charAt(0));
}
return i;
}
@Override
public int processFromJscl(@NotNull StringBuilder result, int i, @NotNull String match) {
if (match.length() > 0) {
result.append(match.charAt(0));
}
return i;
}
};
public static enum MathGroupType {
function,
number,
operation,
other
}
@NotNull
private final List<String> tokens;
@NotNull
private final Integer priority;
private final boolean needMultiplicationSignBefore;
private final boolean needMultiplicationSignAfter;
@NotNull
private final MathGroupType groupType;
MathType(@NotNull Integer priority,
boolean needMultiplicationSignBefore,
boolean needMultiplicationSignAfter,
@NotNull MathGroupType groupType,
@NotNull String... tokens) {
this(priority, needMultiplicationSignBefore, needMultiplicationSignAfter, groupType, CollectionsUtils.asList(tokens));
}
MathType(@NotNull Integer priority,
boolean needMultiplicationSignBefore,
boolean needMultiplicationSignAfter,
@NotNull MathGroupType groupType,
@NotNull List<String> tokens) {
this.priority = priority;
this.needMultiplicationSignBefore = needMultiplicationSignBefore;
this.needMultiplicationSignAfter = needMultiplicationSignAfter;
this.groupType = groupType;
this.tokens = Collections.unmodifiableList(tokens);
}
@NotNull
public MathGroupType getGroupType() {
return groupType;
}
/* public static int getPostfixFunctionStart(@NotNull CharSequence s, int position) throws ParseException {
assert s.length() > position;
int numberOfOpenGroups = 0;
int result = position;
for (; result >= 0; result--) {
final MathType mathType = getType(s.toString(), result).getMathType();
if (CollectionsUtils.contains(mathType, digit, dot, grouping_separator, power_10)) {
// continue
} else if (mathType == close_group_symbol) {
numberOfOpenGroups++;
} else if (mathType == open_group_symbol) {
if (numberOfOpenGroups > 0) {
numberOfOpenGroups--;
} else {
break;
}
} else {
if (stop(s, numberOfOpenGroups, result)) break;
}
}
if (numberOfOpenGroups != 0){
throw new ParseException("Could not find start of prefix function!");
}
return result;
}
public static boolean stop(CharSequence s, int numberOfOpenGroups, int i) {
if (numberOfOpenGroups == 0) {
if (i > 0) {
final EndsWithFinder endsWithFinder = new EndsWithFinder(s);
endsWithFinder.setI(i + 1);
if (!CollectionsUtils.contains(function.getTokens(), FilterType.included, endsWithFinder)) {
MathType type = getType(s.toString(), i).getMathType();
if (type != constant) {
return true;
}
}
} else {
return true;
}
}
return false;
}*/
@NotNull
public List<String> getTokens() {
return tokens;
}
private boolean isNeedMultiplicationSignBefore() {
return needMultiplicationSignBefore;
}
private boolean isNeedMultiplicationSignAfter() {
return needMultiplicationSignAfter;
}
public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) {
return needMultiplicationSignBefore && mathTypeBefore.isNeedMultiplicationSignAfter();
}
public int processToJscl(@NotNull StringBuilder result, int i, @NotNull String match) throws CalculatorParseException {
final String substitute = getSubstituteToJscl(match);
result.append(substitute == null ? match : substitute);
return returnI(i, match);
}
protected int returnI(int i, @NotNull String match) {
if (match.length() > 1) {
return i + match.length() - 1;
} else {
return i;
}
}
public int processFromJscl(@NotNull StringBuilder result, int i, @NotNull String match) {
final String substitute = getSubstituteFromJscl(match);
result.append(substitute == null ? match : substitute);
return returnI(i, match);
}
@Nullable
protected String getSubstituteFromJscl(@NotNull String match) {
return null;
}
@Nullable
protected String getSubstituteToJscl(@NotNull String match) {
return null;
}
public static final List<String> openGroupSymbols = Arrays.asList("[]", "()", "{}");
public final static Character POWER_10 = 'E';
public static final String IMAGINARY_NUMBER = "i";
public static final String IMAGINARY_NUMBER_JSCL = "√(-1)";
public static final String PI = "π";
public static final String E = "e";
public static final String C = "c";
public static final Double C_VALUE = 299792458d;
public static final String G = "G";
public static final Double G_VALUE = 6.6738480E-11;
public static final String H_REDUCED = "h";
public static final Double H_REDUCED_VALUE = 6.6260695729E-34 / ( 2 * Math.PI );
public final static String NAN = "NaN";
public final static String INFINITY = "";
public final static String INFINITY_JSCL = "Infinity";
/**
* Method determines mathematical entity type for text substring starting from ith index
*
*
* @param text analyzed text
* @param i index which points to start of substring
* @param hexMode
* @return math entity type of substring starting from ith index of specified text
*/
@NotNull
public static Result getType(@NotNull String text, int i, boolean hexMode) {
if (i < 0) {
throw new IllegalArgumentException("I must be more or equals to 0.");
} else if (i >= text.length() && i != 0) {
throw new IllegalArgumentException("I must be less than size of text.");
} else if (i == 0 && text.length() == 0) {
return new Result(MathType.text, text);
}
final StartsWithFinder startsWithFinder = new StartsWithFinder(text, i);
for (MathType mathType : getMathTypesByPriority()) {
final String s = CollectionsUtils.find(mathType.getTokens(), startsWithFinder);
if (s != null) {
if ( s.length() == 1 ) {
if (hexMode || JsclMathEngine.instance.getNumeralBase() == NumeralBase.hex) {
final Character ch = s.charAt(0);
if ( NumeralBase.hex.getAcceptableCharacters().contains(ch) ) {
return new Result(MathType.digit, s);
}
}
}
return new Result(mathType, s);
}
}
return new Result(MathType.text, text.substring(i));
}
private static List<MathType> mathTypesByPriority;
@NotNull
private static List<MathType> getMathTypesByPriority() {
if (mathTypesByPriority == null) {
final List<MathType> result = CollectionsUtils.asList(MathType.values());
Collections.sort(result, new Comparator<MathType>() {
@Override
public int compare(MathType l, MathType r) {
return l.priority.compareTo(r.priority);
}
});
mathTypesByPriority = result;
}
return mathTypesByPriority;
}
public static class Result {
@NotNull
private final MathType mathType;
@NotNull
private final String match;
public Result(@NotNull MathType mathType, @NotNull String match) {
this.mathType = mathType;
this.match = match;
}
public int processToJscl(@NotNull StringBuilder result, int i) throws CalculatorParseException {
return mathType.processToJscl(result, i, match);
}
public int processFromJscl(@NotNull StringBuilder result, int i) {
return mathType.processFromJscl(result, i, match);
}
@NotNull
public String getMatch() {
return match;
}
@NotNull
public MathType getMathType() {
return mathType;
}
}
private static class EndsWithFinder implements JPredicate<String> {
private int i;
@NotNull
private final CharSequence targetString;
private EndsWithFinder(@NotNull CharSequence targetString) {
this.targetString = targetString;
}
@Override
public boolean apply(@Nullable String s) {
return targetString.subSequence(0, i).toString().endsWith(s);
}
public void setI(int i) {
this.i = i;
}
}
}

View File

@@ -16,13 +16,16 @@ import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CalculatorApplication;
import org.solovyev.android.calculator.JCalculatorEngine;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.android.prefs.BooleanPreference;
import org.solovyev.android.prefs.Preference;
import org.solovyev.android.prefs.StringPreference;
import org.solovyev.common.MutableObject;
import org.solovyev.common.msg.MessageRegistry;
import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.EnumMapper;
import org.solovyev.common.text.NumberMapper;
import org.solovyev.common.text.StringUtils;
@@ -40,7 +43,7 @@ import java.util.concurrent.TimeUnit;
* Time: 11:38 PM
*/
public enum CalculatorEngine {
public enum CalculatorEngine implements JCalculatorEngine {
instance;
@@ -130,7 +133,8 @@ public enum CalculatorEngine {
this.engine.setUseGroupingSeparator(true);
}
@NotNull
@Override
@NotNull
public String getMultiplicationSign() {
return multiplicationSign;
}
@@ -229,10 +233,12 @@ public enum CalculatorEngine {
evalException.setObject(new CalculatorEvalException(e, e, jsclExpression));
} catch (ArithmeticException e) {
//System.out.println(e.getMessage());
parseException.setObject(new CalculatorParseException(R.string.msg_1, CalculatorApplication.getInstance(), jsclExpression, e.getMessage()));
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_1, MessageType.error, CalculatorApplication.getInstance(), e.getMessage());
parseException.setObject(new CalculatorParseException(jsclExpression, androidMessage));
} catch (StackOverflowError e) {
//System.out.println(StringUtils.fromStackTrace(e.getStackTrace()));
parseException.setObject(new CalculatorParseException(R.string.msg_2, CalculatorApplication.getInstance(), jsclExpression));
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_2, MessageType.error, CalculatorApplication.getInstance());
parseException.setObject(new CalculatorParseException(jsclExpression, androidMessage));
} catch (jscl.text.ParseException e) {
//System.out.println(e.getMessage());
parseException.setObject(new CalculatorParseException(e));
@@ -278,11 +284,13 @@ public enum CalculatorEngine {
}
if (calculationResultLocal == null) {
throw new CalculatorParseException(R.string.msg_3, CalculatorApplication.getInstance(), jsclExpression);
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_3, MessageType.error, CalculatorApplication.getInstance());
throw new CalculatorParseException(jsclExpression, androidMessage);
}
} catch (InterruptedException e) {
throw new CalculatorParseException(R.string.msg_4, CalculatorApplication.getInstance(), jsclExpression);
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_4, MessageType.error, CalculatorApplication.getInstance());
throw new CalculatorParseException(jsclExpression, androidMessage);
}
final Generic genericResult = calculationResult.getObject();
@@ -356,27 +364,32 @@ public enum CalculatorEngine {
}
}
@NotNull
@Override
@NotNull
public AndroidMathRegistry<IConstant> getVarsRegistry() {
return varsRegistry;
}
@NotNull
@Override
@NotNull
public AndroidMathRegistry<Function> getFunctionsRegistry() {
return functionsRegistry;
}
@NotNull
@Override
@NotNull
public AndroidMathRegistry<Operator> getOperatorsRegistry() {
return operatorsRegistry;
}
@NotNull
@Override
@NotNull
public AndroidMathRegistry<Operator> getPostfixFunctionsRegistry() {
return postfixFunctionsRegistry;
}
@NotNull
@Override
@NotNull
public MathEngine getEngine() {
return engine;
}

View File

@@ -1,91 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.model;
import android.app.Application;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.exceptions.SersoException;
import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType;
import java.util.List;
import java.util.Locale;
/**
* User: serso
* Date: 10/6/11
* Time: 9:25 PM
*/
public class CalculatorParseException extends SersoException implements Message {
@NotNull
private final Message message;
@NotNull
private final String expression;
@Nullable
private final Integer position;
public CalculatorParseException(@NotNull jscl.text.ParseException jsclParseException) {
this.message = jsclParseException;
this.expression = jsclParseException.getExpression();
this.position = jsclParseException.getPosition();
}
public CalculatorParseException(@NotNull Integer messageId, @NotNull Application application, @Nullable Integer position, @NotNull String expression, Object... parameters) {
this.message = new AndroidMessage(messageId, MessageType.error, application, parameters);
this.expression = expression;
this.position = position;
}
public CalculatorParseException(@NotNull Integer messageId, @NotNull Application application, @NotNull String expression, Object... parameters) {
this(messageId, application, null, expression, parameters);
}
@NotNull
public String getExpression() {
return expression;
}
@Nullable
public Integer getPosition() {
return position;
}
@NotNull
@Override
public String getMessageCode() {
return this.message.getMessageCode();
}
@NotNull
@Override
public List<Object> getParameters() {
return this.message.getParameters();
}
@NotNull
@Override
public MessageType getMessageType() {
return this.message.getMessageType();
}
@Override
@Nullable
public String getLocalizedMessage() {
return this.message.getLocalizedMessage(Locale.getDefault());
}
@NotNull
@Override
public String getLocalizedMessage(@NotNull Locale locale) {
return this.message.getLocalizedMessage(locale);
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.model;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
/**
* User: serso
* Date: 10/18/11
* Time: 10:39 PM
*/
public enum DummyTextProcessor implements TextProcessor<String, Generic> {
instance;
@NotNull
@Override
public String process(@NotNull Generic s) throws CalculatorParseException {
return s.toString();
}
}

View File

@@ -1,92 +0,0 @@
package org.solovyev.android.calculator.model;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.math.MathType;
import java.util.Arrays;
import java.util.List;
/**
* User: serso
* Date: 10/20/11
* Time: 2:59 PM
*/
public class FromJsclSimplifyTextProcessor implements TextProcessor<String, Generic> {
public static final FromJsclSimplifyTextProcessor instance = new FromJsclSimplifyTextProcessor();
public FromJsclSimplifyTextProcessor() {
}
@NotNull
@Override
public String process(@NotNull Generic from) throws CalculatorParseException {
return removeMultiplicationSigns(from.toString());
}
public String process(@NotNull String s) {
return removeMultiplicationSigns(s);
}
@NotNull
private String removeMultiplicationSigns(String s) {
final StringBuilder sb = new StringBuilder();
MathType.Result mathTypeBefore;
MathType.Result mathType = null;
MathType.Result mathTypeAfter = null;
for (int i = 0; i < s.length(); i++) {
mathTypeBefore = mathType;
if (mathTypeAfter == null) {
mathType = MathType.getType(s, i, false);
} else {
mathType = mathTypeAfter;
}
char ch = s.charAt(i);
if (ch == '*') {
if (i + 1 < s.length()) {
mathTypeAfter = MathType.getType(s, i + 1, false);
} else {
mathTypeAfter = null;
}
if (needMultiplicationSign(mathTypeBefore == null ? null : mathTypeBefore.getMathType(), mathTypeAfter == null ? null : mathTypeAfter.getMathType())) {
sb.append(CalculatorEngine.instance.getMultiplicationSign());
}
} else {
if (mathType.getMathType() == MathType.constant || mathType.getMathType() == MathType.function || mathType.getMathType() == MathType.operator) {
sb.append(mathType.getMatch());
i += mathType.getMatch().length() - 1;
} else {
sb.append(ch);
}
mathTypeAfter = null;
}
}
return sb.toString();
}
private final List<MathType> mathTypes = Arrays.asList(MathType.function, MathType.constant);
private boolean needMultiplicationSign(@Nullable MathType mathTypeBefore, @Nullable MathType mathTypeAfter) {
if (mathTypeBefore == null || mathTypeAfter == null) {
return true;
} else if (mathTypes.contains(mathTypeBefore) || mathTypes.contains(mathTypeAfter)) {
return false;
} else if ( mathTypeBefore == MathType.close_group_symbol ) {
return false;
} else if ( mathTypeAfter == MathType.open_group_symbol ) {
return false;
}
return true;
}
}

View File

@@ -1,14 +0,0 @@
package org.solovyev.android.calculator.model;
import org.jetbrains.annotations.NotNull;
/**
* User: serso
* Date: 9/26/11
* Time: 12:12 PM
*/
public interface TextProcessor<TO extends CharSequence, FROM> {
@NotNull
TO process(@NotNull FROM from) throws CalculatorParseException;
}

View File

@@ -10,9 +10,11 @@ import jscl.math.function.IConstant;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.CalculatorApplication;
import org.solovyev.android.calculator.R;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.StartsWithFinder;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.common.collections.CollectionsUtils;
import org.solovyev.common.msg.MessageType;
import java.util.ArrayList;
import java.util.List;
@@ -75,7 +77,8 @@ public class ToJsclTextProcessor implements TextProcessor<PreparedExpression, St
if (mathTypeBefore != null &&
(mathTypeBefore.getMathType() == MathType.function || mathTypeBefore.getMathType() == MathType.operator) &&
CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) {
throw new CalculatorParseException(R.string.msg_5, CalculatorApplication.getInstance(), i, s, mathTypeBefore.getMatch());
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_5, MessageType.error, CalculatorApplication.getInstance(), mathTypeBefore.getMatch());
throw new CalculatorParseException(i, s, androidMessage);
}
i = mathTypeResult.processToJscl(result, i);
@@ -86,7 +89,8 @@ public class ToJsclTextProcessor implements TextProcessor<PreparedExpression, St
@NotNull
private static PreparedExpression replaceVariables(@NotNull final String s, int depth, @NotNull List<IConstant> undefinedVars) throws CalculatorParseException {
if (depth >= MAX_DEPTH) {
throw new CalculatorParseException(R.string.msg_6, CalculatorApplication.getInstance(), s);
final AndroidMessage androidMessage = new AndroidMessage(R.string.msg_6, MessageType.error, CalculatorApplication.getInstance());
throw new CalculatorParseException(s, androidMessage);
} else {
depth++;
}