This commit is contained in:
serso 2011-10-09 20:22:44 +04:00
parent cfe1adad08
commit 2c27a10540
23 changed files with 354 additions and 121 deletions

View File

@ -1,27 +1,33 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:a="http://schemas.android.com/apk/res/android" <manifest xmlns:a="http://schemas.android.com/apk/res/android"
package="org.solovyev.android.calculator" package="org.solovyev.android.calculator"
versionCode="1" versionCode="1"
versionName="1.0"> versionName="1.0">
<uses-sdk a:minSdkVersion="8"/> <uses-sdk a:minSdkVersion="8"/>
<application a:icon="@drawable/icon" a:label="@string/c_app_name"> <application a:icon="@drawable/icon" a:label="@string/c_app_name">
<activity a:name=".CalculatorActivity" a:label="@string/c_app_name"> <activity a:name=".CalculatorActivity"
<intent-filter> a:windowSoftInputMode="stateHidden"
<action a:name="android.intent.action.MAIN" /> a:label="@string/c_app_name">
<category a:name="android.intent.category.LAUNCHER" /> <intent-filter>
<action a:name="android.intent.action.MAIN"/>
<category a:name="android.intent.category.LAUNCHER"/>
<action a:name="org.solovyev.android.calculator.CalculatorActivity.insertText"/> <action a:name="org.solovyev.android.calculator.CalculatorActivity.insertText"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity a:name=".CalculatorPreferencesActivity" a:label="@string/c_app_settings"/> <activity a:name=".CalculatorPreferencesActivity"
<activity a:name=".AboutActivity" a:label="@string/c_about"/> a:label="@string/c_app_settings"/>
<activity a:name=".CalculatorVarsActivity"
a:label="@string/c_vars_and_constants"
a:configChanges="orientation|keyboardHidden" />
</application> <activity a:name=".AboutActivity"
a:label="@string/c_about"/>
<activity a:name=".CalculatorVarsActivity"
a:label="@string/c_vars_and_constants"
a:configChanges="orientation|keyboardHidden"/>
</application>
</manifest> </manifest>

BIN
res/drawable/copy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
res/drawable/heart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -17,73 +17,68 @@
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp"> <LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<org.solovyev.android.view.widgets.DirectionDragButton a:id="@+id/leftButton" <include layout="@layout/calc_left_button"
calc:textUp="↞" a:layout_width="match_parent"
a:text="←" a:layout_height="match_parent"
a:layout_weight="1.5" a:layout_weight="1.5"/>
style="@style/control_button_style"
a:onClick="moveLeftButtonClickHandler"/>
<org.solovyev.android.view.widgets.DirectionDragButton a:id="@+id/eraseButton" <include layout="@layout/calc_erase_button"
a:text="@string/c_erase" a:layout_width="match_parent"
a:layout_weight="1.5" a:layout_height="match_parent"
style="@style/control_button_style" a:layout_weight="1.5"/>
a:onClick="eraseButtonClickHandler"/>
<include layout="@layout/calc_display"/>
<org.solovyev.android.view.widgets.DirectionDragButton a:id="@+id/clearButton" <include layout="@layout/calc_display"
a:text="@string/c_clear" a:layout_width="match_parent"
a:layout_weight="1.5" a:layout_height="match_parent"
style="@style/control_button_style" a:layout_weight="1"/>
a:onClick="clearButtonClickHandler"/>
<org.solovyev.android.view.widgets.DirectionDragButton a:id="@+id/rightButton" <include layout="@layout/calc_clear_button"
calc:textUp="↠" a:layout_width="match_parent"
a:text="→" a:layout_height="match_parent"
a:layout_weight="1.5" a:layout_weight="1.5"/>
style="@style/control_button_style"
a:onClick="moveRightButtonClickHandler"/>
<include layout="@layout/calc_right_button"
a:layout_width="match_parent"
a:layout_height="match_parent"
a:layout_weight="1.5"/>
</LinearLayout> </LinearLayout>
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp"> <LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<include layout="@layout/calc_equals_button"/>
<include layout="@layout/calc_paste_button"/>
<include layout="@layout/calc_one_digit_button"/> <include layout="@layout/calc_one_digit_button"/>
<include layout="@layout/calc_two_digit_button"/> <include layout="@layout/calc_two_digit_button"/>
<include layout="@layout/calc_three_digit_button"/> <include layout="@layout/calc_three_digit_button"/>
<include layout="@layout/calc_multiplication_button"/> <include layout="@layout/calc_multiplication_button"/>
<include layout="@layout/calc_division_button"/> <include layout="@layout/calc_division_button"/>
<include layout="@layout/calc_equals_button"/>
<include layout="@layout/calc_paste_button"/>
</LinearLayout> </LinearLayout>
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp"> <LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<include layout="@layout/calc_history_button"/>
<include layout="@layout/calc_copy_button"/>
<include layout="@layout/calc_four_digit_button"/> <include layout="@layout/calc_four_digit_button"/>
<include layout="@layout/calc_five_digit_button"/> <include layout="@layout/calc_five_digit_button"/>
<include layout="@layout/calc_six_digit_button"/> <include layout="@layout/calc_six_digit_button"/>
<include layout="@layout/calc_plus_button"/> <include layout="@layout/calc_plus_button"/>
<include layout="@layout/calc_subtraction_button"/> <include layout="@layout/calc_subtraction_button"/>
<include layout="@layout/calc_square_brackets_button"/>
<include layout="@layout/calc_history_button"/>
</LinearLayout> </LinearLayout>
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp"> <LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<include layout="@layout/calc_vars_button"/>
<include layout="@layout/calc_square_brackets_button"/>
<include layout="@layout/calc_seven_digit_button"/> <include layout="@layout/calc_seven_digit_button"/>
<include layout="@layout/calc_eight_digit_button"/> <include layout="@layout/calc_eight_digit_button"/>
<include layout="@layout/calc_nine_digit_button"/> <include layout="@layout/calc_nine_digit_button"/>
<include layout="@layout/calc_zero_digit_button"/> <include layout="@layout/calc_zero_digit_button"/>
<include layout="@layout/calc_round_brackets_button"/> <include layout="@layout/calc_round_brackets_button"/>
<include layout="@layout/calc_vars_button"/>
<org.solovyev.android.view.widgets.DirectionDragButton a:text="" style="@style/control_button_style"/>
</LinearLayout> </LinearLayout>

