diff --git a/AndroidManifest.xml b/AndroidManifest.xml index dee85def..717d3dbe 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -42,6 +42,11 @@ a:configChanges="orientation|keyboardHidden"> + + + diff --git a/res/layout-land/main_calculator.xml b/res/layout-land/main_calculator.xml index 2390e6d9..5ea43f97 100644 --- a/res/layout-land/main_calculator.xml +++ b/res/layout-land/main_calculator.xml @@ -99,7 +99,7 @@ - + diff --git a/res/layout/calc_operators_button.xml b/res/layout/calc_operators_button.xml new file mode 100644 index 00000000..ffb943fc --- /dev/null +++ b/res/layout/calc_operators_button.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/res/layout/operators.xml b/res/layout/operators.xml new file mode 100644 index 00000000..c0165d13 --- /dev/null +++ b/res/layout/operators.xml @@ -0,0 +1,20 @@ + + + + + + + + + \ No newline at end of file diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 522edd12..8c9534d2 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -145,5 +145,6 @@ Невозможно создать пустую константу! Результат не допустим! + Операторы diff --git a/res/values/strings.xml b/res/values/strings.xml index 9ffadc12..a741d9cf 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -146,5 +146,6 @@ Unable to create empty constant! Current result is not valid! + Operators diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java index 94e1cb6f..330cb048 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java @@ -333,6 +333,11 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh CalculatorActivityLauncher.showFunctions(this); } + @SuppressWarnings({"UnusedDeclaration"}) + public void operatorsButtonClickHandler(@NotNull View v) { + CalculatorActivityLauncher.showOperators(this); + } + @SuppressWarnings({"UnusedDeclaration"}) public void varsButtonClickHandler(@NotNull View v) { CalculatorActivityLauncher.showVars(this); diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java b/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java index d9a60845..23036374 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorActivityLauncher.java @@ -29,6 +29,10 @@ public class CalculatorActivityLauncher { context.startActivity(new Intent(context, CalculatorFunctionsActivity.class)); } + public static void showOperators(@NotNull final Context context) { + context.startActivity(new Intent(context, CalculatorOperatorsActivity.class)); + } + public static void showVars(@NotNull final Context context) { context.startActivity(new Intent(context, CalculatorVarsActivity.class)); } diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java index 49f5ecb6..76c68d9d 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorModel.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorModel.java @@ -265,6 +265,10 @@ public enum CalculatorModel implements CursorControl, HistoryControl(CalculatorEngine.instance.getOperatorsRegistry().getEntities())); + setListAdapter(adapter); + + final ListView lv = getListView(); + lv.setTextFilterEnabled(true); + + lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { + public void onItemClick(final AdapterView parent, + final View view, + final int position, + final long id) { + + CalculatorModel.instance.processDigitButtonAction(((Operator) parent.getItemAtPosition(position)).getName(), false); + + CalculatorOperatorsActivity.this.finish(); + } + }); + + sort(); + + } + + private void sort() { + CalculatorOperatorsActivity.this.adapter.sort(new Comparator() { + @Override + public int compare(Operator operator1, Operator operator2) { + return operator1.getName().compareTo(operator2.getName()); + } + }); + + CalculatorOperatorsActivity.this.adapter.notifyDataSetChanged(); + } + + private class OperatorsArrayAdapter extends ArrayAdapter { + + private OperatorsArrayAdapter(Context context, int resource, int textViewResourceId, List objects) { + super(context, resource, textViewResourceId, objects); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final ViewGroup result = (ViewGroup) super.getView(position, convertView, parent); + + final Operator operator = getItem(position); + + final String operatorDescription = CalculatorEngine.instance.getOperatorsRegistry().getDescription(getContext(), operator.getName()); + if (!StringUtils.isEmpty(operatorDescription)) { + TextView description = (TextView) result.findViewById(R.id.var_description); + if (description == null) { + final LayoutInflater layoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); + final ViewGroup itemView = (ViewGroup) layoutInflater.inflate(R.layout.var, null); + description = (TextView) itemView.findViewById(R.id.var_description); + itemView.removeView(description); + result.addView(description); + } + description.setText(operatorDescription); + } else { + TextView description = (TextView) result.findViewById(R.id.var_description); + if (description != null) { + result.removeView(description); + } + } + + + return result; + } + } + + +} + diff --git a/src/main/java/org/solovyev/android/calculator/TextHighlighter.java b/src/main/java/org/solovyev/android/calculator/TextHighlighter.java index dae13291..34ccca9e 100644 --- a/src/main/java/org/solovyev/android/calculator/TextHighlighter.java +++ b/src/main/java/org/solovyev/android/calculator/TextHighlighter.java @@ -104,6 +104,7 @@ public class TextHighlighter implements TextProcessor { numberOfOpenGroupSymbols--; text1.append(text.charAt(i)); break; + case operator: case function: i = processHighlightedText(text1, i, mathType.getMatch(), "i"); break; diff --git a/src/main/java/org/solovyev/android/calculator/math/MathType.java b/src/main/java/org/solovyev/android/calculator/math/MathType.java index 3a4cc2dd..0fd4da6b 100644 --- a/src/main/java/org/solovyev/android/calculator/math/MathType.java +++ b/src/main/java/org/solovyev/android/calculator/math/MathType.java @@ -68,7 +68,7 @@ public enum MathType { open_group_symbol(800, true, false, "[", "(", "{") { @Override public boolean isNeedMultiplicationSignBefore(@NotNull MathType mathTypeBefore) { - return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function; + return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function && mathTypeBefore != operator; } @Override @@ -97,6 +97,14 @@ public enum MathType { } }, + operator(1050, true, true) { + @NotNull + @Override + public List getTokens() { + return CalculatorEngine.instance.getOperatorsRegistry().getNames(); + } + }, + constant(1100, true, true) { @NotNull @Override diff --git a/src/main/java/org/solovyev/android/calculator/model/AndroidFunctionsRegistry.java b/src/main/java/org/solovyev/android/calculator/model/AndroidMathRegistry.java similarity index 81% rename from src/main/java/org/solovyev/android/calculator/model/AndroidFunctionsRegistry.java rename to src/main/java/org/solovyev/android/calculator/model/AndroidMathRegistry.java index d5f687db..70e762c5 100644 --- a/src/main/java/org/solovyev/android/calculator/model/AndroidFunctionsRegistry.java +++ b/src/main/java/org/solovyev/android/calculator/model/AndroidMathRegistry.java @@ -10,6 +10,7 @@ import android.content.Context; import jscl.math.function.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.solovyev.common.math.MathEntity; import org.solovyev.common.math.MathRegistry; /** @@ -17,7 +18,7 @@ import org.solovyev.common.math.MathRegistry; * Date: 10/30/11 * Time: 1:02 AM */ -public interface AndroidFunctionsRegistry extends MathRegistry { +public interface AndroidMathRegistry extends MathRegistry { @Nullable String getDescription(@NotNull Context context, @NotNull String functionName); diff --git a/src/main/java/org/solovyev/android/calculator/model/AndroidFunctionsRegistryImpl.java b/src/main/java/org/solovyev/android/calculator/model/AndroidMathRegistryImpl.java similarity index 79% rename from src/main/java/org/solovyev/android/calculator/model/AndroidFunctionsRegistryImpl.java rename to src/main/java/org/solovyev/android/calculator/model/AndroidMathRegistryImpl.java index b4eb234c..5a362fc3 100644 --- a/src/main/java/org/solovyev/android/calculator/model/AndroidFunctionsRegistryImpl.java +++ b/src/main/java/org/solovyev/android/calculator/model/AndroidMathRegistryImpl.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.RClassUtils; import org.solovyev.common.definitions.IBuilder; +import org.solovyev.common.math.MathEntity; import org.solovyev.common.math.MathRegistry; import java.util.List; @@ -23,15 +24,15 @@ import java.util.Map; * Date: 10/30/11 * Time: 1:03 AM */ -public class AndroidFunctionsRegistryImpl implements AndroidFunctionsRegistry { +public class AndroidMathRegistryImpl implements AndroidMathRegistry { @NotNull private static final String FUNCTION_DESCRIPTION_PREFIX = "c_fun_description_"; @NotNull - private final MathRegistry functionsRegistry; + private final MathRegistry functionsRegistry; - public AndroidFunctionsRegistryImpl(@NotNull MathRegistry functionsRegistry) { + public AndroidMathRegistryImpl(@NotNull MathRegistry functionsRegistry) { this.functionsRegistry = functionsRegistry; } @@ -60,23 +61,23 @@ public class AndroidFunctionsRegistryImpl implements AndroidFunctionsRegistry { @NotNull @Override - public List getEntities() { + public List getEntities() { return functionsRegistry.getEntities(); } @NotNull @Override - public List getSystemEntities() { + public List getSystemEntities() { return functionsRegistry.getSystemEntities(); } @Override - public Function add(@NotNull IBuilder IBuilder) { + public T add(@NotNull IBuilder IBuilder) { return functionsRegistry.add(IBuilder); } @Override - public void remove(@NotNull Function var) { + public void remove(@NotNull T var) { functionsRegistry.remove(var); } @@ -92,12 +93,12 @@ public class AndroidFunctionsRegistryImpl implements AndroidFunctionsRegistry { } @Override - public Function get(@NotNull String name) { + public T get(@NotNull String name) { return functionsRegistry.get(name); } @Override - public Function getById(@NotNull Integer id) { + public T getById(@NotNull Integer id) { return functionsRegistry.getById(id); } } diff --git a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java index a40fab6a..625e18ee 100644 --- a/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java +++ b/src/main/java/org/solovyev/android/calculator/model/CalculatorEngine.java @@ -70,7 +70,10 @@ public enum CalculatorEngine { private final AndroidVarsRegistry varsRegister = new AndroidVarsRegistryImpl(engine.getConstantsRegistry()); @NotNull - private final AndroidFunctionsRegistry functionsRegistry = new AndroidFunctionsRegistryImpl(engine.getFunctionsRegistry()); + private final AndroidMathRegistry functionsRegistry = new AndroidMathRegistryImpl(engine.getFunctionsRegistry()); + + @NotNull + private final AndroidMathRegistry operatorsRegistry = new AndroidMathRegistryImpl(engine.getOperatorsRegistry()); private final MathRegistry postfixFunctionsRegistry = engine.getPostfixFunctionsRegistry(); @@ -156,7 +159,7 @@ public enum CalculatorEngine { sb.append(preparedExpression); //Log.d(CalculatorEngine.class.getName(), "Preprocessed expression: " + preprocessedExpression); - if (operation == JsclOperation.numeric && preparedExpression.isExistsUndefinedVar()) { + /*if (operation == JsclOperation.numeric && preparedExpression.isExistsUndefinedVar()) { operation = JsclOperation.simplify; if (mr != null) { @@ -169,7 +172,7 @@ public enum CalculatorEngine { mr.addMessage(new AndroidMessage(R.string.c_simplify_instead_of_numeric, MessageType.info, undefinedVars)); } - } + }*/ final String jsclExpression = sb.toString(); final JsclOperation finalOperation = operation; @@ -224,6 +227,9 @@ public enum CalculatorEngine { } if ( evalErrorLocal != null ) { + if ( finalOperation == JsclOperation.numeric && preparedExpression.isExistsUndefinedVar() ) { + return evaluate(JsclOperation.simplify, expression, mr); + } throw evalErrorLocal; } @@ -301,10 +307,15 @@ public enum CalculatorEngine { } @NotNull - public AndroidFunctionsRegistry getFunctionsRegistry() { + public AndroidMathRegistry getFunctionsRegistry() { return functionsRegistry; } + @NotNull + public AndroidMathRegistry getOperatorsRegistry() { + return operatorsRegistry; + } + @NotNull public MathRegistry getPostfixFunctionsRegistry() { return postfixFunctionsRegistry; diff --git a/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java b/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java index 58ab385a..feec68c0 100644 --- a/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/FromJsclSimplifyTextProcessor.java @@ -62,7 +62,7 @@ public class FromJsclSimplifyTextProcessor implements TextProcessor { } } else { - if (mathType.getMathType() == MathType.constant || mathType.getMathType() == MathType.function) { + if (mathType.getMathType() == MathType.constant || mathType.getMathType() == MathType.function || mathType.getMathType() == MathType.operator) { sb.append(mathType.getMatch()); i += mathType.getMatch().length() - 1; } else { diff --git a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java index 209adea6..1d8a44fe 100644 --- a/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java +++ b/src/main/java/org/solovyev/android/calculator/model/ToJsclTextProcessor.java @@ -54,7 +54,7 @@ class ToJsclTextProcessor implements TextProcessor { } } - if (mathTypeBefore == MathType.function && 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()); } @@ -80,28 +80,34 @@ class ToJsclTextProcessor implements TextProcessor { int offset = 0; String functionName = CollectionsUtils.find(MathType.function.getTokens(), startsWithFinder); if (functionName == null) { - String varName = CollectionsUtils.find(CalculatorEngine.instance.getVarsRegister().getNames(), startsWithFinder); - if (varName != null) { - final Var var = CalculatorEngine.instance.getVarsRegister().get(varName); - if (var != null) { - if (!var.isDefined()) { - undefinedVars.add(var); - result.append(varName); - offset = varName.length(); - } else { - final String value = var.getValue(); - assert value != null; - - if ( var.getDoubleValue() != null ) { - //result.append(value); - // NOTE: append varName as JSCL engine will convert it to double if needed + String operatorName = CollectionsUtils.find(MathType.operator.getTokens(), startsWithFinder); + if (operatorName == null) { + String varName = CollectionsUtils.find(CalculatorEngine.instance.getVarsRegister().getNames(), startsWithFinder); + if (varName != null) { + final Var var = CalculatorEngine.instance.getVarsRegister().get(varName); + if (var != null) { + if (!var.isDefined()) { + undefinedVars.add(var); result.append(varName); + offset = varName.length(); } else { - result.append("(").append(processWithDepth(value, depth, undefinedVars)).append(")"); + final String value = var.getValue(); + assert value != null; + + if ( var.getDoubleValue() != null ) { + //result.append(value); + // NOTE: append varName as JSCL engine will convert it to double if needed + result.append(varName); + } else { + result.append("(").append(processWithDepth(value, depth, undefinedVars)).append(")"); + } + offset = varName.length(); } - offset = varName.length(); } } + } else { + result.append(operatorName); + offset = operatorName.length(); } } else { result.append(functionName); diff --git a/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java b/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java index b8e30ef8..58bf8ff3 100644 --- a/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java +++ b/src/test/java/org/solovyev/android/calculator/model/CalculatorEngineTest.java @@ -113,7 +113,7 @@ public class CalculatorEngineTest { junit.framework.Assert.assertEquals("36.0", Expression.valueOf("3!^2").numeric().toString()); junit.framework.Assert.assertEquals("3.0", Expression.valueOf("cubic(27)").numeric().toString()); try { - junit.framework.Assert.assertEquals("i", cm.evaluate(JsclOperation.numeric, "i!").getResult()); + junit.framework.Assert.assertEquals("√(-1)!", cm.evaluate(JsclOperation.numeric, "i!").getResult()); fail(); } catch (ParseException e) { }