This commit is contained in:
serso
2011-12-15 22:50:05 +04:00
parent d6316f32d6
commit 602a626420
10 changed files with 260 additions and 223 deletions

View File

@@ -10,10 +10,7 @@ import jscl.MathContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.model.CalculatorParseException;
import org.solovyev.android.calculator.model.NumberBuilder;
import org.solovyev.android.calculator.model.TextProcessor;
import org.solovyev.android.calculator.model.*;
import org.solovyev.common.utils.MutableObject;
import java.util.HashMap;
@@ -27,6 +24,7 @@ import java.util.Map;
public class TextHighlighter implements TextProcessor<TextHighlighter.Result, String> {
private static final Map<String, String> nbFontAttributes = new HashMap<String, String>();
static {
nbFontAttributes.put("color", "#008000");
}
@@ -75,11 +73,11 @@ public class TextHighlighter implements TextProcessor<TextHighlighter.Result, St
private final int colorRed;
private final int colorGreen;
private final int colorBlue;
private final boolean allowScientificFormat;
private final boolean formatNumber;
public TextHighlighter(int baseColor, boolean allowScientificFormat, @NotNull MathContext mathContext) {
public TextHighlighter(int baseColor, boolean formatNumber, @NotNull MathContext mathContext) {
this.color = baseColor;
this.allowScientificFormat = allowScientificFormat;
this.formatNumber = formatNumber;
this.mathContext = mathContext;
//this.colorRed = Color.red(baseColor);
this.colorRed = (baseColor >> 16) & 0xFF;
@@ -99,15 +97,24 @@ public class TextHighlighter implements TextProcessor<TextHighlighter.Result, St
final StringBuilder text1 = new StringBuilder();
int numberOffset = 0;
int resultOffset = 0;
final NumberBuilder numberBuilder = new NumberBuilder(allowScientificFormat, CalculatorEngine.instance.getEngine());
final AbstractNumberBuilder numberBuilder;
if (!formatNumber) {
numberBuilder = new LiteNumberBuilder(CalculatorEngine.instance.getEngine());
} else {
numberBuilder = new NumberBuilder(CalculatorEngine.instance.getEngine());
}
for (int i = 0; i < text.length(); i++) {
MathType.Result mathType = MathType.getType(text, i, numberBuilder.isHexMode());
final MutableObject<Integer> localNumberOffset = new MutableObject<Integer>(0);
numberBuilder.process(text1, mathType, localNumberOffset);
numberOffset += localNumberOffset.getObject();
if (numberBuilder instanceof NumberBuilder) {
final MutableObject<Integer> numberOffset = new MutableObject<Integer>(0);
((NumberBuilder) numberBuilder).process(text1, mathType, numberOffset);
resultOffset += numberOffset.getObject();
} else {
((LiteNumberBuilder) numberBuilder).process(mathType);
}
final String match = mathType.getMatch();
switch (mathType.getMathType()) {
@@ -144,9 +151,11 @@ public class TextHighlighter implements TextProcessor<TextHighlighter.Result, St
}
}
final MutableObject<Integer> localNumberOffset = new MutableObject<Integer>(0);
numberBuilder.processNumber(text1, localNumberOffset);
numberOffset += localNumberOffset.getObject();
if (numberBuilder instanceof NumberBuilder) {
final MutableObject<Integer> numberOffset = new MutableObject<Integer>(0);
((NumberBuilder) numberBuilder).processNumber(text1, numberOffset);
resultOffset += numberOffset.getObject();
}
if (maxNumberOfOpenGroupSymbols > 0) {
@@ -165,13 +174,13 @@ public class TextHighlighter implements TextProcessor<TextHighlighter.Result, St
result = text1.toString();
}
return new Result(result, numberOffset);
return new Result(result, resultOffset);
}
private int processHighlightedText(@NotNull StringBuilder result, int i, @NotNull String match, @NotNull String tag, @Nullable Map<String, String> tagAttributes) {
result.append("<").append(tag);
if ( tagAttributes != null ) {
if (tagAttributes != null) {
for (Map.Entry<String, String> entry : tagAttributes.entrySet()) {
// attr1="attr1_value" attr2="attr2_value"
result.append(" ").append(entry.getKey()).append("=\"").append(entry.getValue()).append("\"");

View File

@@ -16,7 +16,7 @@ import org.solovyev.android.calculator.model.TextProcessor;
public enum JsclOperation {
simplify(new FromJsclSimplifyTextProcessor(CalculatorEngine.instance.getEngine())) {
simplify(new FromJsclSimplifyTextProcessor()) {
@NotNull
@Override
public String evaluate(@NotNull String expression) throws ParseException {

View File

@@ -0,0 +1,74 @@
/*
* 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.MathEngine;
import jscl.NumeralBase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.math.MathType;
/**
* User: serso
* Date: 12/15/11
* Time: 9:01 PM
*/
public abstract class AbstractNumberBuilder {
@NotNull
protected final MathEngine engine;
@Nullable
protected StringBuilder numberBuilder = null;
@Nullable
protected NumeralBase nb;
protected AbstractNumberBuilder(@NotNull MathEngine engine) {
this.engine = engine;
this.nb = engine.getNumeralBase();
}
/**
* Method determines if we can continue to process current number
*
* @param mathTypeResult current math type result
* @return true if we can continue of processing of current number, if false - new number should be constructed
*/
protected boolean canContinue(@NotNull MathType.Result mathTypeResult) {
return ((mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number && numeralBaseCheck(mathTypeResult) && numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult)));
}
private boolean numeralBaseInTheStart(@NotNull MathType mathType) {
return mathType != MathType.numeral_base || numberBuilder == null;
}
private boolean numeralBaseCheck(@NotNull MathType.Result mathType) {
return mathType.getMathType() != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.getMatch().charAt(0));
}
private boolean isSignAfterE(@NotNull MathType.Result mathTypeResult) {
if ("-".equals(mathTypeResult.getMatch()) || "+".equals(mathTypeResult.getMatch())) {
final StringBuilder localNb = numberBuilder;
if (localNb != null && localNb.length() > 0) {
if (localNb.charAt(localNb.length() - 1) == MathType.POWER_10) {
return true;
}
}
}
return false;
}
public boolean isHexMode() {
return nb == NumeralBase.hex || (nb == null && engine.getNumeralBase() == NumeralBase.hex);
}
@NotNull
protected NumeralBase getNumeralBase() {
return nb == null ? engine.getNumeralBase() : nb;
}
}

View File

@@ -1,6 +1,5 @@
package org.solovyev.android.calculator.model;
import jscl.MathContext;
import jscl.math.Generic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -16,35 +15,17 @@ import java.util.List;
*/
public class FromJsclSimplifyTextProcessor implements TextProcessor<String, Generic> {
@NotNull
private final MathContext mathContext;
public FromJsclSimplifyTextProcessor(@NotNull MathContext mathContext) {
this.mathContext = mathContext;
public FromJsclSimplifyTextProcessor() {
}
@NotNull
@Override
public String process(@NotNull Generic from) throws CalculatorParseException {
final String s = from.toString();
return process(s);
return removeMultiplicationSigns(from.toString());
}
public String process(@NotNull String s) {
final StringBuilder sb = new StringBuilder();
final NumberBuilder nb = new NumberBuilder(false, CalculatorEngine.instance.getEngine());
for (int i = 0; i < s.length(); i++) {
final MathType.Result mathTypeResult = MathType.getType(s, i, nb.isHexMode());
nb.process(sb, mathTypeResult, null);
i = mathTypeResult.processFromJscl(sb, i);
}
nb.processNumber(sb, null);
return removeMultiplicationSigns(sb.toString());
return removeMultiplicationSigns(s);
}
@NotNull

View File

@@ -0,0 +1,55 @@
/*
* 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.MathEngine;
import jscl.NumeralBase;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.math.MathType;
/**
* User: serso
* Date: 12/15/11
* Time: 8:33 PM
*/
public class LiteNumberBuilder extends AbstractNumberBuilder {
public LiteNumberBuilder(@NotNull MathEngine engine) {
super(engine);
this.nb = engine.getNumeralBase();
}
public void process(@NotNull MathType.Result mathTypeResult) {
if (canContinue(mathTypeResult)) {
// let's continue building number
if (numberBuilder == null) {
// if new number => create new builder
numberBuilder = new StringBuilder();
}
if (mathTypeResult.getMathType() != MathType.numeral_base) {
// just add matching string
numberBuilder.append(mathTypeResult.getMatch());
} else {
// set explicitly numeral base (do not include it into number)
nb = NumeralBase.getByPrefix(mathTypeResult.getMatch());
}
} else {
// process current number (and go to the next one)
if (numberBuilder != null) {
numberBuilder = null;
// must set default numeral base (exit numeral base mode)
nb = engine.getNumeralBase();
}
}
}
}

View File

@@ -27,23 +27,10 @@ import java.util.List;
* Date: 10/23/11
* Time: 2:57 PM
*/
public class NumberBuilder {
public class NumberBuilder extends AbstractNumberBuilder {
@NotNull
private final MathEngine engine;
@Nullable
private StringBuilder numberBuilder = null;
private final boolean allowScientificFormat;
@Nullable
private NumeralBase nb;
public NumberBuilder(boolean allowScientificFormat, @NotNull MathEngine engine) {
this.allowScientificFormat = allowScientificFormat;
this.nb = engine.getNumeralBase();
this.engine = engine;
public NumberBuilder(@NotNull MathEngine engine) {
super(engine);
}
/**
@@ -83,48 +70,6 @@ public class NumberBuilder {
return possibleResult == null ? mathTypeResult : possibleResult;
}
/**
* Method determines if we can continue to process current number
* @param mathTypeResult current math type result
*
* @return true if we can continue of processing of current number, if false - new number should be constructed
*/
private boolean canContinue(@NotNull MathType.Result mathTypeResult) {
return ((mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number && numeralBaseCheck(mathTypeResult) && numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult)));
}
private boolean numeralBaseInTheStart(@NotNull MathType mathType) {
return mathType != MathType.numeral_base || numberBuilder == null;
}
private boolean numeralBaseCheck(@NotNull MathType.Result mathType) {
if (mathType.getMathType() == MathType.digit) {
final Character ch = mathType.getMatch().charAt(0);
if (NumeralBase.hex.getAcceptableCharacters().contains(ch) && !NumeralBase.dec.getAcceptableCharacters().contains(ch)) {
if (nb == NumeralBase.hex) {
return true;
} else {
return false;
}
} else {
return true;
}
} else {
return true;
}
}
private boolean isSignAfterE(@NotNull MathType.Result mathTypeResult) {
if ("-".equals(mathTypeResult.getMatch()) || "+".equals(mathTypeResult.getMatch())) {
if (numberBuilder != null && numberBuilder.length() > 0) {
if (numberBuilder.charAt(numberBuilder.length() - 1) == MathType.POWER_10) {
return true;
}
}
}
return false;
}
/**
* Method replaces number in text according to some rules (e.g. formatting)
*
@@ -172,7 +117,7 @@ public class NumberBuilder {
nb = engine.getNumeralBase();
}
return replaceNumberInText(text, number, trimmedChars, offset, localNb, allowScientificFormat, engine);
return replaceNumberInText(text, number, trimmedChars, offset, localNb, engine);
}
@Nullable
@@ -181,7 +126,6 @@ public class NumberBuilder {
int trimmedChars,
@Nullable MutableObject<Integer> offset,
@NotNull NumeralBase nb,
boolean allowScientificFormat,
@NotNull final MathEngine engine) {
MathType.Result result = null;
@@ -205,7 +149,7 @@ public class NumberBuilder {
text.append(constant.getName());
result = new MathType.Result(MathType.constant, constant.getName());
} else {
final String newNumber = formatNumber(number, nb, allowScientificFormat, engine);
final String newNumber = formatNumber(number, nb, engine);
if (offset != null) {
// register offset between old number and new number
offset.setObject(newNumber.length() - oldNumberLength);
@@ -218,60 +162,42 @@ public class NumberBuilder {
}
@NotNull
private static String formatNumber(@NotNull String number, @NotNull NumeralBase nb, boolean allowScientificFormat, @NotNull MathEngine engine) {
private static String formatNumber(@NotNull String number, @NotNull NumeralBase nb, @NotNull MathEngine engine) {
String result;
if (allowScientificFormat) {
int indexOfDot = number.indexOf('.');
int indexOfDot = number.indexOf('.');
if (indexOfDot < 0) {
int indexOfE;
if (nb == NumeralBase.hex) {
indexOfE = -1;
} else {
indexOfE = number.indexOf(MathType.POWER_10);
}
if (indexOfE < 0) {
result = toString(number, nb, engine);
} else {
final String part;
if (indexOfDot != 0) {
part = toString(number.substring(0, indexOfE), nb, engine);
} else {
part = "";
}
result = part + number.substring(indexOfE);
}
if (indexOfDot < 0) {
int indexOfE;
if (nb == NumeralBase.hex) {
indexOfE = -1;
} else {
final String integerPart;
if (indexOfDot != 0) {
integerPart = toString(number.substring(0, indexOfDot), nb, engine);
indexOfE = number.indexOf(MathType.POWER_10);
}
if (indexOfE < 0) {
result = engine.addGroupingSeparators(nb, number);
} else {
final String partBeforeE;
if (indexOfE != 0) {
partBeforeE = engine.addGroupingSeparators(nb, number.substring(0, indexOfE));
} else {
integerPart = "";
partBeforeE = "";
}
result = integerPart + number.substring(indexOfDot);
result = partBeforeE + number.substring(indexOfE);
}
} else {
result = toString(number, nb, engine);
final String integerPart;
if (indexOfDot != 0) {
integerPart = engine.addGroupingSeparators(nb, number.substring(0, indexOfDot));
} else {
integerPart = "";
}
result = integerPart + number.substring(indexOfDot);
}
return result;
}
@NotNull
private static String toString(@NotNull String value, @NotNull NumeralBase nb, @NotNull MathContext mathContext) {
return mathContext.format(toDouble(value, nb, mathContext), nb);
}
public boolean isHexMode() {
return nb == NumeralBase.hex || (nb == null && engine.getNumeralBase() == NumeralBase.hex);
}
@NotNull
private NumeralBase getNumeralBase() {
return nb == null ? engine.getNumeralBase() : nb;
}
@NotNull
private static Double toDouble(@NotNull String s, @NotNull NumeralBase nb, @NotNull final MathContext mc) throws NumberFormatException {
final NumeralBase defaultNb = mc.getNumeralBase();

View File

@@ -8,7 +8,6 @@ package org.solovyev.android.calculator.model;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.StartsWithFinder;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.common.utils.CollectionsUtils;
@@ -36,11 +35,9 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression, String> {
final StringBuilder result = new StringBuilder();
MathType.Result mathTypeResult = null;
MathType.Result mathTypeBefore = null;
MathType.Result mathTypeBefore;
final StringBuilder sb = new StringBuilder(s);
final NumberBuilder nb = new NumberBuilder(false, CalculatorEngine.instance.getEngine());
final LiteNumberBuilder nb = new LiteNumberBuilder(CalculatorEngine.instance.getEngine());
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') continue;
startsWithFinder.setI(i);
@@ -49,7 +46,7 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression, String> {
mathTypeResult = MathType.getType(s, i, nb.isHexMode());
nb.process(sb, mathTypeResult, null);
nb.process(mathTypeResult);
if (mathTypeBefore != null) {
@@ -132,8 +129,4 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression, String> {
return new PreparedExpression(result.toString(), undefinedVars);
}
public static String wrap(@NotNull JsclOperation operation, @NotNull String s) {
return operation.name() + "(\"" + s + "\");";
}
}