View File

@ -17,15 +17,15 @@
<LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp"> <LinearLayout a:layout_weight="1" a:layout_width="match_parent" a:layout_height="0dp">
<org.solovyev.android.view.widgets.DirectionDragButton <include layout="@layout/calc_equals_button"
xmlns:a="http://schemas.android.com/apk/res/android" a:layout_weight="4"
a:id="@+id/equalsButton" a:layout_height="match_parent"
a:text="=" a:layout_width="match_parent" />
a:layout_weight="4"
style="@style/control_button_style"
a:onClick="numericButtonClickHandler"/>
<include layout="@layout/calc_display"/> <include layout="@layout/calc_display"
a:layout_width="match_parent"
a:layout_height="match_parent"
a:layout_weight="1"/>
</LinearLayout> </LinearLayout>
@ -65,7 +65,7 @@
<include layout="@layout/calc_zero_digit_button"/> <include layout="@layout/calc_zero_digit_button"/>
<include layout="@layout/calc_square_brackets_button"/> <include layout="@layout/calc_square_brackets_button"/>
<include layout="@layout/calc_subtraction_button"/> <include layout="@layout/calc_subtraction_button"/>
<include layout="@layout/calc_history_button"/> <include layout="@layout/calc_copy_button"/>
</LinearLayout> </LinearLayout>
@ -75,11 +75,8 @@
<include layout="@layout/calc_left_button"/> <include layout="@layout/calc_left_button"/>
<include layout="@layout/calc_right_button"/> <include layout="@layout/calc_right_button"/>
<include layout="@layout/calc_vars_button"/> <include layout="@layout/calc_vars_button"/>
<include layout="@layout/calc_donate_button"/>
<org.solovyev.android.view.widgets.DirectionDragButton a:text="" style="@style/control_button_style"/> <include layout="@layout/calc_history_button"/>
<org.solovyev.android.view.widgets.DirectionDragButton a:text="" style="@style/control_button_style"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,15 @@
<?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
-->
<ImageButton xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:calc="http://schemas.android.com/apk/res/org.solovyev.android.calculator"
a:id="@+id/pasteButton"
a:src="@drawable/copy"
style="@style/control_button_style"
a:padding="6dp"
a:onClick="copyButtonClickHandler"/>

