plotting
This commit is contained in:
parent
731e178b51
commit
fcacb4c486
@ -12,7 +12,8 @@
|
||||
a:targetSdkVersion="8"/>
|
||||
|
||||
<application a:icon="@drawable/icon"
|
||||
a:label="@string/c_app_name">
|
||||
a:label="@string/c_app_name"
|
||||
a:name=".ApplicationContext">
|
||||
|
||||
<activity a:name=".CalculatorActivity"
|
||||
a:label="@string/c_app_name">
|
||||
@ -30,8 +31,7 @@
|
||||
|
||||
<activity a:name=".CalculatorHistoryActivity"
|
||||
a:label="@string/c_app_history"
|
||||
a:configChanges="orientation|keyboardHidden">
|
||||
</activity>
|
||||
a:configChanges="orientation|keyboardHidden"/>
|
||||
|
||||
<activity a:name=".AboutActivity"
|
||||
a:label="@string/c_about"
|
||||
@ -55,23 +55,18 @@
|
||||
|
||||
<activity a:name=".CalculatorFunctionsActivity"
|
||||
a:label="@string/c_functions"
|
||||
a:configChanges="orientation|keyboardHidden">
|
||||
</activity>
|
||||
a:configChanges="orientation|keyboardHidden"/>
|
||||
|
||||
<activity a:name=".CalculatorOperatorsActivity"
|
||||
a:label="@string/c_operators"
|
||||
a:configChanges="orientation|keyboardHidden">
|
||||
</activity>
|
||||
a:configChanges="orientation|keyboardHidden"/>
|
||||
|
||||
<activity a:name=".CalculatorVarsActivity"
|
||||
a:label="@string/c_vars_and_constants"
|
||||
a:configChanges="orientation|keyboardHidden">
|
||||
</activity>
|
||||
a:configChanges="orientation|keyboardHidden"/>
|
||||
|
||||
<activity a:name=".CalculatorPlotActivity"
|
||||
a:label="@string/c_plot_graph"
|
||||
a:configChanges="orientation|keyboardHidden">
|
||||
</activity>
|
||||
a:label="@string/c_plot_graph"/>
|
||||
|
||||
</application>
|
||||
</manifest>
|
48
res/layout-land/calc_plot_view.xml
Normal file
48
res/layout-land/calc_plot_view.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
a:id="@+id/plot_view_container"
|
||||
a:orientation="horizontal"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/plot_graph_container"
|
||||
a:orientation="vertical"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_weight="3">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
a:orientation="vertical"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_weight="1">
|
||||
|
||||
<TextView a:layout_height="wrap_content"
|
||||
a:layout_width="fill_parent"
|
||||
a:padding="6dp"
|
||||
style="@style/default_text_size"
|
||||
a:text="@string/c_min_x_value"/>
|
||||
|
||||
<org.solovyev.android.view.widgets.NumberPicker
|
||||
a:id="@+id/plot_x_min_value"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"/>
|
||||
|
||||
<TextView a:layout_height="wrap_content"
|
||||
a:layout_width="fill_parent"
|
||||
a:padding="6dp"
|
||||
style="@style/default_text_size"
|
||||
a:text="@string/c_max_x_value"/>
|
||||
|
||||
<org.solovyev.android.view.widgets.NumberPicker
|
||||
a:id="@+id/plot_x_max_value"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
48
res/layout-port/calc_plot_view.xml
Normal file
48
res/layout-port/calc_plot_view.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
a:id="@+id/plot_view_container"
|
||||
a:orientation="vertical"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/plot_graph_container"
|
||||
a:orientation="horizontal"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_weight="3">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
a:orientation="horizontal"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_weight="1">
|
||||
|
||||
<TextView a:layout_height="wrap_content"
|
||||
a:layout_width="fill_parent"
|
||||
a:padding="6dp"
|
||||
style="@style/default_text_size"
|
||||
a:text="@string/c_min_x_value"/>
|
||||
|
||||
<org.solovyev.android.view.widgets.NumberPicker
|
||||
a:id="@+id/plot_x_min_value"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"/>
|
||||
|
||||
<TextView a:layout_height="wrap_content"
|
||||
a:layout_width="fill_parent"
|
||||
a:padding="6dp"
|
||||
style="@style/default_text_size"
|
||||
a:text="@string/c_max_x_value"/>
|
||||
|
||||
<org.solovyev.android.view.widgets.NumberPicker
|
||||
a:id="@+id/plot_x_max_value"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -277,5 +277,7 @@ Check the \'Round result\' preference in application settings - it should be tur
|
||||
<string name="msg_6">Infinite loop is detected in expression</string>
|
||||
|
||||
<string name="c_plot_graph">Graph</string>
|
||||
<string name="c_min_x_value">From</string>
|
||||
<string name="c_max_x_value">To</string>
|
||||
|
||||
</resources>
|
||||
|
@ -0,0 +1,23 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 12/1/11
|
||||
* Time: 1:21 PM
|
||||
*/
|
||||
public class ApplicationContext extends android.app.Application {
|
||||
|
||||
@NotNull
|
||||
private static ApplicationContext instance;
|
||||
|
||||
public ApplicationContext() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ApplicationContext getInstance() {
|
||||
return instance;
|
||||
}
|
||||
}
|
@ -74,7 +74,7 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
|
||||
super.onCreate(savedInstanceState);
|
||||
setLayout(preferences);
|
||||
|
||||
ResourceCache.instance.initCaptions(R.string.class, this);
|
||||
ResourceCache.instance.initCaptions(ApplicationContext.getInstance(), R.string.class);
|
||||
firstTimeInit(preferences);
|
||||
|
||||
vibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
|
||||
|
@ -16,7 +16,9 @@ import org.achartengine.model.XYMultipleSeriesDataset;
|
||||
import org.achartengine.model.XYSeries;
|
||||
import org.achartengine.renderer.XYMultipleSeriesRenderer;
|
||||
import org.achartengine.renderer.XYSeriesRenderer;
|
||||
import org.achartengine.util.MathHelper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.help.HelpActivity;
|
||||
import org.solovyev.common.utils.StringUtils;
|
||||
|
||||
@ -56,47 +58,12 @@ public class CalculatorActivityLauncher {
|
||||
}
|
||||
|
||||
public static void plotGraph(@NotNull final Context context, @NotNull Generic generic, @NotNull Constant constant) throws ArithmeticException {
|
||||
|
||||
final XYSeries series = new XYSeries(generic.toString());
|
||||
|
||||
final double min = -10;
|
||||
final double max = 10;
|
||||
final double step = 0.5;
|
||||
double x = min;
|
||||
while (x <= max) {
|
||||
Generic numeric = generic.substitute(constant, Expression.valueOf(x)).numeric();
|
||||
series.add(x, unwrap(numeric));
|
||||
x += step;
|
||||
}
|
||||
final XYMultipleSeriesDataset data = new XYMultipleSeriesDataset();
|
||||
data.addSeries(series);
|
||||
final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
|
||||
renderer.addSeriesRenderer(new XYSeriesRenderer());
|
||||
final Intent intent = ChartFactory.getLineChartIntent(context, data, renderer);
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(CalculatorPlotActivity.INPUT, new CalculatorPlotActivity.Input(generic.toString(), constant.getName()));
|
||||
intent.setClass(context, CalculatorPlotActivity.class);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
private static double unwrap(Generic numeric) {
|
||||
if ( numeric instanceof JsclInteger) {
|
||||
return ((JsclInteger) numeric).intValue();
|
||||
} else if ( numeric instanceof NumericWrapper ) {
|
||||
return unwrap(((NumericWrapper) numeric).content());
|
||||
} else {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
}
|
||||
|
||||
private static double unwrap(Numeric content) {
|
||||
if (content instanceof Real) {
|
||||
return ((Real) content).doubleValue();
|
||||
} else if ( content instanceof Complex) {
|
||||
return ((Complex) content).realPart();
|
||||
} else {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void createVar(@NotNull final Context context, @NotNull CalculatorModel calculatorModel) {
|
||||
if (calculatorModel.getDisplay().isValid() ) {
|
||||
final String varValue = calculatorModel.getDisplay().getText().toString();
|
||||
|
@ -6,12 +6,262 @@
|
||||
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.achartengine.GraphicalActivity;
|
||||
import android.app.Activity;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.Toast;
|
||||
import jscl.math.Expression;
|
||||
import jscl.math.Generic;
|
||||
import jscl.math.JsclInteger;
|
||||
import jscl.math.NumericWrapper;
|
||||
import jscl.math.function.Constant;
|
||||
import jscl.math.numeric.Complex;
|
||||
import jscl.math.numeric.Numeric;
|
||||
import jscl.math.numeric.Real;
|
||||
import jscl.text.ParseException;
|
||||
import org.achartengine.ChartFactory;
|
||||
import org.achartengine.GraphicalView;
|
||||
import org.achartengine.chart.AbstractChart;
|
||||
import org.achartengine.chart.LineChart;
|
||||
import org.achartengine.model.XYMultipleSeriesDataset;
|
||||
import org.achartengine.model.XYSeries;
|
||||
import org.achartengine.renderer.BasicStroke;
|
||||
import org.achartengine.renderer.XYMultipleSeriesRenderer;
|
||||
import org.achartengine.renderer.XYSeriesRenderer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.view.widgets.NumberPicker;
|
||||
import org.solovyev.common.utils.MutableObject;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 12/1/11
|
||||
* Time: 12:40 AM
|
||||
*/
|
||||
public class CalculatorPlotActivity extends GraphicalActivity{
|
||||
public class CalculatorPlotActivity extends Activity {
|
||||
|
||||
private static final int DEFAULT_NUMBER_OF_STEPS = 100;
|
||||
|
||||
private static final int DEFAULT_MIN_NUMBER = -10;
|
||||
|
||||
private static final int DEFAULT_MAX_NUMBER = 10;
|
||||
|
||||
public static final String INPUT = "org.solovyev.android.calculator.CalculatorPlotActivity_input";
|
||||
|
||||
public static final long EVAL_DELAY_MILLIS = 1000;
|
||||
|
||||
/**
|
||||
* The encapsulated graphical view.
|
||||
*/
|
||||
private GraphicalView graphicalView;
|
||||
|
||||
@NotNull
|
||||
private Generic expression;
|
||||
|
||||
@NotNull
|
||||
private Constant variable;
|
||||
|
||||
private double minValue = DEFAULT_MIN_NUMBER;
|
||||
|
||||
private double maxValue = DEFAULT_MAX_NUMBER;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Bundle extras = getIntent().getExtras();
|
||||
|
||||
final Input input = (Input) extras.getSerializable(INPUT);
|
||||
|
||||
try {
|
||||
this.expression = Expression.valueOf(input.getExpression());
|
||||
this.variable = new Constant(input.getVariableName());
|
||||
|
||||
String title = extras.getString(ChartFactory.TITLE);
|
||||
if (title == null) {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
} else if (title.length() > 0) {
|
||||
setTitle(title);
|
||||
}
|
||||
|
||||
setContentView(R.layout.calc_plot_view);
|
||||
|
||||
setGraphicalView(minValue, maxValue);
|
||||
|
||||
final NumberPicker minXNumberPicker = (NumberPicker)findViewById(R.id.plot_x_min_value);
|
||||
final NumberPicker maxXNumberPicker = (NumberPicker)findViewById(R.id.plot_x_max_value);
|
||||
|
||||
minXNumberPicker.setRange(Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||
minXNumberPicker.setCurrent(DEFAULT_MIN_NUMBER);
|
||||
maxXNumberPicker.setRange(Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||
maxXNumberPicker.setCurrent(DEFAULT_MAX_NUMBER);
|
||||
|
||||
|
||||
minXNumberPicker.setOnChangeListener(new BoundariesChangeListener(true));
|
||||
maxXNumberPicker.setOnChangeListener(new BoundariesChangeListener(false));
|
||||
|
||||
} catch (ParseException e) {
|
||||
Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void setGraphicalView(final double minValue, final double maxValue) {
|
||||
final ViewGroup graphContainer = (ViewGroup) findViewById(R.id.plot_graph_container);
|
||||
|
||||
if (graphicalView != null) {
|
||||
graphContainer.removeView(graphicalView);
|
||||
}
|
||||
|
||||
graphicalView = new GraphicalView(this, prepareChart(minValue, maxValue, expression, variable));
|
||||
graphContainer.addView(graphicalView);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final static MutableObject<Runnable> pendingOperation = new MutableObject<Runnable>();
|
||||
|
||||
private class BoundariesChangeListener implements NumberPicker.OnChangedListener {
|
||||
|
||||
private boolean min;
|
||||
|
||||
private BoundariesChangeListener(boolean min) {
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onChanged(NumberPicker picker, int oldVal, final int newVal) {
|
||||
if (min) {
|
||||
minValue = newVal;
|
||||
} else {
|
||||
maxValue = newVal;
|
||||
}
|
||||
|
||||
pendingOperation.setObject(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// allow only one runner at one time
|
||||
synchronized (pendingOperation) {
|
||||
//lock all operations with history
|
||||
if (pendingOperation.getObject() == this) {
|
||||
// actually nothing shall be logged while text operations are done
|
||||
setGraphicalView(CalculatorPlotActivity.this.minValue, CalculatorPlotActivity.this.maxValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new Handler().postDelayed(pendingOperation.getObject(), EVAL_DELAY_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
private static AbstractChart prepareChart(final double minValue, final double maxValue, @NotNull final Generic expression, @NotNull final Constant variable) {
|
||||
final XYSeries realSeries = new XYSeries(expression.toString());
|
||||
final XYSeries imagSeries = new XYSeries("Im(" + expression.toString() + ")");
|
||||
|
||||
boolean imagExists = false;
|
||||
|
||||
final double min = Math.min(minValue, maxValue);
|
||||
final double max = Math.max(minValue, maxValue);
|
||||
final int numberOfSteps = DEFAULT_NUMBER_OF_STEPS;
|
||||
final double step = Math.max((max - min) / numberOfSteps, 0.001);
|
||||
double x = min;
|
||||
while (x <= max) {
|
||||
Generic numeric = expression.substitute(variable, Expression.valueOf(x)).numeric();
|
||||
final Complex c = unwrap(numeric);
|
||||
realSeries.add(x, prepareY(c.realPart()));
|
||||
imagSeries.add(x, prepareY(c.imaginaryPart()));
|
||||
if (c.imaginaryPart() != 0d) {
|
||||
imagExists = true;
|
||||
}
|
||||
x += step;
|
||||
}
|
||||
|
||||
final XYMultipleSeriesDataset data = new XYMultipleSeriesDataset();
|
||||
data.addSeries(realSeries);
|
||||
if (imagExists) {
|
||||
data.addSeries(imagSeries);
|
||||
}
|
||||
|
||||
final XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
|
||||
renderer.setZoomEnabled(false);
|
||||
renderer.setZoomEnabled(false, false);
|
||||
renderer.addSeriesRenderer(createCommonRenderer());
|
||||
renderer.setPanEnabled(false);
|
||||
renderer.setPanEnabled(false, false);
|
||||
if (imagExists) {
|
||||
final XYSeriesRenderer imagRenderer = createCommonRenderer();
|
||||
imagRenderer.setStroke(BasicStroke.DOTTED);
|
||||
renderer.addSeriesRenderer(imagRenderer);
|
||||
}
|
||||
|
||||
return new LineChart(data, renderer);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static XYSeriesRenderer createCommonRenderer() {
|
||||
final XYSeriesRenderer renderer = new XYSeriesRenderer();
|
||||
renderer.setColor(Color.WHITE);
|
||||
renderer.setStroke(BasicStroke.SOLID);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
private static double prepareY(double y) {
|
||||
if (Double.isNaN(y) || Double.isInfinite(y)) {
|
||||
return 0d;
|
||||
} else {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Complex unwrap(@Nullable Generic numeric) {
|
||||
if (numeric instanceof JsclInteger) {
|
||||
return Complex.valueOf(((JsclInteger) numeric).intValue(), 0d);
|
||||
} else if (numeric instanceof NumericWrapper) {
|
||||
return unwrap(((NumericWrapper) numeric).content());
|
||||
} else {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Complex unwrap(@Nullable Numeric content) {
|
||||
if (content instanceof Real) {
|
||||
return Complex.valueOf(((Real) content).doubleValue(), 0d);
|
||||
} else if (content instanceof Complex) {
|
||||
return ((Complex) content);
|
||||
} else {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Input implements Serializable {
|
||||
|
||||
@NotNull
|
||||
private String expression;
|
||||
|
||||
@NotNull
|
||||
private String variableName;
|
||||
|
||||
public Input(@NotNull String expression, @NotNull String variableName) {
|
||||
this.expression = expression;
|
||||
this.variableName = variableName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getVariableName() {
|
||||
return variableName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
package org.solovyev.android.calculator.jscl;
|
||||
|
||||
import jscl.text.Messages;
|
||||
import jscl.text.msg.Messages;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.math.MathType;
|
||||
|
@ -29,6 +29,8 @@ public class AutoResizeTextView extends TextView {
|
||||
// Minimum text size for this text view
|
||||
public static final float MIN_TEXT_SIZE = 20;
|
||||
|
||||
private float initialTextSize = 100;
|
||||
|
||||
// Interface for resize notifications
|
||||
public interface OnTextResizeListener {
|
||||
public void onTextResize(TextView textView, float oldSize, float newSize);
|
||||
@ -207,7 +209,8 @@ public class AutoResizeTextView extends TextView {
|
||||
Log.d(this.getClass().getName(), "Old text size: " + oldTextSize);
|
||||
|
||||
// If there is a max text size set, use the lesser of that and the default text size
|
||||
float newTextSize = 100;
|
||||
// todo serso: +2 is a workaround => to be checked boundary constraints
|
||||
float newTextSize = initialTextSize + 2;
|
||||
|
||||
int newTextHeight;
|
||||
|
||||
@ -227,7 +230,7 @@ public class AutoResizeTextView extends TextView {
|
||||
if (newTextSize <= minTextSize) {
|
||||
break;
|
||||
}
|
||||
newTextSize = Math.max(newTextSize - 2, minTextSize);
|
||||
newTextSize = Math.max(newTextSize - 1, minTextSize);
|
||||
newTextHeight = getTextRect(text, textPaint, width, newTextSize);
|
||||
logDimensions(newTextSize, newTextHeight);
|
||||
}
|
||||
@ -236,7 +239,7 @@ public class AutoResizeTextView extends TextView {
|
||||
if (newTextSize <= minTextSize) {
|
||||
break;
|
||||
}
|
||||
newTextSize = Math.max(newTextSize + 2, minTextSize);
|
||||
newTextSize = Math.max(newTextSize + 1, minTextSize);
|
||||
newTextHeight = getTextRect(text, textPaint, width, newTextSize);
|
||||
logDimensions(newTextSize, newTextHeight);
|
||||
}
|
||||
@ -247,6 +250,8 @@ public class AutoResizeTextView extends TextView {
|
||||
}
|
||||
}
|
||||
|
||||
initialTextSize = newTextSize;
|
||||
|
||||
// If we had reached our minimum text size and still don't fit, append an ellipsis
|
||||
if (addEllipsis && newTextSize == minTextSize && newTextHeight > height) {
|
||||
// Draw using a static layout
|
||||
|
@ -7,11 +7,14 @@
|
||||
package org.solovyev.android.view.prefs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.CalculatorActivity;
|
||||
import org.solovyev.android.view.widgets.DragButton;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@ -33,7 +36,13 @@ public enum ResourceCache {
|
||||
// ids of buttons in R.class
|
||||
private List<Integer> buttonIds = null;
|
||||
|
||||
private static final Map<String, Map<String, String>> captions = new HashMap<String, Map<String, String>>();
|
||||
// first map: key: language id, value: map of captions and translations
|
||||
// second mal: key: caption id, value: translation
|
||||
private final Map<String, Map<String, String>> captions = new HashMap<String, Map<String, String>>();
|
||||
|
||||
private Class<?> resourceClass;
|
||||
|
||||
private Context context;
|
||||
|
||||
public List<Integer> getDragButtonIds() {
|
||||
return dragButtonIds;
|
||||
@ -43,11 +52,28 @@ public enum ResourceCache {
|
||||
return buttonIds;
|
||||
}
|
||||
|
||||
public void initCaptions(@NotNull Class<?> resourceClass, @NotNull Activity activity) {
|
||||
final Locale locale = Locale.getDefault();
|
||||
/**
|
||||
* Method load captions for default locale using android R class
|
||||
* @param context STATIC CONTEXT
|
||||
* @param resourceClass class of captions in android (SUBCLASS of R class)
|
||||
*/
|
||||
public void initCaptions(@NotNull Context context, @NotNull Class<?> resourceClass) {
|
||||
initCaptions(context, resourceClass, Locale.getDefault());
|
||||
}
|
||||
|
||||
if (!captions.containsKey(locale.getLanguage())) {
|
||||
/**
|
||||
* Method load captions for specified locale using android R class
|
||||
* @param context STATIC CONTEXT
|
||||
* @param resourceClass class of captions in android (SUBCLASS of R class)
|
||||
* @param locale language to be used for translation
|
||||
*/
|
||||
public void initCaptions(@NotNull Context context, @NotNull Class<?> resourceClass, @NotNull Locale locale) {
|
||||
assert this.resourceClass == null || this.resourceClass.equals(resourceClass);
|
||||
|
||||
this.context = context;
|
||||
this.resourceClass = resourceClass;
|
||||
|
||||
if (!initialized(locale)) {
|
||||
final Map<String, String> captionsByLanguage = new HashMap<String, String>();
|
||||
|
||||
for (Field field : resourceClass.getDeclaredFields()) {
|
||||
@ -55,7 +81,7 @@ public enum ResourceCache {
|
||||
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
|
||||
try {
|
||||
int captionId = field.getInt(resourceClass);
|
||||
captionsByLanguage.put(field.getName(), activity.getString(captionId));
|
||||
captionsByLanguage.put(field.getName(), context.getString(captionId));
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(ResourceCache.class.getName(), e.getMessage());
|
||||
}
|
||||
@ -66,13 +92,39 @@ public enum ResourceCache {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean initialized(@NotNull Locale locale) {
|
||||
return captions.containsKey(locale.getLanguage());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param captionId id of caption to be translated
|
||||
* @return translation by caption id in default language, null if no translation in default language present
|
||||
*/
|
||||
@Nullable
|
||||
public String getCaption(@NotNull String captionId) {
|
||||
final Locale locale = Locale.getDefault();
|
||||
return getCaption(captionId, Locale.getDefault());
|
||||
}
|
||||
|
||||
final Map<String, String> captionsByLanguage = captions.get(locale.getLanguage());
|
||||
|
||||
/**
|
||||
* @param captionId id of caption to be translated
|
||||
* @param locale language to be used for translation
|
||||
* @return translation by caption id in specified language, null if no translation in specified language present
|
||||
*/
|
||||
@Nullable
|
||||
public String getCaption(@NotNull String captionId, @NotNull final Locale locale) {
|
||||
Map<String, String> captionsByLanguage = captions.get(locale.getLanguage());
|
||||
if (captionsByLanguage != null) {
|
||||
return captionsByLanguage.get(captionId);
|
||||
} else {
|
||||
assert resourceClass != null && context != null;
|
||||
|
||||
initCaptions(context, resourceClass, locale);
|
||||
|
||||
captionsByLanguage = captions.get(locale.getLanguage());
|
||||
if (captionsByLanguage != null) {
|
||||
return captionsByLanguage.get(captionId);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -412,7 +412,7 @@ public class NumberPicker extends LinearLayout {
|
||||
}
|
||||
|
||||
private static final char[] DIGIT_CHARACTERS = new char[] {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
||||
'-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
||||
};
|
||||
|
||||
private NumberPickerButton mIncrementButton;
|
||||
|
Loading…
Reference in New Issue
Block a user