Fixes dut library update

This commit is contained in:
serso 2012-09-20 11:59:43 +04:00
parent cf9a609d6b
commit f909b49c7c
6 changed files with 1697 additions and 1672 deletions

View File

@ -1,186 +1,186 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:range="http://schemas.android.com/apk/res/org.solovyev.android.calculator"> xmlns:range="http://schemas.android.com/apk/res-auto">
<Preference <Preference
a:key="@string/p_calc_ad_free_key" a:key="@string/p_calc_ad_free_key"
a:title="@string/c_calc_ad_free_title" a:title="@string/c_calc_ad_free_title"
a:summary="@string/c_calc_ad_free_summary" a:summary="@string/c_calc_ad_free_summary"
a:defaultValue="false" a:defaultValue="false"
/> />
<org.solovyev.android.ads.AdViewPreference <org.solovyev.android.ads.AdViewPreference
a:key="admob_01" a:key="admob_01"
a:layout="@layout/admob_pref"/> a:layout="@layout/admob_pref"/>
<PreferenceScreen a:title="@string/c_prefs_calculations_category"> <PreferenceScreen a:title="@string/c_prefs_calculations_category">
<org.solovyev.android.ads.AdViewPreference <org.solovyev.android.ads.AdViewPreference
a:key="admob_02" a:key="admob_02"
a:layout="@layout/admob_pref"/> a:layout="@layout/admob_pref"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="@string/p_calc_round_result_key" a:key="@string/p_calc_round_result_key"
a:summary="@string/c_calc_round_result_summary" a:summary="@string/c_calc_round_result_summary"
a:title="@string/c_calc_round_result_title" a:title="@string/c_calc_round_result_title"
a:defaultValue="true"/> a:defaultValue="true"/>
<org.solovyev.android.prefs.NumberPickerDialogPreference <org.solovyev.android.prefs.IntegerPickerDialogPreference
a:key="@string/p_calc_result_precision_key" a:key="@string/p_calc_result_precision_key"
a:title="@string/p_calc_result_precision_title" a:title="@string/p_calc_result_precision_title"
a:summary="@string/c_calc_result_precision_summary" a:summary="@string/c_calc_result_precision_summary"
a:defaultValue="5" a:defaultValue="5"
range:boundaries="0;16"/> range:boundaries="0;16"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="@string/p_calc_science_notation_key" a:key="@string/p_calc_science_notation_key"
a:summary="@string/c_calc_science_notation_summary" a:summary="@string/c_calc_science_notation_summary"
a:title="@string/c_calc_science_notation_title" a:title="@string/c_calc_science_notation_title"
a:defaultValue="false"/> a:defaultValue="false"/>
<ListPreference a:key="@string/p_calc_grouping_separator_key" <ListPreference a:key="@string/p_calc_grouping_separator_key"
a:title="@string/c_calc_grouping_separator" a:title="@string/c_calc_grouping_separator"
a:entries="@array/p_grouping_separator_names" a:entries="@array/p_grouping_separator_names"
a:summary="@string/c_calc_grouping_separator_summary" a:summary="@string/c_calc_grouping_separator_summary"
a:entryValues="@array/p_grouping_separator_values"/> a:entryValues="@array/p_grouping_separator_values"/>
<ListPreference a:key="@string/p_calc_angle_units_key" <ListPreference a:key="@string/p_calc_angle_units_key"
a:title="@string/c_calc_angle_units" a:title="@string/c_calc_angle_units"
a:entries="@array/p_angle_units_names" a:entries="@array/p_angle_units_names"
a:summary="@string/c_angle_units_summary" a:summary="@string/c_angle_units_summary"
a:entryValues="@array/p_angle_units"/> a:entryValues="@array/p_angle_units"/>
<ListPreference a:key="@string/p_calc_numeral_bases_key" <ListPreference a:key="@string/p_calc_numeral_bases_key"
a:title="@string/c_calc_numeral_bases" a:title="@string/c_calc_numeral_bases"
a:entries="@array/p_numeral_bases_names" a:entries="@array/p_numeral_bases_names"
a:summary="@string/c_numeral_bases_summary" a:summary="@string/c_numeral_bases_summary"
a:entryValues="@array/p_numeral_bases"/> a:entryValues="@array/p_numeral_bases"/>
<org.solovyev.android.prefs.NumberPickerDialogPreference <org.solovyev.android.prefs.IntegerPickerDialogPreference
a:key="@string/p_calc_max_calculation_time_key" a:key="@string/p_calc_max_calculation_time_key"
a:title="@string/p_calc_max_calculation_time_title" a:title="@string/p_calc_max_calculation_time_title"
a:summary="@string/p_calc_max_calculation_time_summary" a:summary="@string/p_calc_max_calculation_time_summary"
a:defaultValue="5" a:defaultValue="5"
range:boundaries="3;1000"/> range:boundaries="3;1000"/>
</PreferenceScreen> </PreferenceScreen>
<PreferenceScreen <PreferenceScreen
a:title="@string/c_prefs_appearance_category"> a:title="@string/c_prefs_appearance_category">
<org.solovyev.android.ads.AdViewPreference <org.solovyev.android.ads.AdViewPreference
a:key="admob_03" a:key="admob_03"
a:layout="@layout/admob_pref"/> a:layout="@layout/admob_pref"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="@string/p_calc_color_display_key" a:key="@string/p_calc_color_display_key"
a:summary="@string/c_calc_color_display_summary" a:summary="@string/c_calc_color_display_summary"
a:title="@string/c_calc_color_display_title" a:title="@string/c_calc_color_display_title"
a:defaultValue="true"/> a:defaultValue="true"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="@string/p_calc_haptic_feedback_key" a:key="@string/p_calc_haptic_feedback_key"
a:summary="@string/c_calc_haptic_feedback_summary" a:summary="@string/c_calc_haptic_feedback_summary"
a:title="@string/c_calc_haptic_feedback_title" a:title="@string/c_calc_haptic_feedback_title"
a:defaultValue="false"/> a:defaultValue="false"/>
<ListPreference a:key="@string/p_calc_haptic_feedback_duration_key" <ListPreference a:key="@string/p_calc_haptic_feedback_duration_key"
a:title="@string/p_calc_haptic_feedback_duration_title" a:title="@string/p_calc_haptic_feedback_duration_title"
a:entries="@array/p_calc_haptic_feedback_duration_names" a:entries="@array/p_calc_haptic_feedback_duration_names"
a:summary="@string/p_calc_haptic_feedback_duration_summary" a:summary="@string/p_calc_haptic_feedback_duration_summary"
a:entryValues="@array/p_calc_haptic_feedback_duration_values"/> a:entryValues="@array/p_calc_haptic_feedback_duration_values"/>
<ListPreference a:key="@string/p_calc_multiplication_sign_key" <ListPreference a:key="@string/p_calc_multiplication_sign_key"
a:title="@string/c_calc_multiplication_sign" a:title="@string/c_calc_multiplication_sign"
a:entries="@array/p_multiplication_sign_values" a:entries="@array/p_multiplication_sign_values"
a:summary="@string/c_calc_multiplication_sign_summary" a:summary="@string/c_calc_multiplication_sign_summary"
a:entryValues="@array/p_multiplication_sign_values"/> a:entryValues="@array/p_multiplication_sign_values"/>
<ListPreference a:key="@string/p_calc_theme_key" <ListPreference a:key="@string/p_calc_theme_key"
a:title="@string/c_calc_theme" a:title="@string/c_calc_theme"
a:entries="@array/p_theme_names" a:entries="@array/p_theme_names"
a:summary="@string/c_calc_theme_summary" a:summary="@string/c_calc_theme_summary"
a:entryValues="@array/p_theme_values"/> a:entryValues="@array/p_theme_values"/>
<ListPreference a:key="@string/p_calc_layout_key" <ListPreference a:key="@string/p_calc_layout_key"
a:title="@string/c_calc_layout" a:title="@string/c_calc_layout"
a:entries="@array/p_layout_names" a:entries="@array/p_layout_names"
a:summary="@string/c_calc_layout_summary" a:summary="@string/c_calc_layout_summary"
a:entryValues="@array/p_layout_values"/> a:entryValues="@array/p_layout_values"/>
<org.solovyev.android.prefs.FloatRangeSeekBarPreference <org.solovyev.android.prefs.FloatRangeSeekBarPreference
a:key="@string/p_drag_distance_key" a:key="@string/p_drag_distance_key"
a:title="@string/c_swipe_distance" a:title="@string/c_swipe_distance"
a:summary="@string/c_swipe_distance_summary" a:summary="@string/c_swipe_distance_summary"
a:text=" pxs" a:text=" pxs"
a:defaultValue="35;350" a:defaultValue="35;350"
range:step="10" range:step="10"
range:boundaries="10;500"/> range:boundaries="10;500"/>
<!-- <org.solovyev.android.prefs.FloatRangeSeekBarPreference <!-- <org.solovyev.android.prefs.FloatRangeSeekBarPreference
a:key="@string/p_drag_duration_key" a:key="@string/p_drag_duration_key"
a:title="Duration of drag event" a:title="Duration of drag event"
a:text=" ms" a:text=" ms"
a:defaultValue="40;2500" a:defaultValue="40;2500"
range:steps="10" range:steps="10"
range:boundaries="5;4000"/> range:boundaries="5;4000"/>
<org.solovyev.android.prefs.FloatRangeSeekBarPreference <org.solovyev.android.prefs.FloatRangeSeekBarPreference
a:key="@string/p_drag_angle_key" a:key="@string/p_drag_angle_key"
a:title="Angle of drag event" a:title="Angle of drag event"
a:text=" degrees" a:text=" degrees"
a:defaultValue="0;45" a:defaultValue="0;45"
range:steps="5" range:steps="5"
range:boundaries="0;45"/>--> range:boundaries="0;45"/>-->
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="autoOrientation" a:key="autoOrientation"
a:title="@string/c_auto_orientation_title" a:title="@string/c_auto_orientation_title"
a:summary="@string/c_auto_orientation_summary" a:summary="@string/c_auto_orientation_summary"
a:defaultValue="true"/> a:defaultValue="true"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="showEqualsButton" a:key="showEqualsButton"
a:title="@string/c_show_equals_button_title" a:title="@string/c_show_equals_button_title"
a:summary="@string/c_show_equals_button_summary" a:summary="@string/c_show_equals_button_summary"
a:defaultValue="true"/> a:defaultValue="true"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="hideNumeralBaseDigits" a:key="hideNumeralBaseDigits"
a:title="@string/c_hide_numeral_base_digits_title" a:title="@string/c_hide_numeral_base_digits_title"
a:summary="@string/c_hide_numeral_base_digits_summary" a:summary="@string/c_hide_numeral_base_digits_summary"
a:defaultValue="true"/> a:defaultValue="true"/>
</PreferenceScreen> </PreferenceScreen>
<PreferenceScreen <PreferenceScreen
a:title="@string/c_prefs_other_category"> a:title="@string/c_prefs_other_category">
<org.solovyev.android.ads.AdViewPreference <org.solovyev.android.ads.AdViewPreference
a:key="admob_04" a:key="admob_04"
a:layout="@layout/admob_pref"/> a:layout="@layout/admob_pref"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="@string/p_calc_show_release_notes_key" a:key="@string/p_calc_show_release_notes_key"
a:summary="@string/c_calc_show_release_notes_summary" a:summary="@string/c_calc_show_release_notes_summary"
a:title="@string/c_calc_show_release_notes_title" a:title="@string/c_calc_show_release_notes_title"
a:defaultValue="true"/> a:defaultValue="true"/>
<android.preference.CheckBoxPreference <android.preference.CheckBoxPreference
a:key="@string/p_calc_use_back_button_as_prev_key" a:key="@string/p_calc_use_back_button_as_prev_key"
a:summary="@string/c_calc_use_back_button_as_prev_summary" a:summary="@string/c_calc_use_back_button_as_prev_summary"
a:title="@string/c_calc_use_back_button_as_prev_title" a:title="@string/c_calc_use_back_button_as_prev_title"
a:defaultValue="false"/> a:defaultValue="false"/>
<Preference <Preference
a:key="@string/p_clear_billing_info_key" a:key="@string/p_clear_billing_info_key"
a:summary="@string/c_clear_billing_info_summary" a:summary="@string/c_clear_billing_info_summary"
a:title="@string/c_clear_billing_info_title"/> a:title="@string/c_clear_billing_info_title"/>
</PreferenceScreen> </PreferenceScreen>
</PreferenceScreen> </PreferenceScreen>