View File

@ -8,7 +8,7 @@
<org.solovyev.android.calculator.CalculatorDisplay <org.solovyev.android.calculator.CalculatorDisplay
xmlns:a="http://schemas.android.com/apk/res/android" xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/resultEditText" a:id="@+id/calculatorDisplay"
style="@style/display_style" style="@style/display_style"
a:layout_weight="1" a:layout_weight="1"
a:minLines="1" a:minLines="1"

View File

@ -0,0 +1,15 @@
<?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
-->
<ImageButton xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:calc="http://schemas.android.com/apk/res/org.solovyev.android.calculator"
a:id="@+id/pasteButton"
a:src="@drawable/heart"
style="@style/control_button_style"
a:padding="6dp"
a:onClick="donateButtonClickHandler"/>

View File

@ -12,7 +12,7 @@
a:layout_height="0dp"> a:layout_height="0dp">
<org.solovyev.android.calculator.CalculatorEditor <org.solovyev.android.calculator.CalculatorEditor
a:id="@+id/editText" a:id="@+id/calculatorEditor"
style="@style/editor_style" style="@style/editor_style"
a:inputType="textMultiLine" a:inputType="textMultiLine"
a:maxLines="4" a:maxLines="4"

View File

@ -55,4 +55,5 @@
<string name="c_pi_description">Отношение длины окружности к диаметру</string> <string name="c_pi_description">Отношение длины окружности к диаметру</string>
<string name="c_e_description">Вещесвтенное число, такое что производная функции f(x) = e^x в точке x = 0 равно 1</string> <string name="c_e_description">Вещесвтенное число, такое что производная функции f(x) = e^x в точке x = 0 равно 1</string>
<string name="c_i_description">Мнимая единица, определённая как i^2 = 1</string> <string name="c_i_description">Мнимая единица, определённая как i^2 = 1</string>
<string name="c_calc_editor_hint">Введите новое выражение</string>
</resources> </resources>

View File

@ -58,5 +58,6 @@
<string name="c_pi_description">Ratio of any circle\'s circumference to its diameter</string> <string name="c_pi_description">Ratio of any circle\'s circumference to its diameter</string>
<string name="c_e_description">Unique real number such that the value of the derivative (slope of the tangent line) of the function f(x) = e^x at the point x = 0 is equal to 1</string> <string name="c_e_description">Unique real number such that the value of the derivative (slope of the tangent line) of the function f(x) = e^x at the point x = 0 is equal to 1</string>
<string name="c_i_description">Imaginary unit, defined such that i^2 = 1</string> <string name="c_i_description">Imaginary unit, defined such that i^2 = 1</string>
<string name="c_calc_editor_hint"></string> <string name="c_calc_editor_hint">Enter new expression</string>
<string name="c_press_to_copy">Press to copy</string>
</resources> </resources>

View File

