This commit is contained in:
serso 2011-10-16 15:11:33 +04:00
parent 6e45eb176c
commit 4e36d2779e
19 changed files with 205 additions and 105 deletions

View File

@ -21,17 +21,22 @@
</activity>
<activity a:name=".CalculatorPreferencesActivity"
a:label="@string/c_app_settings"/>
a:label="@string/c_app_settings"
a:configChanges="orientation|keyboardHidden"/>
<activity a:name=".CalculatorHistoryActivity"
a:label="@string/c_app_history"/>
a:label="@string/c_app_history"
a:configChanges="orientation|keyboardHidden">
</activity>
<activity a:name=".AboutActivity"
a:label="@string/c_about"/>
a:label="@string/c_about"
a:configChanges="orientation|keyboardHidden"/>
<activity a:name=".CalculatorVarsActivity"
a:label="@string/c_vars_and_constants"
a:configChanges="orientation|keyboardHidden"/>
a:configChanges="orientation|keyboardHidden">
</activity>
</application>
</manifest>

View File

@ -73,7 +73,7 @@
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<include layout="@layout/calc_equals_button"/>
<include layout="@layout/calc_history_button"/>
<include layout="@layout/calc_paste_button"/>
<include layout="@layout/calc_one_digit_button"/>
<include layout="@layout/calc_two_digit_button"/>
@ -85,7 +85,7 @@
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<include layout="@layout/calc_history_button"/>
<include layout="@layout/calc_vars_button"/>
<include layout="@layout/calc_copy_button"/>
<include layout="@layout/calc_four_digit_button"/>
<include layout="@layout/calc_five_digit_button"/>
@ -93,12 +93,11 @@
<include layout="@layout/calc_plus_button"/>
<include layout="@layout/calc_subtraction_button"/>
</LinearLayout>
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<include layout="@layout/calc_vars_button"/>
<include layout="@layout/calc_donate_button"/>
<include layout="@layout/calc_square_brackets_button"/>
<include layout="@layout/calc_seven_digit_button"/>
<include layout="@layout/calc_eight_digit_button"/>

View File

@ -17,15 +17,9 @@
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<include layout="@layout/calc_equals_button"
a:layout_weight="4"
a:layout_height="match_parent"
a:layout_width="match_parent" />
<include layout="@layout/calc_display"
a:layout_width="match_parent"
a:layout_height="match_parent"
a:layout_weight="1"/>
a:layout_height="match_parent"/>
</LinearLayout>

14
res/menu/history_menu.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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
-->
<menu xmlns:a="http://schemas.android.com/apk/res/android">
<item a:id="@+id/history_menu_clear_history"
a:title="@string/c_clear_history"/>
</menu>

View File

@ -82,5 +82,5 @@
<string name="c_calc_result_precision_summary">Точность результата(все вычисления производятся максимально точно)</string>
<string name="c_calc_color_display_summary">Включает/выключает подсветку синтаксиса в поле редактирования калькулятора</string>
<string name="c_calc_theme_summary">Устанавливает тему оформления приложения</string>
<string name="c_clear_history">Очистить историю</string>
</resources>

View File

@ -82,4 +82,5 @@
<string name="c_calc_result_precision_summary">Precision of result value (all calculations are done with maximum precision regardless of the value of this option)</string>
<string name="c_calc_color_display_summary">Enables/disables colouring and styling in calculator editor</string>
<string name="c_calc_theme_summary">Sets the theme for calculator</string>
<string name="c_clear_history">Clear history</string>
</resources>

View File