View File

@ -1,76 +1,75 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.about; package org.solovyev.android.calculator.about;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.text.Html; import android.text.Html;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.widget.TextView; import android.widget.TextView;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.AndroidUtils; import org.solovyev.android.AndroidUtils;
import org.solovyev.android.ResourceCache; import org.solovyev.android.calculator.CalculatorActivity;
import org.solovyev.android.calculator.CalculatorActivity; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.R; import org.solovyev.common.text.StringUtils;
import org.solovyev.common.text.StringUtils;
/**
/** * User: serso
* User: serso * Date: 12/25/11
* Date: 12/25/11 * Time: 12:00 AM
* Time: 12:00 AM */
*/ public class CalculatorReleaseNotesActivity extends Activity {
public class CalculatorReleaseNotesActivity extends Activity {
@Override
@Override protected void onCreate(Bundle savedInstanceState) {
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
setContentView(R.layout.release_notes);
setContentView(R.layout.release_notes);
final TextView releaseNotes = (TextView) findViewById(R.id.releaseNotesTextView);
final TextView releaseNotes = (TextView) findViewById(R.id.releaseNotesTextView); releaseNotes.setMovementMethod(LinkMovementMethod.getInstance());
releaseNotes.setMovementMethod(LinkMovementMethod.getInstance());
releaseNotes.setText(Html.fromHtml(getReleaseNotes(this)));
releaseNotes.setText(Html.fromHtml(getReleaseNotes(this)));
}
}
@NotNull
@NotNull public static String getReleaseNotes(@NotNull Context context) {
public static String getReleaseNotes(@NotNull Context context) { return getReleaseNotes(context, 0);
return getReleaseNotes(context, 0); }
}
@NotNull
@NotNull public static String getReleaseNotes(@NotNull Context context, int minVersion) {
public static String getReleaseNotes(@NotNull Context context, int minVersion) { final StringBuilder result = new StringBuilder();
final StringBuilder result = new StringBuilder();
final String releaseNotesForTitle = context.getString(R.string.c_release_notes_for_title);
final String releaseNotesForTitle = context.getString(R.string.c_release_notes_for_title); final int version = AndroidUtils.getAppVersionCode(context, CalculatorActivity.class.getPackage().getName());
final int version = AndroidUtils.getAppVersionCode(context, CalculatorActivity.class.getPackage().getName());
final TextHelper textHelper = new TextHelper(context.getResources(), R.class.getPackage().getName());
final TextHelper textHelper = new TextHelper(context.getResources(), R.class.getPackage().getName());
boolean first = true;
boolean first = true; for ( int i = version; i >= minVersion; i-- ) {
for ( int i = version; i >= minVersion; i-- ) { String releaseNotesForVersion = textHelper.getText("c_release_notes_for_" + i);
String releaseNotesForVersion = textHelper.getText("c_release_notes_for_" + i); if (!StringUtils.isEmpty(releaseNotesForVersion)){
if (!StringUtils.isEmpty(releaseNotesForVersion)){ assert releaseNotesForVersion != null;
assert releaseNotesForVersion != null; if ( !first ) {
if ( !first ) { result.append("<br/><br/>");
result.append("<br/><br/>"); } else {
} else { first = false;
first = false; }
} releaseNotesForVersion = releaseNotesForVersion.replace("\n", "<br/>");
releaseNotesForVersion = releaseNotesForVersion.replace("\n", "<br/>"); result.append("<b>").append(releaseNotesForTitle).append(i).append("</b><br/><br/>");
result.append("<b>").append(releaseNotesForTitle).append(i).append("</b><br/><br/>"); result.append(releaseNotesForVersion);
result.append(releaseNotesForVersion); }
} }
}
return result.toString();
return result.toString(); }
} }
}