@ -7,6 +7,7 @@ package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.content.*; import android.content.*;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.ClipboardManager; import android.text.ClipboardManager;
@ -100,6 +101,9 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
} }
private void init() { private void init() {
calculatorView = new CalculatorView(this, CalculatorModel.instance);
insertTextReceiver = new BroadcastReceiver() { insertTextReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -128,9 +132,6 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
// todo serso: create serso runtime exception // todo serso: create serso runtime exception
throw new RuntimeException("Could not initialize interpreter!"); throw new RuntimeException("Could not initialize interpreter!");
} }
this.calculatorView = new CalculatorView(this, CalculatorModel.instance);
initialized = true; initialized = true;
} }
} }
@ -191,6 +192,11 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
}); });
} }
@SuppressWarnings({"UnusedDeclaration"})
public void copyButtonClickHandler(@NotNull View v) {
calculatorView.copyResult(this);
}
@SuppressWarnings({"UnusedDeclaration"}) @SuppressWarnings({"UnusedDeclaration"})
public void clearButtonClickHandler(@NotNull View v) { public void clearButtonClickHandler(@NotNull View v) {
calculatorView.clear(); calculatorView.clear();
@ -207,6 +213,14 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
startActivity(new Intent(this, CalculatorVarsActivity.class)); startActivity(new Intent(this, CalculatorVarsActivity.class));
} }
@SuppressWarnings({"UnusedDeclaration"})
public void donateButtonClickHandler(@NotNull View v) {
final String paypalDonateUrl = "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=se%2esolovyev%40gmail%2ecom&lc=RU&item_name=android%2ecalculator%40se%2esolovyev&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted";
final Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(paypalDonateUrl));
startActivity(i);
}
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) { if (keyCode == KeyEvent.KEYCODE_BACK) {

View File

@ -5,6 +5,7 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
/** /**
@ -12,19 +13,24 @@ import org.jetbrains.annotations.Nullable;
* Date: 9/17/11 * Date: 9/17/11
* Time: 11:05 PM * Time: 11:05 PM
*/ */
public class CalculatorDisplayHistoryState extends EditorHistoryState { public class CalculatorDisplayHistoryState {
private boolean valid = true; private boolean valid = true;
@NotNull
private final EditorHistoryState editorHistoryState;
public CalculatorDisplayHistoryState() { public CalculatorDisplayHistoryState() {
this.editorHistoryState = new EditorHistoryState();
} }
public CalculatorDisplayHistoryState(boolean valid) { public CalculatorDisplayHistoryState(boolean valid) {
this.editorHistoryState = new EditorHistoryState();
this.valid = valid; this.valid = valid;
} }
public CalculatorDisplayHistoryState(int cursorPosition, @Nullable String text, boolean valid) { public CalculatorDisplayHistoryState(int cursorPosition, @Nullable String text, boolean valid) {
super(cursorPosition, text); this.editorHistoryState = new EditorHistoryState(cursorPosition, text);
this.valid = valid; this.valid = valid;
} }
@ -35,4 +41,29 @@ public class CalculatorDisplayHistoryState extends EditorHistoryState {
public void setValid(boolean valid) { public void setValid(boolean valid) {
this.valid = valid; this.valid = valid;
} }
public EditorHistoryState getEditorHistoryState() {
return editorHistoryState;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CalculatorDisplayHistoryState)) return false;
CalculatorDisplayHistoryState that = (CalculatorDisplayHistoryState) o;
if (valid != that.valid) return false;
if (editorHistoryState != null ? !editorHistoryState.equals(that.editorHistoryState) : that.editorHistoryState != null)
return false;
return true;
}
@Override
public int hashCode() {
int result = (valid ? 1 : 0);
result = 31 * result + (editorHistoryState != null ? editorHistoryState.hashCode() : 0);
return result;
}
} }

View File

@ -0,0 +1,72 @@
/*
* 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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.common.utils.history.HistoryAction;
import org.solovyev.common.utils.history.HistoryHelper;
import org.solovyev.common.utils.history.SimpleHistoryHelper;
/**
* User: serso
* Date: 10/9/11
* Time: 6:35 PM
*/
public enum CalculatorHistory implements HistoryHelper<CalculatorHistoryState> {
instance;
private final HistoryHelper<CalculatorHistoryState> historyHelper = new SimpleHistoryHelper<CalculatorHistoryState>();
@Override
public boolean isEmpty() {
return this.historyHelper.isEmpty();
}
@Override
public CalculatorHistoryState getLastHistoryState() {
return this.historyHelper.getLastHistoryState();
}
@Override
public boolean isUndoAvailable() {
return historyHelper.isUndoAvailable();
}
@Override
public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) {
return historyHelper.undo(currentState);
}
@Override
public boolean isRedoAvailable() {
return historyHelper.isRedoAvailable();
}
@Override
public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) {
return historyHelper.redo(currentState);
}
@Override
public boolean isActionAvailable(@NotNull HistoryAction historyAction) {
return historyHelper.isActionAvailable(historyAction);
}
@Override
public CalculatorHistoryState doAction(@NotNull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) {
return historyHelper.doAction(historyAction, currentState);
}
@Override
public void addState(@Nullable CalculatorHistoryState currentState) {
historyHelper.addState(currentState);
}
}

View File

