This commit is contained in:
serso 2016-02-28 13:08:10 +01:00
parent 4070de7693
commit f7b66673a5
16 changed files with 131 additions and 748 deletions

View File

@ -28,7 +28,11 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import dagger.Lazy;
import jscl.math.Generic;
import jscl.math.function.Constant;
import jscl.math.function.CustomFunction;
import org.solovyev.android.Activities;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.about.AboutActivity;
@ -38,31 +42,40 @@ import org.solovyev.android.calculator.functions.FunctionsActivity;
import org.solovyev.android.calculator.history.HistoryActivity;
import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity;
import org.solovyev.android.calculator.operators.OperatorsActivity;
import org.solovyev.android.calculator.plot.CalculatorPlotter;
import org.solovyev.android.calculator.plot.ExpressionFunction;
import org.solovyev.android.calculator.plot.PlotActivity;
import org.solovyev.android.calculator.preferences.PreferencesActivity;
import org.solovyev.android.calculator.variables.CppVariable;
import org.solovyev.android.calculator.variables.EditVariableFragment;
import org.solovyev.android.calculator.variables.VariablesActivity;
import org.solovyev.android.calculator.variables.VariablesFragment;
import org.solovyev.android.plotter.Plotter;
import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.Strings;
import jscl.math.Generic;
import jscl.math.function.Constant;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Singleton
public final class ActivityLauncher implements CalculatorEventListener {
@Inject
Application application;
@Inject
Lazy<Plotter> plotter;
@Inject
Lazy<ErrorReporter> errorReporter;
@Inject
Lazy<Display> display;
@Inject
Lazy<VariablesRegistry> variablesRegistry;
@Inject
Notifier notifier;
@Nullable
private CalculatorActivity activity;
@ -109,7 +122,7 @@ public final class ActivityLauncher implements CalculatorEventListener {
final CppFunction.Builder builder = CppFunction.builder("", functionBody);
final Generic generic = viewState.getResult();
if (generic != null) {
final Set<Constant> constants = CalculatorUtils.getNotSystemConstants(generic);
final Set<Constant> constants = generic.getUndefinedConstants(null);
for (Constant constant : constants) {
builder.withParameter(constant.getName());
}
@ -128,26 +141,13 @@ public final class ActivityLauncher implements CalculatorEventListener {
return ((CalculatorApplication) App.getApplication()).notifier;
}
public static void tryPlot() {
final CalculatorPlotter plotter = Locator.getInstance().getPlotter();
final Display display = App.getDisplay();
final DisplayState viewState = display.getState();
if (viewState.valid) {
final String functionValue = viewState.text;
final Generic expression = viewState.getResult();
if (!Strings.isEmpty(functionValue) && expression != null) {
if (plotter.isPlotPossibleFor(expression)) {
plotter.plot(expression);
} else {
getNotifier().showMessage(R.string.cpp_plot_too_many_variables, MessageType.error);
}
} else {
getNotifier().showMessage(R.string.cpp_plot_empty_function_error, MessageType.error);
}
} else {
public void plotDisplayedExpression() {
final DisplayState state = display.get().getState();
if (!state.valid) {
getNotifier().showMessage(R.string.not_valid_result, MessageType.error);
return;
}
plot(state.getResult());
}
public void showHistory() {
@ -161,7 +161,7 @@ public final class ActivityLauncher implements CalculatorEventListener {
public void showWidgetSettings() {
final Context context = getContext();
show(context, PreferencesActivity.makeIntent(context, R.xml.preferences_widget,
R.string.prefs_widget_title));
R.string.prefs_widget_title));
}
public void showOperators() {
@ -258,4 +258,44 @@ public final class ActivityLauncher implements CalculatorEventListener {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
}
void plot(@Nullable Generic expression) {
if (expression == null) {
notifier.showMessage(R.string.cpp_plot_empty_function_error);
return;
}
final String content = expression.toString();
if (TextUtils.isEmpty(content)) {
notifier.showMessage(R.string.cpp_plot_empty_function_error);
return;
}
final List<String> parameters = new ArrayList<>();
for (Constant parameter : expression.getUndefinedConstants(variablesRegistry.get())) {
parameters.add(parameter.getName());
}
if (parameters.size() > 2) {
notifier.showMessage(R.string.cpp_plot_too_many_variables);
return;
}
try {
final CustomFunction f = new CustomFunction.Builder().setName("").setParameterNames(parameters).setContent(content).create();
final ExpressionFunction ef = new ExpressionFunction(f, false);
plotter.get().add(ef);
showPlotter();
} catch (RuntimeException e) {
errorReporter.get().onException(e);
notifier.showMessage(e.getLocalizedMessage());
}
}
public boolean canPlot(@Nullable Generic expression) {
if (expression == null || TextUtils.isEmpty(expression.toString())) {
return false;
}
if (expression.getUndefinedConstants(variablesRegistry.get()).size() > 2) {
return false;
}
return true;
}
}

View File

@ -27,9 +27,8 @@ import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import android.util.TimingLogger;
import com.squareup.otto.Bus;
import jscl.MathEngine;
import org.acra.ACRA;
import org.acra.ACRAConfiguration;
import org.acra.sender.HttpSender;
@ -38,18 +37,13 @@ import org.solovyev.android.calculator.floating.FloatingCalculatorActivity;
import org.solovyev.android.calculator.history.History;
import org.solovyev.android.calculator.language.Language;
import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.calculator.plot.AndroidCalculatorPlotter;
import org.solovyev.android.calculator.plot.CalculatorPlotterImpl;
import org.solovyev.common.msg.MessageType;
import jscl.MathEngine;
import java.util.Locale;
import java.util.concurrent.Executor;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Locale;
import java.util.concurrent.Executor;
public class CalculatorApplication extends android.app.Application implements SharedPreferences.OnSharedPreferenceChangeListener {
@ -143,11 +137,7 @@ public class CalculatorApplication extends android.app.Application implements Sh
languages.updateContextLocale(this, true);
App.getGa().reportInitially(preferences);
Locator.getInstance().init(calculator,
engine,
keyboard,
new AndroidCalculatorPlotter(this, new CalculatorPlotterImpl(calculator))
);
Locator.getInstance().init(calculator, engine, keyboard);
calculator.init(initThread);

View File

@ -22,16 +22,13 @@
package org.solovyev.android.calculator;
import org.solovyev.android.calculator.plot.CalculatorPlotter;
import javax.annotation.Nonnull;
public interface CalculatorLocator {
void init(@Nonnull Calculator calculator,
@Nonnull Engine engine,
@Nonnull Keyboard keyboard,
@Nonnull CalculatorPlotter plotter);
@Nonnull Keyboard keyboard);
@Nonnull
Calculator getCalculator();
@ -42,6 +39,4 @@ public interface CalculatorLocator {
@Nonnull
Keyboard getKeyboard();
@Nonnull
CalculatorPlotter getPlotter();
}

View File

@ -22,15 +22,6 @@
package org.solovyev.android.calculator;
import jscl.math.Generic;
import jscl.math.function.Constant;
import jscl.math.function.IConstant;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 9/22/12
@ -42,18 +33,4 @@ public final class CalculatorUtils {
throw new AssertionError();
}
@Nonnull
public static Set<Constant> getNotSystemConstants(@Nonnull Generic expression) {
final Set<Constant> notSystemConstants = new HashSet<Constant>();
for (Constant constant : expression.getConstants()) {
IConstant var = Locator.getInstance().getEngine().getVariablesRegistry().get(constant.getName());
if (var != null && !var.isSystem() && !var.isDefined()) {
notSystemConstants.add(constant);
}
}
return notSystemConstants;
}
}

View File

@ -57,8 +57,6 @@ public class Display {
Lazy<Notifier> notifier;
@Inject
Lazy<PreferredPreferences> preferredPreferences;
@Inject
ActivityLauncher launcher;
@Nullable
private DisplayView view;
@Nonnull

View File

@ -37,17 +37,12 @@ import butterknife.ButterKnife;
import com.squareup.otto.Bus;
import jscl.NumeralBase;
import jscl.math.Generic;
import jscl.math.function.Constant;
import jscl.math.function.CustomFunction;
import org.solovyev.android.calculator.converter.ConverterFragment;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.plot.ExpressionFunction;
import org.solovyev.android.plotter.Plotter;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
public class DisplayFragment extends BaseFragment implements View.OnClickListener,
MenuItem.OnMenuItemClickListener {
@ -146,8 +141,7 @@ public class DisplayFragment extends BaseFragment implements View.OnClickListene
addMenu(menu, R.string.c_convert, this);
}
}
final int parameters = CalculatorUtils.getNotSystemConstants(result).size();
if (parameters >= 0 && parameters <= 2) {
if (launcher.canPlot(result)) {
addMenu(menu, R.string.c_plot, this);
}
}
@ -216,21 +210,7 @@ public class DisplayFragment extends BaseFragment implements View.OnClickListene
ConverterFragment.show(getActivity(), getValue(result));
return true;
case R.string.c_plot:
if (result != null) {
try {
final List<String> parameters = new ArrayList<>();
for (Constant parameter : CalculatorUtils.getNotSystemConstants(result)) {
parameters.add(parameter.getName());
}
new CustomFunction.Builder().setParameterNames(parameters).setContent(state.text).create();
final CustomFunction f = new CustomFunction.Builder().setName("").setParameterNames(parameters).setContent(result.toString()).create();
final ExpressionFunction ef = new ExpressionFunction(f, false);
plotter.add(ef);
launcher.showPlotter();
} catch (RuntimeException e) {
errorReporter.onException(e);
}
}
launcher.plot(result);
return true;
default:
return false;

View File

@ -22,8 +22,6 @@
package org.solovyev.android.calculator;
import org.solovyev.android.calculator.plot.CalculatorPlotter;
import javax.annotation.Nonnull;
public class Locator implements CalculatorLocator {
@ -36,8 +34,6 @@ public class Locator implements CalculatorLocator {
private Calculator calculator;
@Nonnull
private Keyboard keyboard;
@Nonnull
private CalculatorPlotter calculatorPlotter;
public Locator() {
}
@ -50,13 +46,10 @@ public class Locator implements CalculatorLocator {
@Override
public void init(@Nonnull Calculator calculator,
@Nonnull Engine engine,
@Nonnull Keyboard keyboard,
@Nonnull CalculatorPlotter plotter) {
@Nonnull Keyboard keyboard) {
this.calculator = calculator;
this.engine = engine;
this.calculatorPlotter = plotter;
this.keyboard = keyboard;
}
@ -78,9 +71,4 @@ public class Locator implements CalculatorLocator {
return keyboard;
}
@Nonnull
@Override
public CalculatorPlotter getPlotter() {
return calculatorPlotter;
}
}

View File

@ -24,17 +24,14 @@ package org.solovyev.android.calculator;
import android.app.Application;
import android.os.Handler;
import android.support.annotation.StringRes;
import android.widget.Toast;
import org.solovyev.android.Threads;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.List;
@Singleton
public class Notifier {
@ -48,27 +45,27 @@ public class Notifier {
}
public void showMessage(@Nonnull Message message) {
showMessageInUiThread(message.getLocalizedMessage());
showMessage(message.getLocalizedMessage());
}
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nonnull List<Object> parameters) {
showMessage(new AndroidMessage(messageCode, messageType, application, parameters));
public void showMessage(@StringRes int message, Object... parameters) {
showMessage(application.getString(message, parameters));
}
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters) {
showMessage(new AndroidMessage(messageCode, messageType, application, parameters));
public void showMessage(@StringRes int message) {
showMessage(application.getString(message));
}
private void showMessageInUiThread(@Nonnull final String message) {
public void showMessage(@Nonnull final String message) {
if (Threads.isUiThread()) {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
} else {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
}
});
return;
}
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
}
});
}
}

View File

@ -1,13 +1,5 @@
package org.solovyev.android.calculator.keyboard;
import static android.view.HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING;
import static android.view.HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING;
import static android.view.HapticFeedbackConstants.KEYBOARD_TAP;
import static org.solovyev.android.calculator.App.cast;
import static org.solovyev.android.calculator.App.getScreenMetrics;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
@ -20,15 +12,8 @@ import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.solovyev.android.Views;
import org.solovyev.android.calculator.ActivityUi;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.Calculator;
import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.Keyboard;
import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.PreferredPreferences;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.buttons.CppSpecialButton;
import org.solovyev.android.calculator.view.ScreenMetrics;
import org.solovyev.android.views.Adjuster;
@ -37,11 +22,16 @@ import org.solovyev.android.views.dragbutton.DragButton;
import org.solovyev.android.views.dragbutton.DragDirection;
import org.solovyev.android.views.dragbutton.SimpleDragListener;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import static android.view.HapticFeedbackConstants.*;
import static org.solovyev.android.calculator.App.cast;
import static org.solovyev.android.calculator.App.getScreenMetrics;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile;
public abstract class BaseKeyboardUi implements SharedPreferences.OnSharedPreferenceChangeListener, SimpleDragListener.DragProcessor, View.OnClickListener {
@ -67,6 +57,8 @@ public abstract class BaseKeyboardUi implements SharedPreferences.OnSharedPrefer
@Inject
Calculator calculator;
@Inject
ActivityLauncher launcher;
@Inject
PreferredPreferences preferredPreferences;
protected int orientation = Configuration.ORIENTATION_PORTRAIT;
private int textSize;

View File

@ -17,7 +17,6 @@ import butterknife.Bind;
import butterknife.ButterKnife;
import jscl.NumeralBase;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.ActivityLauncher;
import org.solovyev.android.calculator.Engine;
import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.R;
@ -121,7 +120,7 @@ public class PartialKeyboardUi extends BaseKeyboardUi {
return true;
case R.id.cpp_button_equals:
if (direction == down) {
ActivityLauncher.tryPlot();
launcher.plotDisplayedExpression();
return true;
} else if (direction == up) {
calculator.simplify();

View File

@ -1,442 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import jscl.math.Generic;
import jscl.math.function.Constant;
import org.solovyev.android.calculator.Calculator;
import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CalculatorUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CalculatorPlotterImpl implements CalculatorPlotter {
@Nonnull
private final List<PlotFunction> functions = new ArrayList<PlotFunction>();
@Nonnull
private final Calculator calculator;
private final PlotResourceManager resourceManager = new MapPlotResourceManager();
private boolean plot3d = false;
private boolean adjustYAxis = true;
private boolean plotImag = false;
private int arity = 0;
@Nonnull
private PlotBoundaries plotBoundaries = PlotBoundaries.newDefaultInstance();
@Nonnull
private PlotData plotData = new PlotData(Collections.<PlotFunction>emptyList(), plot3d, true, plotBoundaries);
public CalculatorPlotterImpl(@Nonnull Calculator calculator) {
this.calculator = calculator;
}
@Nonnull
@Override
public PlotData getPlotData() {
return plotData;
}
@Override
public boolean addFunction(@Nonnull Generic expression) {
final List<Constant> variables = new ArrayList<Constant>(CalculatorUtils.getNotSystemConstants(expression));
if (variables.size() > 2) throw new AssertionError();
final Constant xVariable;
if (variables.size() > 0) {
xVariable = variables.get(0);
} else {
xVariable = null;
}
final Constant yVariable;
if (variables.size() > 1) {
yVariable = variables.get(1);
} else {
yVariable = null;
}
final XyFunction realXyFunction = new XyFunction(expression, xVariable, yVariable, false);
final XyFunction imagXyFunction = new XyFunction(expression, xVariable, yVariable, true);
// first create plot functions with default line definitions
PlotFunction realPlotFunction = new PlotFunction(realXyFunction);
PlotFunction imagPlotFunction = new PlotFunction(imagXyFunction);
// then remove all unpinned graphs and free their line definitions
removeAllUnpinnedExcept(realPlotFunction, imagPlotFunction);
// create plot functions with freed line definitions
realPlotFunction = newPlotFunction(realXyFunction);
imagPlotFunction = newPlotFunction(imagXyFunction);
final boolean realAdded = addFunction(realPlotFunction);
final boolean imagAdded = addFunction(plotImag ? imagPlotFunction : PlotFunction.invisible(imagPlotFunction));
return imagAdded || realAdded;
}
@Nonnull
private PlotFunction newPlotFunction(@Nonnull XyFunction xyFunction) {
return new PlotFunction(xyFunction, resourceManager.generateAndRegister());
}
@Override
public boolean addFunction(@Nonnull PlotFunction plotFunction) {
synchronized (functions) {
if (!functions.contains(plotFunction)) {
resourceManager.register(plotFunction.getPlotLineDef());
functions.add(plotFunction);
onFunctionsChanged();
return true;
} else {
return false;
}
}
}
private boolean removeAllUnpinnedExcept(@Nonnull final PlotFunction... exceptFunctions) {
synchronized (functions) {
boolean changed = Iterables.removeIf(functions, new Predicate<PlotFunction>() {
@Override
public boolean apply(@Nullable PlotFunction function) {
if (function != null && !function.isPinned()) {
for (PlotFunction exceptFunction : exceptFunctions) {
if (exceptFunction.equals(function)) {
return false;
}
}
resourceManager.unregister(function.getPlotLineDef());
return true;
} else {
return false;
}
}
});
if (changed) {
onFunctionsChanged();
}
return changed;
}
}
@Override
public void removeAllUnpinned() {
synchronized (functions) {
boolean changed = Iterables.removeIf(functions, new Predicate<PlotFunction>() {
@Override
public boolean apply(@Nullable PlotFunction function) {
boolean removed = function != null && !function.isPinned();
if (removed) {
resourceManager.unregister(function.getPlotLineDef());
}
return removed;
}
});
if (changed) {
onFunctionsChanged();
}
}
}
@Override
public boolean removeFunction(@Nonnull PlotFunction plotFunction) {
synchronized (functions) {
boolean changed = functions.remove(plotFunction);
if (changed) {
resourceManager.unregister(plotFunction.getPlotLineDef());
onFunctionsChanged();
}
return changed;
}
}
@Override
public boolean addFunction(@Nonnull XyFunction xyFunction) {
return addFunction(newPlotFunction(xyFunction));
}
@Override
public boolean addFunction(@Nonnull XyFunction xyFunction, @Nonnull PlotLineDef functionLineDef) {
return addFunction(new PlotFunction(xyFunction, functionLineDef));
}
@Override
public boolean updateFunction(@Nonnull XyFunction xyFunction, @Nonnull PlotLineDef functionLineDef) {
final PlotFunction newFunction = new PlotFunction(xyFunction, functionLineDef);
return updateFunction(newFunction);
}
@Override
public boolean updateFunction(@Nonnull PlotFunction newFunction) {
boolean changed = updateFunction0(newFunction);
if (changed) {
firePlotDataChangedEvent();
}
return changed;
}
public boolean updateFunction0(@Nonnull PlotFunction newFunction) {
boolean changed = false;
synchronized (functions) {
for (int i = 0; i < functions.size(); i++) {
final PlotFunction oldFunction = functions.get(i);
if (oldFunction.equals(newFunction)) {
resourceManager.unregister(oldFunction.getPlotLineDef());
resourceManager.register(newFunction.getPlotLineDef());
// update old function
functions.set(i, newFunction);
changed = true;
break;
}
}
}
return changed;
}
@Override
public boolean removeFunction(@Nonnull XyFunction xyFunction) {
return removeFunction(new PlotFunction(xyFunction));
}
@Nonnull
@Override
public PlotFunction pin(@Nonnull PlotFunction plotFunction) {
final PlotFunction newFunction = PlotFunction.pin(plotFunction);
updateFunction0(newFunction);
return newFunction;
}
@Nonnull
@Override
public PlotFunction unpin(@Nonnull PlotFunction plotFunction) {
final PlotFunction newFunction = PlotFunction.unpin(plotFunction);
updateFunction0(newFunction);
return newFunction;
}
@Nonnull
@Override
public PlotFunction show(@Nonnull PlotFunction plotFunction) {
final PlotFunction newFunction = PlotFunction.visible(plotFunction);
updateFunction(newFunction);
return newFunction;
}
@Nonnull
@Override
public PlotFunction hide(@Nonnull PlotFunction plotFunction) {
final PlotFunction newFunction = PlotFunction.invisible(plotFunction);
updateFunction(newFunction);
return newFunction;
}
@Override
public void clearAllFunctions() {
synchronized (functions) {
resourceManager.unregisterAll();
functions.clear();
onFunctionsChanged();
}
}
@Nullable
@Override
public PlotFunction getFunctionById(@Nonnull final String functionId) {
synchronized (functions) {
return Iterables.find(functions, new Predicate<PlotFunction>() {
@Override
public boolean apply(@Nullable PlotFunction function) {
return function != null && function.getXyFunction().getId().equals(functionId);
}
}, null);
}
}
// NOTE: this method must be called from synchronized block
private void onFunctionsChanged() {
if (!Thread.holdsLock(functions)) throw new AssertionError();
int maxArity = 0;
for (PlotFunction function : functions) {
final XyFunction xyFunction = function.getXyFunction();
maxArity = Math.max(maxArity, xyFunction.getArity());
}
plot3d = maxArity > 1;
if (functions.isEmpty()) {
// no functions => new plot => default boundaries
this.plotBoundaries = PlotBoundaries.newDefaultInstance();
this.adjustYAxis = true;
}
arity = maxArity;
firePlotDataChangedEvent();
}
@Nonnull
@Override
public List<PlotFunction> getFunctions() {
synchronized (functions) {
return new ArrayList<PlotFunction>(functions);
}
}
@Nonnull
@Override
public List<PlotFunction> getVisibleFunctions() {
synchronized (functions) {
return Lists.newArrayList(Iterables.filter(functions, new Predicate<PlotFunction>() {
@Override
public boolean apply(@Nullable PlotFunction function) {
return function != null && function.isVisible();
}
}));
}
}
@Override
public void plot() {
calculator.fireCalculatorEvent(CalculatorEventType.plot_graph, null);
}
@Override
public void plot(@Nonnull Generic expression) {
addFunction(expression);
plot();
}
@Override
public boolean is2dPlotPossible() {
return arity < 2;
}
@Override
public boolean isPlotPossibleFor(@Nonnull Generic expression) {
boolean result = false;
int size = CalculatorUtils.getNotSystemConstants(expression).size();
if (size == 0 || size == 1 || size == 2) {
result = true;
}
return result;
}
@Override
public void setPlot3d(boolean plot3d) {
if (this.plot3d != plot3d) {
this.plot3d = plot3d;
firePlotDataChangedEvent();
}
}
private void firePlotDataChangedEvent() {
updatePlotData();
calculator.fireCalculatorEvent(CalculatorEventType.plot_data_changed, plotData);
}
private void updatePlotData() {
plotData = new PlotData(getVisibleFunctions(), plot3d, adjustYAxis, plotBoundaries);
}
@Override
public void setPlotImag(boolean plotImag) {
if (this.plotImag != plotImag) {
this.plotImag = plotImag;
if (toggleImagFunctions(this.plotImag)) {
firePlotDataChangedEvent();
}
}
}
@Override
public void savePlotBoundaries(@Nonnull PlotBoundaries plotBoundaries) {
if (!this.plotBoundaries.equals(plotBoundaries)) {
this.plotBoundaries = plotBoundaries;
this.adjustYAxis = false;
updatePlotData();
}
}
@Override
public void setPlotBoundaries(@Nonnull PlotBoundaries plotBoundaries) {
if (!this.plotBoundaries.equals(plotBoundaries)) {
this.plotBoundaries = plotBoundaries;
this.adjustYAxis = false;
firePlotDataChangedEvent();
}
}
private boolean toggleImagFunctions(boolean show) {
boolean changed = false;
synchronized (functions) {
for (int i = 0; i < functions.size(); i++) {
final PlotFunction plotFunction = functions.get(i);
if (plotFunction.getXyFunction().isImag()) {
functions.set(i, show ? PlotFunction.visible(plotFunction) : PlotFunction.invisible(plotFunction));
changed = true;
}
}
}
return changed;
}
}

View File

@ -1,152 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.content.Context;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.TextView;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R;
import org.solovyev.android.list.ListItem;
import org.solovyev.android.view.ViewBuilder;
import org.solovyev.android.view.ViewFromLayoutBuilder;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class PlotFunctionListItem implements ListItem {
private static final String PREFIX = "plot_function_";
@Nonnull
private PlotFunction plotFunction;
@Nonnull
private ViewBuilder<View> viewBuilder;
@Nonnull
private String tag;
public PlotFunctionListItem(@Nonnull PlotFunction plotFunction) {
this.plotFunction = plotFunction;
this.viewBuilder = ViewFromLayoutBuilder.newInstance(R.layout.cpp_plot_function_list_item);
this.tag = PREFIX + plotFunction.getXyFunction().getExpressionString();
}
@Nullable
@Override
public OnClickAction getOnClickAction() {
return null;
}
@Nullable
@Override
public OnClickAction getOnLongClickAction() {
return null;
}
@Nonnull
@Override
public View updateView(@Nonnull Context context, @Nonnull View view) {
final Object viewTag = view.getTag();
if (viewTag instanceof String) {
if (this.tag.equals(viewTag)) {
return view;
} else if (((String) viewTag).startsWith(PREFIX)) {
fillView(view, context);
return view;
} else {
return build(context);
}
}
return build(context);
}
@Nonnull
@Override
public View build(@Nonnull Context context) {
final View root = buildView(context);
fillView(root, context);
return root;
}
private View buildView(@Nonnull Context context) {
return viewBuilder.build(context);
}
private void fillView(@Nonnull View root, @Nonnull final Context context) {
root.setTag(tag);
final CalculatorPlotter plotter = Locator.getInstance().getPlotter();
final TextView expressionTextView = (TextView) root.findViewById(R.id.cpp_plot_function_expression_textview);
expressionTextView.setText(plotFunction.getXyFunction().getExpressionString());
final CheckBox pinnedCheckBox = (CheckBox) root.findViewById(R.id.cpp_plot_function_pinned_checkbox);
pinnedCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean pin) {
if (pin) {
if (!plotFunction.isPinned()) {
plotFunction = plotter.pin(plotFunction);
}
} else {
if (plotFunction.isPinned()) {
plotFunction = plotter.unpin(plotFunction);
}
}
}
});
pinnedCheckBox.setChecked(plotFunction.isPinned());
final CheckBox visibleCheckBox = (CheckBox) root.findViewById(R.id.cpp_plot_function_visible_checkbox);
visibleCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean show) {
if (show) {
if (!plotFunction.isVisible()) {
plotFunction = plotter.show(plotFunction);
}
} else {
if (plotFunction.isVisible()) {
plotFunction = plotter.hide(plotFunction);
}
}
}
});
visibleCheckBox.setChecked(plotFunction.isVisible());
final ImageButton settingsButton = (ImageButton) root.findViewById(R.id.cpp_plot_function_settings_button);
settingsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// FIXME: 2016-02-01
}
});
}
}