View File

@ -1,423 +1,425 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
*/ */
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import jscl.*; import jscl.*;
import jscl.math.Generic; import jscl.math.Generic;
import jscl.math.function.Function; import jscl.math.function.Function;
import jscl.math.function.IConstant; import jscl.math.function.IConstant;
import jscl.math.operator.Operator; import jscl.math.operator.Operator;
import jscl.text.ParseInterruptedException; import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.CalculatorApplication;
import org.solovyev.android.prefs.BooleanPreference; import org.solovyev.android.calculator.R;
import org.solovyev.android.prefs.Preference; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.prefs.StringPreference; import org.solovyev.android.prefs.BooleanPreference;
import org.solovyev.common.MutableObject; import org.solovyev.android.prefs.Preference;
import org.solovyev.common.msg.MessageRegistry; import org.solovyev.android.prefs.StringPreference;
import org.solovyev.common.text.EnumMapper; import org.solovyev.common.MutableObject;
import org.solovyev.common.text.NumberMapper; import org.solovyev.common.msg.MessageRegistry;
import org.solovyev.common.text.StringUtils; import org.solovyev.common.text.EnumMapper;
import org.solovyev.common.text.NumberMapper;
import java.text.DecimalFormatSymbols; import org.solovyev.common.text.StringUtils;
import java.util.ArrayList;
import java.util.Collections; import java.text.DecimalFormatSymbols;
import java.util.List; import java.util.ArrayList;
import java.util.concurrent.CountDownLatch; import java.util.Collections;
import java.util.concurrent.TimeUnit; import java.util.List;
import java.util.concurrent.CountDownLatch;
/** import java.util.concurrent.TimeUnit;
* User: serso
* Date: 9/12/11 /**
* Time: 11:38 PM * User: serso
*/ * Date: 9/12/11
* Time: 11:38 PM
public enum CalculatorEngine { */
instance; public enum CalculatorEngine {
private static final String GROUPING_SEPARATOR_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator"; instance;
private static final String MULTIPLICATION_SIGN_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_multiplication_sign"; private static final String GROUPING_SEPARATOR_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator";
private static final String MULTIPLICATION_SIGN_DEFAULT = "×";
private static final String MULTIPLICATION_SIGN_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_calc_multiplication_sign";
private static final String MAX_CALCULATION_TIME_P_KEY = "calculation.max_calculation_time"; private static final String MULTIPLICATION_SIGN_DEFAULT = "×";
private static final String MAX_CALCULATION_TIME_DEFAULT = "5";
private static final String MAX_CALCULATION_TIME_P_KEY = "calculation.max_calculation_time";
private static final String SCIENCE_NOTATION_P_KEY = "calculation.output.science_notation"; private static final String MAX_CALCULATION_TIME_DEFAULT = "5";
private static final boolean SCIENCE_NOTATION_DEFAULT = false;
private static final String SCIENCE_NOTATION_P_KEY = "calculation.output.science_notation";
private static final String ROUND_RESULT_P_KEY = "org.solovyev.android.calculator.CalculatorModel_round_result"; private static final boolean SCIENCE_NOTATION_DEFAULT = false;
private static final boolean ROUND_RESULT_DEFAULT = true;
private static final String ROUND_RESULT_P_KEY = "org.solovyev.android.calculator.CalculatorModel_round_result";
private static final String RESULT_PRECISION_P_KEY = "org.solovyev.android.calculator.CalculatorModel_result_precision"; private static final boolean ROUND_RESULT_DEFAULT = true;
private static final String RESULT_PRECISION_DEFAULT = "5";
private static final String RESULT_PRECISION_P_KEY = "org.solovyev.android.calculator.CalculatorModel_result_precision";
private static final String NUMERAL_BASES_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_numeral_bases"; private static final String RESULT_PRECISION_DEFAULT = "5";
private static final String NUMERAL_BASES_DEFAULT = "dec";
private static final String NUMERAL_BASES_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_numeral_bases";
private static final String ANGLE_UNITS_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_angle_units"; private static final String NUMERAL_BASES_DEFAULT = "dec";
private static final String ANGLE_UNITS_DEFAULT = "deg";
private static final String ANGLE_UNITS_P_KEY = "org.solovyev.android.calculator.CalculatorActivity_angle_units";
public static class Preferences { private static final String ANGLE_UNITS_DEFAULT = "deg";
public static final Preference<String> groupingSeparator = StringPreference.newInstance(GROUPING_SEPARATOR_P_KEY, JsclMathEngine.GROUPING_SEPARATOR_DEFAULT);
public static final Preference<String> multiplicationSign = StringPreference.newInstance(MULTIPLICATION_SIGN_P_KEY, MULTIPLICATION_SIGN_DEFAULT); public static class Preferences {
public static final Preference<Integer> precision = StringPreference.newInstance(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT, new NumberMapper<Integer>(Integer.class)); public static final Preference<String> groupingSeparator = StringPreference.newInstance(GROUPING_SEPARATOR_P_KEY, JsclMathEngine.GROUPING_SEPARATOR_DEFAULT);
public static final Preference<Boolean> roundResult = new BooleanPreference(ROUND_RESULT_P_KEY, ROUND_RESULT_DEFAULT); public static final Preference<String> multiplicationSign = StringPreference.newInstance(MULTIPLICATION_SIGN_P_KEY, MULTIPLICATION_SIGN_DEFAULT);
public static final Preference<NumeralBase> numeralBase = StringPreference.newInstance(NUMERAL_BASES_P_KEY, NUMERAL_BASES_DEFAULT, EnumMapper.newInstance(NumeralBase.class)); public static final Preference<Integer> precision = StringPreference.newInstance(RESULT_PRECISION_P_KEY, RESULT_PRECISION_DEFAULT, new NumberMapper<Integer>(Integer.class));
public static final Preference<AngleUnit> angleUnit = StringPreference.newInstance(ANGLE_UNITS_P_KEY, ANGLE_UNITS_DEFAULT, EnumMapper.newInstance(AngleUnit.class)); public static final Preference<Boolean> roundResult = new BooleanPreference(ROUND_RESULT_P_KEY, ROUND_RESULT_DEFAULT);
public static final Preference<Boolean> scienceNotation = new BooleanPreference(SCIENCE_NOTATION_P_KEY, SCIENCE_NOTATION_DEFAULT); public static final Preference<NumeralBase> numeralBase = StringPreference.newInstance(NUMERAL_BASES_P_KEY, NUMERAL_BASES_DEFAULT, EnumMapper.newInstance(NumeralBase.class));
public static final Preference<Integer> maxCalculationTime = StringPreference.newInstance(MAX_CALCULATION_TIME_P_KEY, MAX_CALCULATION_TIME_DEFAULT, new NumberMapper<Integer>(Integer.class)); public static final Preference<AngleUnit> angleUnit = StringPreference.newInstance(ANGLE_UNITS_P_KEY, ANGLE_UNITS_DEFAULT, EnumMapper.newInstance(AngleUnit.class));
public static final Preference<Boolean> scienceNotation = new BooleanPreference(SCIENCE_NOTATION_P_KEY, SCIENCE_NOTATION_DEFAULT);
private static final List<String> preferenceKeys = new ArrayList<String>(); public static final Preference<Integer> maxCalculationTime = StringPreference.newInstance(MAX_CALCULATION_TIME_P_KEY, MAX_CALCULATION_TIME_DEFAULT, new NumberMapper<Integer>(Integer.class));
static { private static final List<String> preferenceKeys = new ArrayList<String>();
preferenceKeys.add(groupingSeparator.getKey());
preferenceKeys.add(multiplicationSign.getKey()); static {
preferenceKeys.add(precision.getKey()); preferenceKeys.add(groupingSeparator.getKey());
preferenceKeys.add(roundResult.getKey()); preferenceKeys.add(multiplicationSign.getKey());
preferenceKeys.add(numeralBase.getKey()); preferenceKeys.add(precision.getKey());
preferenceKeys.add(angleUnit.getKey()); preferenceKeys.add(roundResult.getKey());
preferenceKeys.add(scienceNotation.getKey()); preferenceKeys.add(numeralBase.getKey());
preferenceKeys.add(maxCalculationTime.getKey()); preferenceKeys.add(angleUnit.getKey());
} preferenceKeys.add(scienceNotation.getKey());
preferenceKeys.add(maxCalculationTime.getKey());
@NotNull }
public static List<String> getPreferenceKeys() {
return Collections.unmodifiableList(preferenceKeys); @NotNull
} public static List<String> getPreferenceKeys() {
} return Collections.unmodifiableList(preferenceKeys);
}
@NotNull }
private final Object lock = new Object();
@NotNull
@NotNull private final Object lock = new Object();
private MathEngine engine = JsclMathEngine.instance;
@NotNull
@NotNull private MathEngine engine = JsclMathEngine.instance;
public final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
@NotNull
@NotNull public final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
private final AndroidMathRegistry<IConstant> varsRegistry = new AndroidVarsRegistryImpl(engine.getConstantsRegistry());
@NotNull
@NotNull private final AndroidMathRegistry<IConstant> varsRegistry = new AndroidVarsRegistryImpl(engine.getConstantsRegistry());
private final AndroidMathRegistry<jscl.math.function.Function> functionsRegistry = new AndroidFunctionsMathRegistry(engine.getFunctionsRegistry());
@NotNull
@NotNull private final AndroidMathRegistry<jscl.math.function.Function> functionsRegistry = new AndroidFunctionsMathRegistry(engine.getFunctionsRegistry());
private final AndroidMathRegistry<Operator> operatorsRegistry = new AndroidOperatorsMathRegistry(engine.getOperatorsRegistry());
@NotNull
private final AndroidMathRegistry<Operator> postfixFunctionsRegistry = new AndroidPostfixFunctionsRegistry(engine.getPostfixFunctionsRegistry()); private final AndroidMathRegistry<Operator> operatorsRegistry = new AndroidOperatorsMathRegistry(engine.getOperatorsRegistry());
@Nullable private final AndroidMathRegistry<Operator> postfixFunctionsRegistry = new AndroidPostfixFunctionsRegistry(engine.getPostfixFunctionsRegistry());
private ThreadKiller threadKiller = new AndroidThreadKiller();
@Nullable
// calculation thread timeout in seconds, after timeout thread would be interrupted private ThreadKiller threadKiller = new AndroidThreadKiller();
private int timeout = Integer.valueOf(MAX_CALCULATION_TIME_DEFAULT);
// calculation thread timeout in seconds, after timeout thread would be interrupted
@NotNull private int timeout = Integer.valueOf(MAX_CALCULATION_TIME_DEFAULT);
private String multiplicationSign = MULTIPLICATION_SIGN_DEFAULT;
@NotNull
CalculatorEngine() { private String multiplicationSign = MULTIPLICATION_SIGN_DEFAULT;
this.engine.setRoundResult(true);
this.engine.setUseGroupingSeparator(true); CalculatorEngine() {
} this.engine.setRoundResult(true);
this.engine.setUseGroupingSeparator(true);
@NotNull }
public String getMultiplicationSign() {
return multiplicationSign; @NotNull
} public String getMultiplicationSign() {
return multiplicationSign;
public void setMultiplicationSign(@NotNull String multiplicationSign) { }
this.multiplicationSign = multiplicationSign;
} public void setMultiplicationSign(@NotNull String multiplicationSign) {
this.multiplicationSign = multiplicationSign;
public static class Result { }
@NotNull public static class Result {
private Generic genericResult;
@NotNull
@NotNull private Generic genericResult;
private String result;
@NotNull
@NotNull private String result;
private JsclOperation userOperation;
@NotNull
public Result(@NotNull String result, @NotNull JsclOperation userOperation, @NotNull Generic genericResult) { private JsclOperation userOperation;
this.result = result;
this.userOperation = userOperation; public Result(@NotNull String result, @NotNull JsclOperation userOperation, @NotNull Generic genericResult) {
this.genericResult = genericResult; this.result = result;
} this.userOperation = userOperation;
this.genericResult = genericResult;
@NotNull }
public String getResult() {
return result; @NotNull
} public String getResult() {
return result;
@NotNull }
public JsclOperation getUserOperation() {
return userOperation; @NotNull
} public JsclOperation getUserOperation() {
return userOperation;
@NotNull }
public Generic getGenericResult() {
return genericResult; @NotNull
} public Generic getGenericResult() {
} return genericResult;
}
public Result evaluate(@NotNull JsclOperation operation, }
@NotNull String expression) throws CalculatorParseException, CalculatorEvalException {
return evaluate(operation, expression, null); public Result evaluate(@NotNull JsclOperation operation,
} @NotNull String expression) throws CalculatorParseException, CalculatorEvalException {
return evaluate(operation, expression, null);
public Result evaluate(@NotNull final JsclOperation operation, }
@NotNull String expression,
@Nullable MessageRegistry mr) throws CalculatorParseException, CalculatorEvalException { public Result evaluate(@NotNull final JsclOperation operation,
synchronized (lock) { @NotNull String expression,
final StringBuilder sb = new StringBuilder(); @Nullable MessageRegistry mr) throws CalculatorParseException, CalculatorEvalException {
synchronized (lock) {
final PreparedExpression preparedExpression = preprocessor.process(expression); final StringBuilder sb = new StringBuilder();
sb.append(preparedExpression);
final PreparedExpression preparedExpression = preprocessor.process(expression);
//Log.d(CalculatorEngine.class.getName(), "Preprocessed expression: " + preparedExpression); sb.append(preparedExpression);
/*if (operation == JsclOperation.numeric && preparedExpression.isExistsUndefinedVar()) {
operation = JsclOperation.simplify; //Log.d(CalculatorEngine.class.getName(), "Preprocessed expression: " + preparedExpression);
/*if (operation == JsclOperation.numeric && preparedExpression.isExistsUndefinedVar()) {
if (mr != null) { operation = JsclOperation.simplify;
final String undefinedVars = CollectionsUtils.formatValue(preparedExpression.getUndefinedVars(), ", ", new Formatter<Var>() {
@Override if (mr != null) {
public String formatValue(@Nullable Var var) throws IllegalArgumentException { final String undefinedVars = CollectionsUtils.formatValue(preparedExpression.getUndefinedVars(), ", ", new Formatter<Var>() {
return var != null ? var.getName() : ""; @Override
} public String formatValue(@Nullable Var var) throws IllegalArgumentException {
}); return var != null ? var.getName() : "";
}
mr.addMessage(new AndroidMessage(R.string.c_simplify_instead_of_numeric, MessageType.info, undefinedVars)); });
}
}*/ mr.addMessage(new AndroidMessage(R.string.c_simplify_instead_of_numeric, MessageType.info, undefinedVars));
}
final String jsclExpression = sb.toString(); }*/
final MutableObject<Generic> calculationResult = new MutableObject<Generic>(null); final String jsclExpression = sb.toString();
final MutableObject<CalculatorParseException> parseException = new MutableObject<CalculatorParseException>(null);
final MutableObject<CalculatorEvalException> evalException = new MutableObject<CalculatorEvalException>(null); final MutableObject<Generic> calculationResult = new MutableObject<Generic>(null);
final MutableObject<Thread> calculationThread = new MutableObject<Thread>(null); final MutableObject<CalculatorParseException> parseException = new MutableObject<CalculatorParseException>(null);
final MutableObject<CalculatorEvalException> evalException = new MutableObject<CalculatorEvalException>(null);
final CountDownLatch latch = new CountDownLatch(1); final MutableObject<Thread> calculationThread = new MutableObject<Thread>(null);
new Thread(new Runnable() { final CountDownLatch latch = new CountDownLatch(1);
@Override
public void run() { new Thread(new Runnable() {
final Thread thread = Thread.currentThread(); @Override
try { public void run() {
//Log.d(CalculatorEngine.class.getName(), "Calculation thread started work: " + thread.getName()); final Thread thread = Thread.currentThread();
//System.out.println(jsclExpression); try {
calculationThread.setObject(thread); //Log.d(CalculatorEngine.class.getName(), "Calculation thread started work: " + thread.getName());
final Generic genericResult = operation.evaluateGeneric(jsclExpression); //System.out.println(jsclExpression);
calculationThread.setObject(thread);
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!) final Generic genericResult = operation.evaluateGeneric(jsclExpression);
genericResult.toString();
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!)
calculationResult.setObject(genericResult); genericResult.toString();
} catch (AbstractJsclArithmeticException e) {
evalException.setObject(new CalculatorEvalException(e, e, jsclExpression)); calculationResult.setObject(genericResult);
} catch (ArithmeticException e) { } catch (AbstractJsclArithmeticException e) {
//System.out.println(e.getMessage()); evalException.setObject(new CalculatorEvalException(e, e, jsclExpression));
parseException.setObject(new CalculatorParseException(Messages.msg_1, jsclExpression, e.getMessage())); } catch (ArithmeticException e) {
} catch (StackOverflowError e) { //System.out.println(e.getMessage());
//System.out.println(StringUtils.fromStackTrace(e.getStackTrace())); parseException.setObject(new CalculatorParseException(R.string.msg_1, CalculatorApplication.getInstance(), jsclExpression, e.getMessage()));
parseException.setObject(new CalculatorParseException(Messages.msg_2, jsclExpression)); } catch (StackOverflowError e) {
} catch (jscl.text.ParseException e) { //System.out.println(StringUtils.fromStackTrace(e.getStackTrace()));
//System.out.println(e.getMessage()); parseException.setObject(new CalculatorParseException(R.string.msg_2, CalculatorApplication.getInstance(), jsclExpression));
parseException.setObject(new CalculatorParseException(e)); } catch (jscl.text.ParseException e) {
} catch (ParseInterruptedException e) { //System.out.println(e.getMessage());
//System.out.println(e.getMessage()); parseException.setObject(new CalculatorParseException(e));
// do nothing - we ourselves interrupt the calculations } catch (ParseInterruptedException e) {
} finally { //System.out.println(e.getMessage());
//Log.d(CalculatorEngine.class.getName(), "Calculation thread ended work: " + thread.getName()); // do nothing - we ourselves interrupt the calculations
calculationThread.setObject(null); } finally {
latch.countDown(); //Log.d(CalculatorEngine.class.getName(), "Calculation thread ended work: " + thread.getName());
} calculationThread.setObject(null);
} latch.countDown();
}).start(); }
}
try { }).start();
//Log.d(CalculatorEngine.class.getName(), "Main thread is waiting: " + Thread.currentThread().getName());
latch.await(timeout, TimeUnit.SECONDS); try {
//Log.d(CalculatorEngine.class.getName(), "Main thread got up: " + Thread.currentThread().getName()); //Log.d(CalculatorEngine.class.getName(), "Main thread is waiting: " + Thread.currentThread().getName());
latch.await(timeout, TimeUnit.SECONDS);
final CalculatorParseException parseExceptionObject = parseException.getObject(); //Log.d(CalculatorEngine.class.getName(), "Main thread got up: " + Thread.currentThread().getName());
final CalculatorEvalException evalExceptionObject = evalException.getObject();
final Object calculationResultLocal = calculationResult.getObject(); final CalculatorParseException parseExceptionObject = parseException.getObject();
final Thread calculationThreadLocal = calculationThread.getObject(); final CalculatorEvalException evalExceptionObject = evalException.getObject();
final Object calculationResultLocal = calculationResult.getObject();
if (calculationThreadLocal != null) { final Thread calculationThreadLocal = calculationThread.getObject();
if (threadKiller != null) {
threadKiller.killThread(calculationThreadLocal); if (calculationThreadLocal != null) {
} if (threadKiller != null) {
//calculationThreadLocal.stop(); threadKiller.killThread(calculationThreadLocal);
} }
//calculationThreadLocal.stop();
if (parseExceptionObject != null || evalExceptionObject != null) { }
if (operation == JsclOperation.numeric &&
(preparedExpression.isExistsUndefinedVar() || (evalExceptionObject != null && evalExceptionObject.getCause() instanceof NumeralBaseException))) { if (parseExceptionObject != null || evalExceptionObject != null) {
return evaluate(JsclOperation.simplify, expression, mr); if (operation == JsclOperation.numeric &&
} (preparedExpression.isExistsUndefinedVar() || (evalExceptionObject != null && evalExceptionObject.getCause() instanceof NumeralBaseException))) {
return evaluate(JsclOperation.simplify, expression, mr);
if (parseExceptionObject != null) { }
throw parseExceptionObject;
} else { if (parseExceptionObject != null) {
throw evalExceptionObject; throw parseExceptionObject;
} } else {
} throw evalExceptionObject;
}
if (calculationResultLocal == null) { }
throw new CalculatorParseException(Messages.msg_3, jsclExpression);
} if (calculationResultLocal == null) {
throw new CalculatorParseException(R.string.msg_3, CalculatorApplication.getInstance(), jsclExpression);
} catch (InterruptedException e) { }
throw new CalculatorParseException(Messages.msg_4, jsclExpression);
} } catch (InterruptedException e) {
throw new CalculatorParseException(R.string.msg_4, CalculatorApplication.getInstance(), jsclExpression);
final Generic genericResult = calculationResult.getObject(); }
return new Result(operation.getFromProcessor().process(genericResult), operation, genericResult); final Generic genericResult = calculationResult.getObject();
}
} return new Result(operation.getFromProcessor().process(genericResult), operation, genericResult);
}
public void setPrecision(int precision) { }
this.getEngine().setPrecision(precision);
} public void setPrecision(int precision) {
this.getEngine().setPrecision(precision);
public void setRoundResult(boolean roundResult) { }
this.getEngine().setRoundResult(roundResult);
} public void setRoundResult(boolean roundResult) {
this.getEngine().setRoundResult(roundResult);
public void init(@Nullable Context context, @Nullable SharedPreferences preferences) { }
synchronized (lock) {
reset(context, preferences); public void init(@Nullable Context context, @Nullable SharedPreferences preferences) {
} synchronized (lock) {
} reset(context, preferences);
}
public void reset(@Nullable Context context, @Nullable SharedPreferences preferences) { }
synchronized (lock) {
softReset(context, preferences); public void reset(@Nullable Context context, @Nullable SharedPreferences preferences) {
synchronized (lock) {
varsRegistry.load(context, preferences); softReset(context, preferences);
functionsRegistry.load(context, preferences);
operatorsRegistry.load(context, preferences); varsRegistry.load(context, preferences);
postfixFunctionsRegistry.load(context, preferences); functionsRegistry.load(context, preferences);
} operatorsRegistry.load(context, preferences);
} postfixFunctionsRegistry.load(context, preferences);
}
public void softReset(@Nullable Context context, @Nullable SharedPreferences preferences) { }
synchronized (lock) {
if (preferences != null) { public void softReset(@Nullable Context context, @Nullable SharedPreferences preferences) {
this.setPrecision(Preferences.precision.getPreference(preferences)); synchronized (lock) {
this.setRoundResult(Preferences.roundResult.getPreference(preferences)); if (preferences != null) {
this.setAngleUnits(getAngleUnitsFromPrefs(preferences)); this.setPrecision(Preferences.precision.getPreference(preferences));
this.setNumeralBase(getNumeralBaseFromPrefs(preferences)); this.setRoundResult(Preferences.roundResult.getPreference(preferences));
this.setMultiplicationSign(Preferences.multiplicationSign.getPreference(preferences)); this.setAngleUnits(getAngleUnitsFromPrefs(preferences));
this.setScienceNotation(Preferences.scienceNotation.getPreference(preferences)); this.setNumeralBase(getNumeralBaseFromPrefs(preferences));
this.setTimeout(Preferences.maxCalculationTime.getPreference(preferences)); this.setMultiplicationSign(Preferences.multiplicationSign.getPreference(preferences));
this.setScienceNotation(Preferences.scienceNotation.getPreference(preferences));
final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences); this.setTimeout(Preferences.maxCalculationTime.getPreference(preferences));
if (StringUtils.isEmpty(groupingSeparator)) {
this.getEngine().setUseGroupingSeparator(false); final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences);
} else { if (StringUtils.isEmpty(groupingSeparator)) {
this.getEngine().setUseGroupingSeparator(true); this.getEngine().setUseGroupingSeparator(false);
this.getEngine().setGroupingSeparator(groupingSeparator.charAt(0)); } else {
} this.getEngine().setUseGroupingSeparator(true);
} this.getEngine().setGroupingSeparator(groupingSeparator.charAt(0));
} }
} }
}
}
@NotNull
public NumeralBase getNumeralBaseFromPrefs(@NotNull SharedPreferences preferences) {
return Preferences.numeralBase.getPreference(preferences); @NotNull
} public NumeralBase getNumeralBaseFromPrefs(@NotNull SharedPreferences preferences) {
return Preferences.numeralBase.getPreference(preferences);
@NotNull }
public AngleUnit getAngleUnitsFromPrefs(@NotNull SharedPreferences preferences) {
return Preferences.angleUnit.getPreference(preferences); @NotNull
} public AngleUnit getAngleUnitsFromPrefs(@NotNull SharedPreferences preferences) {
return Preferences.angleUnit.getPreference(preferences);
//for tests only }
void setDecimalGroupSymbols(@NotNull DecimalFormatSymbols decimalGroupSymbols) {
synchronized (lock) { //for tests only
this.getEngine().setDecimalGroupSymbols(decimalGroupSymbols); void setDecimalGroupSymbols(@NotNull DecimalFormatSymbols decimalGroupSymbols) {
} synchronized (lock) {
} this.getEngine().setDecimalGroupSymbols(decimalGroupSymbols);
}
@NotNull }
public AndroidMathRegistry<IConstant> getVarsRegistry() {
return varsRegistry; @NotNull
} public AndroidMathRegistry<IConstant> getVarsRegistry() {
return varsRegistry;
@NotNull }
public AndroidMathRegistry<Function> getFunctionsRegistry() {
return functionsRegistry; @NotNull
} public AndroidMathRegistry<Function> getFunctionsRegistry() {
return functionsRegistry;
@NotNull }
public AndroidMathRegistry<Operator> getOperatorsRegistry() {
return operatorsRegistry; @NotNull
} public AndroidMathRegistry<Operator> getOperatorsRegistry() {
return operatorsRegistry;
@NotNull }
public AndroidMathRegistry<Operator> getPostfixFunctionsRegistry() {
return postfixFunctionsRegistry; @NotNull
} public AndroidMathRegistry<Operator> getPostfixFunctionsRegistry() {
return postfixFunctionsRegistry;
@NotNull }
public MathEngine getEngine() {
return engine; @NotNull
} public MathEngine getEngine() {
return engine;
// package protected for tests }
void setTimeout(int timeout) {
this.timeout = timeout; // package protected for tests
} void setTimeout(int timeout) {
this.timeout = timeout;
public void setAngleUnits(@NotNull AngleUnit angleUnits) { }
getEngine().setAngleUnits(angleUnits);
} public void setAngleUnits(@NotNull AngleUnit angleUnits) {
getEngine().setAngleUnits(angleUnits);
public void setScienceNotation(boolean scienceNotation) { }
getEngine().setScienceNotation(scienceNotation);
} public void setScienceNotation(boolean scienceNotation) {
getEngine().setScienceNotation(scienceNotation);
public void setNumeralBase(@NotNull NumeralBase numeralBase) { }
getEngine().setNumeralBase(numeralBase);
} public void setNumeralBase(@NotNull NumeralBase numeralBase) {
getEngine().setNumeralBase(numeralBase);
// for tests only }
void setThreadKiller(@Nullable ThreadKiller threadKiller) {
this.threadKiller = threadKiller; // for tests only
} void setThreadKiller(@Nullable ThreadKiller threadKiller) {
this.threadKiller = threadKiller;
private static interface ThreadKiller { }
void killThread(@NotNull Thread thread);
} private static interface ThreadKiller {
void killThread(@NotNull Thread thread);
private static class AndroidThreadKiller implements ThreadKiller { }
@Override
public void killThread(@NotNull Thread thread) { private static class AndroidThreadKiller implements ThreadKiller {
thread.setPriority(Thread.MIN_PRIORITY); @Override
thread.interrupt(); public void killThread(@NotNull Thread thread) {
} thread.setPriority(Thread.MIN_PRIORITY);
} thread.interrupt();
}
public static class ThreadKillerImpl implements ThreadKiller { }
@Override
public void killThread(@NotNull Thread thread) { public static class ThreadKillerImpl implements ThreadKiller {
thread.setPriority(Thread.MIN_PRIORITY); @Override
thread.stop(); public void killThread(@NotNull Thread thread) {
} thread.setPriority(Thread.MIN_PRIORITY);
} thread.stop();
} }
}
}

View File

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

View File

@ -1,145 +1,147 @@
/* /*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev. * Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com * For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org * or visit http://se.solovyev.org
*/ */
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import jscl.math.function.IConstant; import jscl.math.function.IConstant;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.common.StartsWithFinder; import org.solovyev.android.calculator.CalculatorApplication;
import org.solovyev.android.calculator.math.MathType; import org.solovyev.android.calculator.R;
import org.solovyev.common.collections.CollectionsUtils; import org.solovyev.common.StartsWithFinder;
import org.solovyev.android.calculator.math.MathType;
import java.util.ArrayList; import org.solovyev.common.collections.CollectionsUtils;
import java.util.List;
import java.util.ArrayList;
public class ToJsclTextProcessor implements TextProcessor<PreparedExpression, String> { import java.util.List;
@NotNull public class ToJsclTextProcessor implements TextProcessor<PreparedExpression, String> {
private static final Integer MAX_DEPTH = 20;
@NotNull
@NotNull private static final Integer MAX_DEPTH = 20;
private static final TextProcessor<PreparedExpression, String> instance = new ToJsclTextProcessor();
@NotNull
private ToJsclTextProcessor() { private static final TextProcessor<PreparedExpression, String> instance = new ToJsclTextProcessor();
}
private ToJsclTextProcessor() {
}
@NotNull
public static TextProcessor<PreparedExpression, String> getInstance() {
return instance; @NotNull
} public static TextProcessor<PreparedExpression, String> getInstance() {
return instance;
@Override }
@NotNull
public PreparedExpression process(@NotNull String s) throws CalculatorParseException { @Override
return processWithDepth(s, 0, new ArrayList<IConstant>()); @NotNull
} public PreparedExpression process(@NotNull String s) throws CalculatorParseException {
return processWithDepth(s, 0, new ArrayList<IConstant>());
private static PreparedExpression processWithDepth(@NotNull String s, int depth, @NotNull List<IConstant> undefinedVars) throws CalculatorParseException { }
return replaceVariables(processExpression(s).toString(), depth, undefinedVars);
} private static PreparedExpression processWithDepth(@NotNull String s, int depth, @NotNull List<IConstant> undefinedVars) throws CalculatorParseException {
return replaceVariables(processExpression(s).toString(), depth, undefinedVars);
@NotNull }
private static StringBuilder processExpression(@NotNull String s) throws CalculatorParseException {
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); @NotNull
final StringBuilder result = new StringBuilder(); private static StringBuilder processExpression(@NotNull String s) throws CalculatorParseException {
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
MathType.Result mathTypeResult = null; final StringBuilder result = new StringBuilder();
MathType.Result mathTypeBefore;
MathType.Result mathTypeResult = null;
final LiteNumberBuilder nb = new LiteNumberBuilder(CalculatorEngine.instance.getEngine()); MathType.Result mathTypeBefore;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') continue; final LiteNumberBuilder nb = new LiteNumberBuilder(CalculatorEngine.instance.getEngine());
startsWithFinder.setI(i); for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') continue;
mathTypeBefore = mathTypeResult == null ? null : mathTypeResult; startsWithFinder.setI(i);
mathTypeResult = MathType.getType(s, i, nb.isHexMode()); mathTypeBefore = mathTypeResult == null ? null : mathTypeResult;
nb.process(mathTypeResult); mathTypeResult = MathType.getType(s, i, nb.isHexMode());
if (mathTypeBefore != null) { nb.process(mathTypeResult);
final MathType current = mathTypeResult.getMathType(); if (mathTypeBefore != null) {
if (current.isNeedMultiplicationSignBefore(mathTypeBefore.getMathType())) { final MathType current = mathTypeResult.getMathType();
result.append("*");
} if (current.isNeedMultiplicationSignBefore(mathTypeBefore.getMathType())) {
} result.append("*");
}
if (mathTypeBefore != null && }
(mathTypeBefore.getMathType() == MathType.function || mathTypeBefore.getMathType() == MathType.operator) &&
CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) { if (mathTypeBefore != null &&
throw new CalculatorParseException(Messages.msg_5, i, s, mathTypeBefore.getMatch()); (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());
i = mathTypeResult.processToJscl(result, i); }
}
return result; i = mathTypeResult.processToJscl(result, i);
} }
return result;
@NotNull }
private static PreparedExpression replaceVariables(@NotNull final String s, int depth, @NotNull List<IConstant> undefinedVars) throws CalculatorParseException {
if (depth >= MAX_DEPTH) { @NotNull
throw new CalculatorParseException(Messages.msg_6, s); private static PreparedExpression replaceVariables(@NotNull final String s, int depth, @NotNull List<IConstant> undefinedVars) throws CalculatorParseException {
} else { if (depth >= MAX_DEPTH) {
depth++; throw new CalculatorParseException(R.string.msg_6, CalculatorApplication.getInstance(), s);
} } else {
depth++;
final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0); }
final StringBuilder result = new StringBuilder(); final StartsWithFinder startsWithFinder = new StartsWithFinder(s, 0);
for (int i = 0; i < s.length(); i++) {
startsWithFinder.setI(i); final StringBuilder result = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
int offset = 0; startsWithFinder.setI(i);
String functionName = CollectionsUtils.find(MathType.function.getTokens(), startsWithFinder);
if (functionName == null) { int offset = 0;
String operatorName = CollectionsUtils.find(MathType.operator.getTokens(), startsWithFinder); String functionName = CollectionsUtils.find(MathType.function.getTokens(), startsWithFinder);
if (operatorName == null) { if (functionName == null) {
String varName = CollectionsUtils.find(CalculatorEngine.instance.getVarsRegistry().getNames(), startsWithFinder); String operatorName = CollectionsUtils.find(MathType.operator.getTokens(), startsWithFinder);
if (varName != null) { if (operatorName == null) {
final IConstant var = CalculatorEngine.instance.getVarsRegistry().get(varName); String varName = CollectionsUtils.find(CalculatorEngine.instance.getVarsRegistry().getNames(), startsWithFinder);
if (var != null) { if (varName != null) {
if (!var.isDefined()) { final IConstant var = CalculatorEngine.instance.getVarsRegistry().get(varName);
undefinedVars.add(var); if (var != null) {
result.append(varName); if (!var.isDefined()) {
offset = varName.length(); undefinedVars.add(var);
} else { result.append(varName);
final String value = var.getValue(); offset = varName.length();
assert value != null; } else {
final String value = var.getValue();
if ( var.getDoubleValue() != null ) { assert value != null;
//result.append(value);
// NOTE: append varName as JSCL engine will convert it to double if needed if ( var.getDoubleValue() != null ) {
result.append(varName); //result.append(value);
} else { // NOTE: append varName as JSCL engine will convert it to double if needed
result.append("(").append(processWithDepth(value, depth, undefinedVars)).append(")"); result.append(varName);
} } else {
offset = varName.length(); result.append("(").append(processWithDepth(value, depth, undefinedVars)).append(")");
} }
} offset = varName.length();
} }
} else { }
result.append(operatorName); }
offset = operatorName.length(); } else {
} result.append(operatorName);
} else { offset = operatorName.length();
result.append(functionName); }
offset = functionName.length(); } else {
} result.append(functionName);
offset = functionName.length();
}
if (offset == 0) {
result.append(s.charAt(i));
} else { if (offset == 0) {
i += offset - 1; result.append(s.charAt(i));
} } else {
} i += offset - 1;
}
return new PreparedExpression(result.toString(), undefinedVars); }
}
} return new PreparedExpression(result.toString(), undefinedVars);
}
}