@ -67,6 +67,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
// ids of drag buttons in R.class
private List<Integer> dragButtonIds = null;
@NotNull
private final static Object broadcastReceiverLock = new Object();
/**
* Called when the activity is first created.
@ -83,7 +85,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
firstTimeInit();
init();
init(preferences);
dpclRegister.clear();
@ -100,9 +102,9 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
((DragButton) findViewById(R.id.leftButton)).setOnDragListener(toPositionOnDragListener);
dpclRegister.addListener(toPositionOnDragListener);
preferences.registerOnSharedPreferenceChangeListener(this);
CalculatorModel.instance.reset(this, preferences);
this.onSharedPreferenceChanged(preferences, null);
preferences.registerOnSharedPreferenceChangeListener(this);
}
private synchronized void setOnDragListeners(@NotNull SimpleOnDragListener.Preferences dragPreferences) {
@ -164,25 +166,31 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
setTheme(styleId);
}
private void init() {
private void init(@NotNull SharedPreferences preferences) {
calculatorView = new CalculatorView(this, CalculatorModel.instance);
synchronized (broadcastReceiverLock) {
calculatorView = new CalculatorView(this, preferences, CalculatorModel.instance);
}
textReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (broadcastReceiverLock) {
Log.d(this.getClass().getName(), "Intent received: " + intent.getAction());
if (INSERT_TEXT_INTENT.equals(intent.getAction())) {
final String s = intent.getStringExtra(INSERT_TEXT_INTENT_EXTRA_STRING);
Log.d(this.getClass().getName(), "Extra data: " + s);
if (!StringUtils.isEmpty(s)) {
calculatorView.doTextOperation(new CalculatorView.TextOperation() {
@Override
public void doOperation(@NotNull EditText editor) {
editor.getText().insert(editor.getSelectionStart(), s);
}
});
}, false);
}
} else if (SET_TEXT_INTENT.equals(intent.getAction())) {
final String s = intent.getStringExtra(SET_TEXT_INTENT_EXTRA_STRING);
Log.d(this.getClass().getName(), "Extra data: " + s);
if (!StringUtils.isEmpty(s)) {
calculatorView.doTextOperation(new CalculatorView.TextOperation() {
@Override
@ -190,7 +198,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
editor.setText(s);
calculatorView.setCursorOnEnd();
}
});
}, false);
}
}
}
}
@ -203,7 +212,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
private synchronized void firstTimeInit() {
if (!initialized) {
try {
CalculatorModel.instance.init(this);
CalculatorModel.instance.init(this, PreferenceManager.getDefaultSharedPreferences(this));
} catch (EvalError evalError) {
throw new RuntimeException("Could not initialize interpreter!");
}
@ -409,22 +418,27 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
super.onResume();
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final String newThemeName = preferences.getString(getString(R.string.p_calc_theme_key), getString(R.string.p_calc_theme));
if (!newThemeName.equals(themeName)) {
restart();
}
synchronized (broadcastReceiverLock) {
calculatorView = new CalculatorView(this, preferences, CalculatorModel.instance);
}
this.calculatorView.evaluate();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, @Nullable String s) {
dpclRegister.announce().onDragPreferencesChange(SimpleOnDragListener.getPreferences(preferences, this));
CalculatorModel.instance.reset(this);
CalculatorModel.instance.reset(this, preferences);
final Boolean colorExpressionsInBracketsDefault = new BooleanMapper().parseValue(this.getString(R.string.p_calc_color_display));
assert colorExpressionsInBracketsDefault != null;
this.calculatorView.getEditor().setHighlightText(preferences.getBoolean(this.getString(R.string.p_calc_color_display_key), colorExpressionsInBracketsDefault));
this.calculatorView.evaluate();
}
}

View File

@ -67,4 +67,12 @@ public class CalculatorDisplayHistoryState {
result = 31 * result + (editorHistoryState != null ? editorHistoryState.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "CalculatorDisplayHistoryState{" +
"valid=" + valid +
", editorHistoryState=" + editorHistoryState +
'}';
}
}

View File

@ -53,6 +53,11 @@ public class CalculatorEditor extends EditText {
menu.removeItem(android.R.id.startSelectingText);
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
}
public synchronized void redraw() {
String text = getText().toString();

View File

@ -75,4 +75,9 @@ public enum CalculatorHistory implements HistoryHelper<CalculatorHistoryState> {
public List<CalculatorHistoryState> getStates() {
return historyHelper.getStates();
}
@Override
public void clear() {
this.historyHelper.clear();
}
}

View File

@ -10,12 +10,13 @@ import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.*;
import android.widget.*;
import org.jetbrains.annotations.NotNull;
import org.solovyev.common.utils.*;
import org.solovyev.common.utils.Filter;
import org.solovyev.common.utils.FilterRule;
import org.solovyev.common.utils.FilterRulesChain;
import org.solovyev.common.utils.StringUtils;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -103,4 +104,33 @@ public class CalculatorHistoryActivity extends ListActivity {
return result;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
final MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.history_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean result;
switch (item.getItemId()) {
case R.id.history_menu_clear_history:
clearHistory();
result = true;
break;
default:
result = super.onOptionsItemSelected(item);
}
return result;
}
private void clearHistory() {
CalculatorHistory.instance.clear();
Toast.makeText(this, R.string.c_history_is_empty, Toast.LENGTH_SHORT).show();
this.finish();
}
}

View File

@ -43,4 +43,12 @@ public class CalculatorHistoryState extends AbstractHistoryState{
public void setDisplayState(@NotNull CalculatorDisplayHistoryState displayState) {
this.displayState = displayState;
}
@Override
public String toString() {
return "CalculatorHistoryState{" +
"editorState=" + editorState +
", displayState=" + displayState +
'}';
}
}

View File

@ -7,6 +7,7 @@ package org.solovyev.android.calculator;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.text.ClipboardManager;
import android.util.Log;
@ -22,6 +23,7 @@ import org.solovyev.android.calculator.model.CalculatorModel;
import org.solovyev.android.calculator.model.ParseException;
import org.solovyev.android.view.CursorControl;
import org.solovyev.android.view.HistoryControl;
import org.solovyev.common.BooleanMapper;
import org.solovyev.common.utils.MutableObject;
import org.solovyev.common.utils.StringUtils;
import org.solovyev.common.utils.history.HistoryAction;
@ -45,11 +47,15 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@NotNull
private final CalculatorModel calculatorModel;
public CalculatorView(@NotNull final Activity activity, @NotNull CalculatorModel calculator) {
public CalculatorView(@NotNull final Activity activity, @NotNull SharedPreferences preferences, @NotNull CalculatorModel calculator) {
this.calculatorModel = calculator;
this.editor = (CalculatorEditor) activity.findViewById(R.id.calculatorEditor);
final Boolean colorExpressionsInBracketsDefault = new BooleanMapper().parseValue(activity.getString(R.string.p_calc_color_display));
assert colorExpressionsInBracketsDefault != null;
this.editor.setHighlightText(preferences.getBoolean(activity.getString(R.string.p_calc_color_display_key), colorExpressionsInBracketsDefault));
this.display = (CalculatorDisplay) activity.findViewById(R.id.calculatorDisplay);
this.display.setOnClickListener(new View.OnClickListener() {
@Override
@ -83,7 +89,6 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
CalculatorHistory.instance.addState(getCurrentHistoryState());
}
public void setCursorOnStart() {
editor.setSelection(0);
}
@ -104,61 +109,75 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
}
}
@NotNull
private final MutableObject<Runnable> currentRunner = new MutableObject<Runnable>();
public void doTextOperation(@NotNull TextOperation operation) {
doTextOperation(operation, true);
}
public synchronized void doTextOperation(@NotNull TextOperation operation) {
public void doTextOperation(@NotNull TextOperation operation, boolean delayEvaluate) {
final String editorStateBefore = this.editor.getText().toString();
operation.doOperation(this.editor);
//Log.d(CalculatorView.class.getName(), "Doing text operation" + StringUtils.fromStackTrace(Thread.currentThread().getStackTrace()));
final String editorStateAfter = this.editor.getText().toString();
if (!editorStateBefore.equals(editorStateAfter)) {
editor.redraw();
currentRunner.setObject(new Runnable() {
evaluate(delayEvaluate, editorStateAfter);
}
}
@NotNull
private final static MutableObject<Runnable> pendingOperation = new MutableObject<Runnable>();
private void evaluate(boolean delayEvaluate, @NotNull final String expression) {
final CalculatorHistoryState historyState = getCurrentHistoryState();
pendingOperation.setObject(new Runnable() {
@Override
public void run() {
// allow only one runner at one time
synchronized (currentRunner) {
synchronized (pendingOperation) {
//lock all operations with history
synchronized (CalculatorHistory.instance) {
// do only if nothing was post delayed before current instance was posted
if (currentRunner.getObject() == this) {
if (pendingOperation.getObject() == this) {
// actually nothing shall be logged while text operations are done
evaluate(editorStateAfter);
evaluate(expression);
if (CalculatorHistory.instance.isUndoAvailable()) {
CalculatorHistory.instance.undo(getCurrentHistoryState());
}
historyState.setDisplayState(getCurrentHistoryState().getDisplayState());
saveHistoryState();
}
pendingOperation.setObject(null);
}
}
}
});
new Handler().postDelayed(currentRunner.getObject(), EVAL_DELAY_MILLIS);
saveHistoryState();
if (delayEvaluate) {
CalculatorHistory.instance.addState(historyState);
new Handler().postDelayed(pendingOperation.getObject(), EVAL_DELAY_MILLIS);
} else {
pendingOperation.getObject().run();
CalculatorHistory.instance.addState(historyState);
}
}
public void evaluate() {
evaluate(false, this.editor.getText().toString());
}
private void evaluate(@Nullable final String expression) {
if (!StringUtils.isEmpty(expression)) {
final CalculatorDisplay localDisplay = display;
if (!StringUtils.isEmpty(expression)) {
try {
Log.d(CalculatorView.class.getName(), "Trying to evaluate: " + expression);
Log.d(CalculatorView.class.getName(), "Trying to evaluate: " + expression /*+ StringUtils.fromStackTrace(Thread.currentThread().getStackTrace())*/);
localDisplay.setText(calculatorModel.evaluate(JsclOperation.numeric, expression));
} catch (EvalError e) {
handleEvaluationException(expression, localDisplay, e);
} catch (ParseException e) {
handleEvaluationException(expression, localDisplay, e);
}
} else {
localDisplay.setText("");
}
}
@ -176,10 +195,6 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
}
}
public void evaluate() {
evaluate(editor.getText().toString());
}
public void processDigitButtonAction(@Nullable final String text) {
//Toast.makeText(CalculatorActivity.this, text, Toast.LENGTH_SHORT).show();
@ -231,6 +246,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@Override
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
synchronized (CalculatorHistory.instance) {
Log.d(this.getClass().getName(), "Saved history found: " + editorHistoryState);
setValuesFromHistory(this.editor, editorHistoryState.getEditorState());
setValuesFromHistory(this.display, editorHistoryState.getDisplayState());

View File

@ -58,4 +58,12 @@ public class EditorHistoryState {
result = 31 * result + (text != null ? text.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "EditorHistoryState{" +
"cursorPosition=" + cursorPosition +
", text='" + text + '\'' +
'}';
}
}

View File

@ -7,14 +7,12 @@ package org.solovyev.android.calculator.model;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import bsh.EvalError;
import bsh.Interpreter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.JsclOperation;
import org.solovyev.common.NumberMapper;
import org.solovyev.common.utils.MutableObject;
/**
* User: serso
@ -68,24 +66,22 @@ public enum CalculatorModel {
this.numberOfFractionDigits = numberOfFractionDigits;
}
public void init(@Nullable Context context) throws EvalError {
public void init(@Nullable Context context, @Nullable SharedPreferences preferences) throws EvalError {
synchronized (lock) {
reset(context);
reset(context, preferences);
resetInterpreter();
}
}
public void reset(@Nullable Context context) {
public void reset(@Nullable Context context, @Nullable SharedPreferences preferences) {
synchronized (lock) {
if (context != null) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (preferences != null) {
final NumberMapper<Integer> integerNumberMapper = new NumberMapper<Integer>(Integer.class);
//noinspection ConstantConditions
this.setNumberOfFractionDigits(integerNumberMapper.parseValue(preferences.getString(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT)));
}
varsRegister.init(context);
varsRegister.init(context, preferences);
}
}

View File

@ -118,14 +118,12 @@ class VarsRegisterImpl implements VarsRegister {
vars.addAll(result);
}
synchronized void init(@Nullable Context context) {
synchronized void init(@Nullable Context context, @Nullable SharedPreferences preferences) {
this.vars.clear();
this.systemVars.clear();
if (context != null) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (context != null && preferences != null) {
final String value = preferences.getString(context.getString(R.string.p_calc_vars), null);
if (value != null) {
final Serializer serializer = new Persister();

View File

@ -20,7 +20,7 @@ public class MathTypeTest {
@BeforeClass
public static void setUp() throws Exception {
CalculatorModel.instance.init(null);
CalculatorModel.instance.init(null, null);
}
@Test

View File

@ -21,7 +21,7 @@ public class CalculatorModelTest {
@BeforeClass
public static void setUp() throws Exception {
CalculatorModel.instance.init(null);
CalculatorModel.instance.init(null, null);
}
@Test

View File

@ -9,7 +9,6 @@ package org.solovyev.android.calculator.model;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.solovyev.android.calculator.JsclOperation;
/**
* User: serso
@ -20,7 +19,7 @@ public class ToJsclTextProcessorTest {
@BeforeClass
public static void setUp() throws Exception {
CalculatorModel.instance.init(null);
CalculatorModel.instance.init(null, null);
}
@Test