View File

@ -24,7 +24,6 @@ package org.solovyev.android.calculator;
import android.content.SharedPreferences;
import com.squareup.otto.Bus;
import org.solovyev.android.calculator.plot.CalculatorPlotter;
import java.util.concurrent.Executor;
@ -38,7 +37,7 @@ import static org.mockito.Mockito.mock;
public class AbstractCalculatorTest {
protected void setUp() throws Exception {
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), CalculatorTestUtils.newCalculatorEngine(), mock(Keyboard.class), mock(CalculatorPlotter.class));
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), CalculatorTestUtils.newCalculatorEngine(), mock(Keyboard.class));
Locator.getInstance().getEngine().init(new Executor() {
@Override
public void execute(Runnable command) {

View File

@ -36,7 +36,6 @@ import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.calculator.operators.OperatorsRegistry;
import org.solovyev.android.calculator.operators.PostfixFunctionsRegistry;
import org.solovyev.android.calculator.plot.CalculatorPlotter;
import jscl.JsclMathEngine;
@ -68,7 +67,7 @@ public class CalculatorTestUtils {
public static void staticSetUp() throws Exception {
App.init(new CalculatorApplication(), new Languages(new RoboSharedPreferences(new HashMap<String, Map<String, Object>>(), "test", 0)));
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class), mock(CalculatorPlotter.class));
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class));
Locator.getInstance().getEngine().init(new Executor() {
@Override
public void execute(Runnable command) {
@ -83,7 +82,7 @@ public class CalculatorTestUtils {
}
public static void staticSetUp(@Nullable Context context) throws Exception {
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class), mock(CalculatorPlotter.class));
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class));
Locator.getInstance().getEngine().init(new Executor() {
@Override
public void execute(Runnable command) {

View File

@ -1,17 +1,40 @@
package jscl.math;
import jscl.math.function.Constant;
import jscl.math.function.IConstant;
import jscl.mathml.MathML;
import jscl.text.ParserUtils;
import java.math.BigInteger;
import java.util.Set;
import org.solovyev.common.math.MathRegistry;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.Set;
public abstract class Generic implements Arithmetic<Generic>, Comparable {
@Nonnull
public Set<Constant> getUndefinedConstants(@Nonnull MathRegistry<IConstant> constantsRegistry) {
final Set<Constant> result = new HashSet<>();
for (Constant expressionConstant : getConstants()) {
final IConstant registryConstant = constantsRegistry.get(expressionConstant.getName());
if (registryConstant == null) {
continue;
}
if (registryConstant.isSystem()) {
continue;
}
if(registryConstant.isDefined()) {
continue;
}
result.add(expressionConstant);
}
return result;
}
public BigInteger toBigInteger() {
return null;
}

View File

@ -43,7 +43,7 @@ public class CustomFunction extends Function implements IFunction {
private CustomFunction(@Nonnull String name,
@Nonnull List<String> parameterNames,
@Nonnull String content,
@Nullable String description) {
@Nullable String description) throws CustomFunctionCalculationException {
super(name, new Generic[parameterNames.size()]);
this.parameterNames = parameterNames;
try {
@ -321,7 +321,7 @@ public class CustomFunction extends Function implements IFunction {
}
@Nonnull
public CustomFunction create() {
public CustomFunction create() throws CustomFunctionCalculationException {
final CustomFunction customFunction = new CustomFunction(name, parameterNames, prepareContent(content), description);
customFunction.setSystem(system);
if (id != null) {