@ -6,6 +6,7 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.os.Handler; import android.os.Handler;
import android.text.ClipboardManager; import android.text.ClipboardManager;
import android.util.Log; import android.util.Log;
@ -21,11 +22,10 @@ import org.solovyev.android.calculator.model.CalculatorModel;
import org.solovyev.android.calculator.model.ParseException; import org.solovyev.android.calculator.model.ParseException;
import org.solovyev.android.view.CursorControl; import org.solovyev.android.view.CursorControl;
import org.solovyev.android.view.HistoryControl; import org.solovyev.android.view.HistoryControl;
import org.solovyev.android.view.widgets.SoftKeyboardDisabler;
import org.solovyev.common.utils.MutableObject; import org.solovyev.common.utils.MutableObject;
import org.solovyev.common.utils.StringUtils; import org.solovyev.common.utils.StringUtils;
import org.solovyev.common.utils.history.HistoryAction; import org.solovyev.common.utils.history.HistoryAction;
import org.solovyev.common.utils.history.HistoryHelper;
import org.solovyev.common.utils.history.SimpleHistoryHelper;
/** /**
* User: serso * User: serso
@ -46,35 +46,43 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@NotNull @NotNull
private final CalculatorModel calculatorModel; private final CalculatorModel calculatorModel;
@NotNull
private final HistoryHelper<CalculatorHistoryState> history;
public CalculatorView(@NotNull final Activity activity, @NotNull CalculatorModel calculator) { public CalculatorView(@NotNull final Activity activity, @NotNull CalculatorModel calculator) {
this.calculatorModel = calculator; this.calculatorModel = calculator;
this.editor = (CalculatorEditor) activity.findViewById(R.id.editText); this.editor = (CalculatorEditor) activity.findViewById(R.id.calculatorEditor);
this.editor.setOnTouchListener(new SoftKeyboardDisabler());
this.display = (CalculatorDisplay) activity.findViewById(R.id.resultEditText); this.display = (CalculatorDisplay) activity.findViewById(R.id.calculatorDisplay);
this.display.setOnClickListener(new View.OnClickListener() { this.display.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (((CalculatorDisplay) v).isValid()) { copyResult(activity);
final CharSequence text = ((TextView) v).getText();
if (!StringUtils.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text);
Toast.makeText(activity, activity.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show();
}
}
} }
}); });
this.history = new SimpleHistoryHelper<CalculatorHistoryState>();
saveHistoryState(); final CalculatorHistoryState lastState = CalculatorHistory.instance.getLastHistoryState();
if ( lastState == null ) {
saveHistoryState();
} else {
setCurrentHistoryState(lastState);
}
}
public void copyResult(@NotNull Context context) {
if (display.isValid()) {
final CharSequence text = display.getText();
if (!StringUtils.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text);
Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show();
}
}
} }
private void saveHistoryState() { private void saveHistoryState() {
history.addState(getCurrentHistoryState()); CalculatorHistory.instance.addState(getCurrentHistoryState());
} }
@ -117,14 +125,14 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
// allow only one runner at one time // allow only one runner at one time
synchronized (currentRunner) { synchronized (currentRunner) {
//lock all operations with history //lock all operations with history
synchronized (history) { synchronized (CalculatorHistory.instance) {
// do only if nothing was post delayed before current instance was posted // do only if nothing was post delayed before current instance was posted
if (currentRunner.getObject() == this) { if (currentRunner.getObject() == this) {
// actually nothing shall be logged while text operations are done // actually nothing shall be logged while text operations are done
evaluate(editorStateAfter); evaluate(editorStateAfter);
if (history.isUndoAvailable()) { if (CalculatorHistory.instance.isUndoAvailable()) {
history.undo(getCurrentHistoryState()); CalculatorHistory.instance.undo(getCurrentHistoryState());
} }
saveHistoryState(); saveHistoryState();
@ -212,9 +220,9 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@Override @Override
public void doHistoryAction(@NotNull HistoryAction historyAction) { public void doHistoryAction(@NotNull HistoryAction historyAction) {
synchronized (history) { synchronized (CalculatorHistory.instance) {
if (history.isActionAvailable(historyAction)) { if (CalculatorHistory.instance.isActionAvailable(historyAction)) {
final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState()); final CalculatorHistoryState newState = CalculatorHistory.instance.doAction(historyAction, getCurrentHistoryState());
if (newState != null) { if (newState != null) {
setCurrentHistoryState(newState); setCurrentHistoryState(newState);
} }
@ -224,7 +232,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@Override @Override
public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) { public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) {
synchronized (history) { synchronized (CalculatorHistory.instance) {
setValuesFromHistory(this.editor, editorHistoryState.getEditorState()); setValuesFromHistory(this.editor, editorHistoryState.getEditorState());
setValuesFromHistory(this.display, editorHistoryState.getDisplayState()); setValuesFromHistory(this.display, editorHistoryState.getDisplayState());
@ -233,7 +241,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
} }
private void setValuesFromHistory(@NotNull CalculatorDisplay display, CalculatorDisplayHistoryState editorHistoryState) { private void setValuesFromHistory(@NotNull CalculatorDisplay display, CalculatorDisplayHistoryState editorHistoryState) {
setValuesFromHistory(display, (EditorHistoryState)editorHistoryState); setValuesFromHistory(display, editorHistoryState.getEditorHistoryState());
display.setValid(editorHistoryState.isValid()); display.setValid(editorHistoryState.isValid());
} }
@ -247,7 +255,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@Override @Override
@NotNull @NotNull
public CalculatorHistoryState getCurrentHistoryState() { public CalculatorHistoryState getCurrentHistoryState() {
synchronized (history) { synchronized (CalculatorHistory.instance) {
return new CalculatorHistoryState(getEditorHistoryState(this.editor), getCalculatorDisplayHistoryState(this.display)); return new CalculatorHistoryState(getEditorHistoryState(this.editor), getCalculatorDisplayHistoryState(this.display));
} }
} }
@ -264,8 +272,8 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
private CalculatorDisplayHistoryState getCalculatorDisplayHistoryState(@NotNull CalculatorDisplay display) { private CalculatorDisplayHistoryState getCalculatorDisplayHistoryState(@NotNull CalculatorDisplay display) {
final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState(); final CalculatorDisplayHistoryState result = new CalculatorDisplayHistoryState();
result.setText(String.valueOf(display.getText())); result.getEditorHistoryState().setText(String.valueOf(display.getText()));
result.setCursorPosition(display.getSelectionStart()); result.getEditorHistoryState().setCursorPosition(display.getSelectionStart());
result.setValid(display.isValid()); result.setValid(display.isValid());
return result; return result;

View File

@ -39,5 +39,23 @@ public class EditorHistoryState {
return cursorPosition; 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;
}
} }

View File

@ -37,11 +37,13 @@ public class Functions {
public final static String EXP = "exp"; public final static String EXP = "exp";
public final static String SQRT_SIGN = ""; public final static String SQRT_SIGN = "";
public final static String SQRT = "sqrt"; public final static String SQRT = "sqrt";
public final static String E = "E";
public final static String E_POWER = "10^";
public static final List<String> allPrefix; public static final List<String> allPrefix;
static { static {
final List<String> functions = new ArrayList<String>(Arrays.asList(SIN, SINH, ASIN, ASINH, COS, COSH, ACOS, ACOSH, TAN, TANH, ATAN, ATANH, LOG, LN, MOD, SQRT, SQRT_SIGN, EXP)); final List<String> functions = new ArrayList<String>(Arrays.asList(SIN, SINH, ASIN, ASINH, COS, COSH, ACOS, ACOSH, TAN, TANH, ATAN, ATANH, LOG, LN, MOD, SQRT, SQRT_SIGN, EXP, E));
Collections.sort(functions, new MathEntityComparator()); Collections.sort(functions, new MathEntityComparator());
allPrefix = functions; allPrefix = functions;
} }

View File

@ -39,10 +39,10 @@ class ToJsclTextProcessor implements TextProcessor {
sb.append(')'); sb.append(')');
} else if (ch == '×' || ch == '∙') { } else if (ch == '×' || ch == '∙') {
sb.append("*"); sb.append("*");
} else if ( mathType == MathType.function ){ } else if (mathType == MathType.function) {
sb.append(toJsclFunction(mathTypeResult.getMatch())); sb.append(toJsclFunction(mathTypeResult.getMatch()));
i += mathTypeResult.getMatch().length() - 1; i += mathTypeResult.getMatch().length() - 1;
} else if ( mathType == MathType.constant ) { } else if (mathType == MathType.constant) {
sb.append(mathTypeResult.getMatch()); sb.append(mathTypeResult.getMatch());
i += mathTypeResult.getMatch().length() - 1; i += mathTypeResult.getMatch().length() - 1;
} else { } else {
@ -148,6 +148,8 @@ class ToJsclTextProcessor implements TextProcessor {
result = Functions.LOG; result = Functions.LOG;
} else if (function.equals(Functions.SQRT_SIGN)) { } else if (function.equals(Functions.SQRT_SIGN)) {
result = Functions.SQRT; result = Functions.SQRT;
} else if (function.equals(Functions.E)) {
result = Functions.E_POWER;
} else { } else {
result = function; result = function;
} }
@ -178,9 +180,9 @@ class ToJsclTextProcessor implements TextProcessor {
@NotNull @NotNull
private static MathType.Result checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb, private static MathType.Result checkMultiplicationSignBeforeFunction(@NotNull StringBuilder sb,
@NotNull String s, @NotNull String s,
int i, int i,
@Nullable MathType.Result mathTypeBeforeResult) { @Nullable MathType.Result mathTypeBeforeResult) {
MathType.Result result = MathType.getType(s, i); MathType.Result result = MathType.getType(s, i);
if (i > 0) { if (i > 0) {

View File

@ -13,8 +13,6 @@ import android.text.TextPaint;
import android.util.AttributeSet; import android.util.AttributeSet;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.view.widgets.DragButton;
import org.solovyev.android.view.widgets.DragDirection;
import org.solovyev.common.utils.Point2d; import org.solovyev.common.utils.Point2d;
import org.solovyev.common.utils.StringUtils; import org.solovyev.common.utils.StringUtils;
@ -101,11 +99,11 @@ public class DirectionDragButton extends DragButton {
initUpDownTextPaint(basePaint); initUpDownTextPaint(basePaint);
if (textUp != null) { if (textUp != null) {
textUpPosition = getTextPosition(upDownTextPaint, basePaint, textUp, 1); textUpPosition = getTextPosition(upDownTextPaint, basePaint, textUp, getText(), 1, getWidth(), getHeight());
} }
if (textDown != null) { if (textDown != null) {
textDownPosition = getTextPosition(upDownTextPaint, basePaint, textDown, -1); textDownPosition = getTextPosition(upDownTextPaint, basePaint, textDown, getText(), -1, getWidth(), getHeight());
} }
if ( textDownPosition != null && textUpPosition != null ) { if ( textDownPosition != null && textUpPosition != null ) {
@ -118,21 +116,21 @@ public class DirectionDragButton extends DragButton {
} }
private Point2d getTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, float direction) { public static Point2d getTextPosition(@NotNull Paint paint, @NotNull Paint basePaint, @NotNull CharSequence text, CharSequence baseText, float direction, int w, int h) {
final Point2d result = new Point2d(); final Point2d result = new Point2d();
float width = paint.measureText(text.toString() + " "); float width = paint.measureText(text.toString() + " ");
result.setX(getWidth() - width); result.setX(w - width);
float selfHeight = paint.ascent() + paint.descent(); float selfHeight = paint.ascent() + paint.descent();
basePaint.measureText(StringUtils.getNotEmpty(getText(), "|")); basePaint.measureText(StringUtils.getNotEmpty(baseText, "|"));
float height = getHeight() - basePaint.ascent() - basePaint.descent(); float height = h - basePaint.ascent() - basePaint.descent();
if (direction < 0) { if (direction < 0) {
result.setY(height / 2 - direction * height / 3 + selfHeight); result.setY(height / 2 + height / 3 + selfHeight);
} else { } else {
result.setY(height / 2 - direction * height / 3); result.setY(height / 2 - height / 3);
} }
return result; return result;

View File

@ -0,0 +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.view.widgets;
import android.text.InputType;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;
/**
* User: serso
* Date: 10/9/11
* Time: 4:27 PM
*/
public class SoftKeyboardDisabler implements View.OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean result;
Log.d(this.getClass().getName(), "org.solovyev.android.view.widgets.SoftKeyboardDisabler.onTouch(): action=" + event.getAction() + ", event=" + event);
if (v instanceof EditText) {
final EditText editText = (EditText) v;
int inputType = editText.getInputType();
int selectionStart = editText.getSelectionStart();
int selectionEnd = editText.getSelectionEnd();
// disable soft input
editText.setInputType(InputType.TYPE_NULL);
editText.onTouchEvent(event);
// restore input type
editText.setInputType(inputType);
editText.setSelection(selectionStart, selectionEnd);
result = true;
} else {
result = false;
}
return result;
}
}

View File

@ -7,6 +7,7 @@
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
/** /**
@ -16,16 +17,23 @@ import org.junit.Test;
*/ */
public class ToJsclPreprocessorTest { public class ToJsclPreprocessorTest {
@BeforeClass
public static void setUp() throws Exception {
CalculatorModel.instance.init(null);
}
@Test @Test
public void testProcess() throws Exception { public void testProcess() throws Exception {
final ToJsclTextProcessor preprocessor = new ToJsclTextProcessor(); final ToJsclTextProcessor preprocessor = new ToJsclTextProcessor();
Assert.assertEquals( "sin(4)*cos(5)", preprocessor.process("sin(4)cos(5)")); Assert.assertEquals( "sin(4)*cos(5)", preprocessor.process("sin(4)cos(5)"));
Assert.assertEquals( "pi*sin(4)*pi*cos(sqrt(5))", preprocessor.process("πsin(4)πcos(√(5))")); Assert.assertEquals( "3.141592653589793*sin(4)*3.141592653589793*cos(sqrt(5))", preprocessor.process("πsin(4)πcos(√(5))"));
Assert.assertEquals( "pi*sin(4)+pi*cos(sqrt(5))", preprocessor.process("πsin(4)+πcos(√(5))")); Assert.assertEquals( "3.141592653589793*sin(4)+3.141592653589793*cos(sqrt(5))", preprocessor.process("πsin(4)+πcos(√(5))"));
Assert.assertEquals( "pi*sin(4)+pi*cos(sqrt(5+sqrt(-1)))", preprocessor.process("πsin(4)+πcos(√(5+i))")); Assert.assertEquals( "3.141592653589793*sin(4)+3.141592653589793*cos(sqrt(5+sqrt(-1)))", preprocessor.process("πsin(4)+πcos(√(5+i))"));
Assert.assertEquals( "pi*sin(4.01)+pi*cos(sqrt(5+sqrt(-1)))", preprocessor.process("πsin(4.01)+πcos(√(5+i))")); Assert.assertEquals( "3.141592653589793*sin(4.01)+3.141592653589793*cos(sqrt(5+sqrt(-1)))", preprocessor.process("πsin(4.01)+πcos(√(5+i))"));
Assert.assertEquals( "exp(1)^pi*sin(4.01)+pi*cos(sqrt(5+sqrt(-1)))", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))")); Assert.assertEquals( "2.718281828459045^3.141592653589793*sin(4.01)+3.141592653589793*cos(sqrt(5+sqrt(-1)))", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))"));
Assert.assertEquals( "2.718281828459045^3.141592653589793*sin(4.01)+3.141592653589793*cos(sqrt(5+sqrt(-1)))*10^2", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))E2"));
Assert.assertEquals( "2.718281828459045^3.141592653589793*sin(4.01)+3.141592653589793*cos(sqrt(5+sqrt(-1)))*10^-2", preprocessor.process("e^πsin(4.01)+πcos(√(5+i))E-2"));
} }
@Test @Test
@ -44,7 +52,7 @@ public class ToJsclPreprocessorTest {
Assert.assertEquals(4, preprocessor.getPostfixFunctionStart("2.23+(5.4434234*sin(5.1+1))!", 26)); Assert.assertEquals(4, preprocessor.getPostfixFunctionStart("2.23+(5.4434234*sin(5.1+1))!", 26));
Assert.assertEquals(0, preprocessor.getPostfixFunctionStart("sin(5)!", 5)); Assert.assertEquals(0, preprocessor.getPostfixFunctionStart("sin(5)!", 5));
Assert.assertEquals(0, preprocessor.getPostfixFunctionStart("sin(5sin(5sin(5)))!", 17)); Assert.assertEquals(0, preprocessor.getPostfixFunctionStart("sin(5sin(5sin(5)))!", 17));
Assert.assertEquals(1, preprocessor.getPostfixFunctionStart("2+sin(5sin(5sin(5)))!", 19)); Assert.assertEquals(2, preprocessor.getPostfixFunctionStart("2+sin(5sin(5sin(5)))!", 19));
Assert.assertEquals(4, preprocessor.getPostfixFunctionStart("2.23+sin(5.4434234*sin(5.1+1))!", 29)); Assert.assertEquals(5, preprocessor.getPostfixFunctionStart("2.23+sin(5.4434234*sin(5.1+1))!", 29));
} }
} }