User defined functions support

This commit is contained in:
Sergey Solovyev 2012-11-14 18:24:08 +04:00
parent 791eac433b
commit 357eed9f3e
15 changed files with 713 additions and 70 deletions

View File

@ -115,6 +115,16 @@ public enum CalculatorEventType {
// @NotNull IConstant // @NotNull IConstant
constant_removed, constant_removed,
// @NotNull Function
function_removed,
// @NotNull Function
function_added,
// @NotNull Change<Function>
function_changed,
/* /*
********************************************************************** **********************************************************************
* *

View File

@ -9,11 +9,14 @@ package org.solovyev.android.calculator;
import jscl.math.function.CustomFunction; import jscl.math.function.CustomFunction;
import jscl.math.function.Function; import jscl.math.function.Function;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.model.AFunction; import org.solovyev.android.calculator.model.AFunction;
import org.solovyev.android.calculator.model.Functions; import org.solovyev.android.calculator.model.Functions;
import org.solovyev.android.calculator.model.MathEntityBuilder;
import org.solovyev.common.JBuilder; import org.solovyev.common.JBuilder;
import org.solovyev.common.math.MathRegistry; import org.solovyev.common.math.MathRegistry;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -42,7 +45,24 @@ public class CalculatorFunctionsMathRegistry extends AbstractCalculatorMathRegis
public void load() { public void load() {
super.load(); super.load();
add(new CustomFunction.Builder(true, "log", new String[]{"base", "x"}, "ln(x)/ln(base)")); add(new CustomFunction.Builder(true, "log", Arrays.asList("base", "x"), "ln(x)/ln(base)"));
}
public static void saveFunction(@NotNull CalculatorMathRegistry<Function> registry,
@NotNull MathEntityBuilder<? extends Function> builder,
@Nullable Function editedInstance,
@NotNull Object source, boolean save) {
final Function addedFunction = registry.add(builder);
if (save) {
registry.save();
}
if (editedInstance == null) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.function_added, addedFunction, source);
} else {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.function_changed, ChangeImpl.newInstance(editedInstance, addedFunction), source);
}
} }
@NotNull @NotNull
@ -65,7 +85,9 @@ public class CalculatorFunctionsMathRegistry extends AbstractCalculatorMathRegis
@NotNull @NotNull
@Override @Override
protected JBuilder<? extends Function> createBuilder(@NotNull AFunction entity) { protected JBuilder<? extends Function> createBuilder(@NotNull AFunction entity) {
return new CustomFunction.Builder(entity.getName(), entity.getParameterNamesAsArray(), entity.getContent()); CustomFunction.Builder builder = new CustomFunction.Builder(entity.getName(), entity.getParameterNames(), entity.getContent());
builder.setDescription(entity.getDescription());
return builder;
} }
@Override @Override

View File

@ -6,15 +6,17 @@
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import jscl.math.function.IConstant;
import jscl.math.function.IFunction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
import org.simpleframework.xml.Transient;
import org.solovyev.android.calculator.MathPersistenceEntity; import org.solovyev.android.calculator.MathPersistenceEntity;
import org.solovyev.common.collections.CollectionsUtils; import org.solovyev.common.math.MathEntity;
import org.solovyev.common.text.CollectionTransformations;
import org.solovyev.common.text.StringMapper;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@ -24,7 +26,17 @@ import java.util.List;
*/ */
@Root @Root
public class AFunction implements MathPersistenceEntity { public class AFunction implements IFunction, MathPersistenceEntity {
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
@Transient
private Integer id;
@Element @Element
@NotNull @NotNull
@ -34,17 +46,95 @@ public class AFunction implements MathPersistenceEntity {
@NotNull @NotNull
private String content; private String content;
@Element(required = false)
@NotNull
private List<String> parameterNames = Collections.emptyList();
@Element
private boolean system;
@Element(required = false) @Element(required = false)
@Nullable @Nullable
private String parameterNames; private String description;
/*
**********************************************************************
*
* CONSTRUCTORS
*
**********************************************************************
*/
public AFunction() {
}
public AFunction(Integer id) {
this.id = id;
}
/*
**********************************************************************
*
* METHODS
*
**********************************************************************
*/
@Override
public void copy(@NotNull MathEntity mathEntity) {
if (mathEntity instanceof IFunction) {
final IFunction that = ((IFunction) mathEntity);
this.name = that.getName();
this.content = that.getContent();
this.description = this.getContent();
this.system = that.isSystem();
if (that.isIdDefined()) {
this.id = that.getId();
}
} else {
throw new IllegalArgumentException("Trying to make a copy of unsupported type: " + mathEntity.getClass());
}
}
@Override
public String toJava() {
return String.valueOf(this.content);
}
/*
**********************************************************************
*
* GETTERS/SEETTERS
*
**********************************************************************
*/
@NotNull @NotNull
public String getName() { public String getName() {
return name; return name;
} }
@Override
public boolean isSystem() {
return system;
}
@NotNull
@Override
public Integer getId() {
return this.id;
}
@Override
public boolean isIdDefined() {
return this.id != null;
}
@Override
public void setId(@NotNull Integer id) {
this.id = id;
}
public void setName(@NotNull String name) { public void setName(@NotNull String name) {
this.name = name; this.name = name;
} }
@ -54,26 +144,128 @@ public class AFunction implements MathPersistenceEntity {
return content; return content;
} }
@Nullable
@Override
public String getDescription() {
return this.description;
}
public void setContent(@NotNull String content) { public void setContent(@NotNull String content) {
this.content = content; this.content = content;
} }
@Nullable @NotNull
public String getParameterNames() { public List<String> getParameterNames() {
return parameterNames; return parameterNames;
} }
public void setParameterNames(@Nullable String[] parameterNames) { public void setParameterNames(@NotNull List<String> parameterNames) {
this.parameterNames = CollectionTransformations.formatValue(CollectionsUtils.asList(parameterNames), ";", new StringMapper());
}
public void setParameterNames(@Nullable String parameterNames) {
this.parameterNames = parameterNames; this.parameterNames = parameterNames;
} }
@NotNull /*
public String[] getParameterNamesAsArray() { **********************************************************************
final List<String> parameterNamesAsList = CollectionTransformations.split(parameterNames, ";"); *
return parameterNamesAsList.toArray(new String[parameterNamesAsList.size()]); * STATIC
*
**********************************************************************
*/
public static class Builder implements MathEntityBuilder<AFunction> {
@NotNull
private String name;
@Nullable
private String value;
private boolean system = false;
@Nullable
private String description;
@Nullable
private Integer id;
@NotNull
private List<String> parameterNames = Collections.emptyList();
public Builder() {
}
public Builder(@NotNull IFunction function) {
this.name = function.getName();
this.value = function.getContent();
this.system = function.isSystem();
this.description = function.getDescription();
this.id = function.getId();
}
public Builder(@NotNull IConstant function) {
this.name = function.getName();
this.value = function.getValue();
this.system = function.isSystem();
this.description = function.getDescription();
if (function.isIdDefined()) {
this.id = function.getId();
}
}
public Builder(@NotNull String name, @NotNull Double value) {
this(name, String.valueOf(value));
}
public Builder(@NotNull String name, @Nullable String value) {
this.name = name;
this.value = value;
}
@NotNull
public Builder setName(@NotNull String name) {
this.name = name;
return this;
}
@NotNull
public Builder setValue(@Nullable String value) {
this.value = value;
return this;
}
protected Builder setSystem(boolean system) {
this.system = system;
return this;
}
public void setParameterNames(@NotNull List<String> parameterNames) {
this.parameterNames = parameterNames;
}
@NotNull
public Builder setDescription(@Nullable String description) {
this.description = description;
return this;
}
@NotNull
public AFunction create() {
final AFunction result;
if (id != null) {
result = new AFunction(id);
} else {
result = new AFunction();
}
result.name = name;
result.content = value;
result.system = system;
result.description = description;
result.parameterNames = parameterNames;
return result;
}
} }
} }

View File

@ -1,6 +1,5 @@
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import jscl.math.function.CustomFunction;
import org.simpleframework.xml.ElementList; import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
import org.solovyev.android.calculator.MathEntityPersistenceContainer; import org.solovyev.android.calculator.MathEntityPersistenceContainer;
@ -16,7 +15,7 @@ import java.util.List;
@Root @Root
public class Functions implements MathEntityPersistenceContainer<AFunction> { public class Functions implements MathEntityPersistenceContainer<AFunction> {
@ElementList(type = CustomFunction.class) @ElementList(type = AFunction.class)
private List<AFunction> functions = new ArrayList<AFunction>(); private List<AFunction> functions = new ArrayList<AFunction>();
public Functions() { public Functions() {

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
a:layout_height="wrap_content"
a:layout_width="match_parent"
a:orientation="horizontal">
<Button
a:id="@+id/function_add_param_button"
a:layout_height="wrap_content"
a:layout_width="wrap_content"
a:text="+" />
</LinearLayout>

View File

@ -33,15 +33,10 @@
style="@style/default_text_size" style="@style/default_text_size"
a:text="@string/c_function_parameters"/> a:text="@string/c_function_parameters"/>
<LinearLayout <org.solovyev.android.calculator.function.FunctionParamsView
a:id="@+id/function_params_layout" a:id="@+id/function_params_layout"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:layout_width="match_parent" a:layout_width="match_parent"/>
a:orientation="vertical">
<include layout="@layout/function_edit_param" />
</LinearLayout>
<TextView a:layout_height="wrap_content" <TextView a:layout_height="wrap_content"
a:layout_width="match_parent" a:layout_width="match_parent"

View File

@ -5,21 +5,27 @@
a:layout_width="match_parent" a:layout_width="match_parent"
a:orientation="horizontal"> a:orientation="horizontal">
<Button
a:id="@+id/function_add_param_button"
a:layout_height="wrap_content"
a:layout_width="wrap_content"
a:text="+" />
<Button <Button
a:id="@+id/function_remove_param_button" a:id="@+id/function_remove_param_button"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:layout_width="wrap_content" a:layout_width="wrap_content"
a:visibility="gone"
a:text="-" /> a:text="-" />
<Button
a:id="@+id/function_up_param_button"
a:layout_height="wrap_content"
a:layout_width="wrap_content"
a:text="^" />
<Button
a:id="@+id/function_down_param_button"
a:layout_height="wrap_content"
a:layout_width="wrap_content"
a:text="v" />
<EditText <EditText
a:layout_height="wrap_content" a:id="@+id/function_param_edit_text"
a:layout_height="wrap_content"
a:layout_width="match_parent" a:layout_width="match_parent"
style="@style/default_text_size" style="@style/default_text_size"
a:inputType="text" /> a:inputType="text" />

View File

@ -239,4 +239,12 @@
<string name="c_function_description">Description</string> <string name="c_function_description">Description</string>
<string name="c_function_parameters">Parameters</string> <string name="c_function_parameters">Parameters</string>
<string name="function_create_function">Create function</string>
<string name="function_edit_function">Edit function</string>
<string name="function_name_is_not_valid">Name of function is not valid: name must start with letter, can contain letters, digits and underscore.</string>
<string name="function_already_exists">Function with same name already exists!</string>
<string name="function_name_clashes">Function name clashes with function name!</string>
<string name="function_is_empty">Function body could not be empty!</string>
<string name="function_param_not_empty">Function parameter should not be empty!</string>
</resources> </resources>

View File

@ -1,6 +1,5 @@
package org.solovyev.android.calculator.function; package org.solovyev.android.calculator.function;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
@ -8,10 +7,18 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import jscl.math.function.CustomFunction; import jscl.math.function.CustomFunction;
import jscl.math.function.Function;
import jscl.math.function.IFunction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.AndroidUtils2; import org.solovyev.android.AndroidUtils2;
import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.CalculatorEventData;
import org.solovyev.android.calculator.CalculatorEventListener;
import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CalculatorLocatorImpl;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.math.edit.MathEntityRemover;
import org.solovyev.android.calculator.model.AFunction;
/** /**
* User: serso * User: serso
@ -23,7 +30,10 @@ public class FunctionEditDialogFragment extends DialogFragment implements Calcul
@NotNull @NotNull
private final Input input; private final Input input;
public FunctionEditDialogFragment() { @NotNull
private FunctionParamsView paramsView;
public FunctionEditDialogFragment() {
this(Input.newInstance()); this(Input.newInstance());
} }
@ -40,26 +50,40 @@ public class FunctionEditDialogFragment extends DialogFragment implements Calcul
public void onViewCreated(@NotNull View root, Bundle savedInstanceState) { public void onViewCreated(@NotNull View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState); super.onViewCreated(root, savedInstanceState);
final View addParamButton = root.findViewById(R.id.function_add_param_button); paramsView = (FunctionParamsView) root.findViewById(R.id.function_params_layout);
final ViewGroup functionParamsLayout = (ViewGroup) root.findViewById(R.id.function_params_layout); final AFunction.Builder builder;
addParamButton.setOnClickListener(new View.OnClickListener() { final IFunction function = input.getFunction();
@Override if (function != null) {
public void onClick(View v) { builder = new AFunction.Builder(function);
final LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); paramsView.init(function.getParameterNames());
final View functionEditParamLayout = inflater.inflate(R.layout.function_edit_param, null); } else {
builder = new AFunction.Builder();
paramsView.init();
}
final View addParamButton = functionEditParamLayout.findViewById(R.id.function_add_param_button); root.findViewById(R.id.cancel_button).setOnClickListener(new View.OnClickListener() {
addParamButton.setVisibility(View.GONE); @Override
public void onClick(View v) {
dismiss();
}
});
final View removeParamButton = functionEditParamLayout.findViewById(R.id.function_remove_param_button); root.findViewById(R.id.save_button).setOnClickListener(new FunctionEditorSaver(builder, function, root, CalculatorLocatorImpl.getInstance().getEngine().getFunctionsRegistry(), this));
removeParamButton.setVisibility(View.VISIBLE);
functionParamsLayout.addView(functionEditParamLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); if ( function == null ) {
} // CREATE MODE
}); getDialog().setTitle(R.string.function_create_function);
} root.findViewById(R.id.remove_button).setVisibility(View.GONE);
} else {
// EDIT MODE
getDialog().setTitle(R.string.function_edit_function);
Function customFunction = new CustomFunction.Builder(function).create();
root.findViewById(R.id.remove_button).setOnClickListener(new MathEntityRemover<Function>(customFunction, null, CalculatorLocatorImpl.getInstance().getEngine().getFunctionsRegistry(), getActivity(), this));
}
}
@Override @Override
public void onResume() { public void onResume() {
@ -77,6 +101,16 @@ public class FunctionEditDialogFragment extends DialogFragment implements Calcul
@Override @Override
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) {
case function_removed:
case function_added:
case function_changed:
if ( calculatorEventData.getSource() == this ) {
dismiss();
}
break;
}
} }
/* /*
@ -94,7 +128,7 @@ public class FunctionEditDialogFragment extends DialogFragment implements Calcul
public static class Input { public static class Input {
@Nullable @Nullable
private CustomFunction function; private IFunction function;
@Nullable @Nullable
private String name; private String name;
@ -114,7 +148,7 @@ public class FunctionEditDialogFragment extends DialogFragment implements Calcul
} }
@NotNull @NotNull
public static Input newFromFunction(@NotNull CustomFunction function) { public static Input newFromFunction(@NotNull IFunction function) {
final Input result = new Input(); final Input result = new Input();
result.function = function; result.function = function;
return result; return result;
@ -128,7 +162,7 @@ public class FunctionEditDialogFragment extends DialogFragment implements Calcul
} }
@NotNull @NotNull
public static Input newInstance(@Nullable CustomFunction function, @Nullable String name, @Nullable String value, @Nullable String description) { public static Input newInstance(@Nullable IFunction function, @Nullable String name, @Nullable String value, @Nullable String description) {
final Input result = new Input(); final Input result = new Input();
result.function = function; result.function = function;
result.name = name; result.name = name;
@ -138,7 +172,7 @@ public class FunctionEditDialogFragment extends DialogFragment implements Calcul
} }
@Nullable @Nullable
public CustomFunction getFunction() { public IFunction getFunction() {
return function; return function;
} }

View File

@ -0,0 +1,167 @@
package org.solovyev.android.calculator.function;
import android.view.View;
import android.widget.EditText;
import jscl.math.function.CustomFunction;
import jscl.math.function.Function;
import jscl.math.function.IFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CalculatorFunctionsMathRegistry;
import org.solovyev.android.calculator.CalculatorLocatorImpl;
import org.solovyev.android.calculator.CalculatorMathRegistry;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.math.edit.VarEditorSaver;
import org.solovyev.android.calculator.model.AFunction;
import org.solovyev.android.calculator.model.MathEntityBuilder;
import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.StringUtils;
import java.util.List;
public class FunctionEditorSaver implements View.OnClickListener {
@NotNull
private final Object source;
@NotNull
private final AFunction.Builder builder;
@Nullable
private final Function editedInstance;
@NotNull
private final View view;
@NotNull
private final CalculatorMathRegistry<Function> mathRegistry;
public FunctionEditorSaver(@NotNull AFunction.Builder builder,
@Nullable IFunction editedInstance,
@NotNull View view,
@NotNull CalculatorMathRegistry<Function> registry,
@NotNull Object source) {
this.builder = builder;
if (editedInstance instanceof Function || editedInstance == null) {
this.editedInstance = (Function)editedInstance;
} else {
throw new IllegalArgumentException();
}
this.view = view;
this.mathRegistry = registry;
this.source = source;
}
@Override
public void onClick(View v) {
final Integer error;
final EditText editName = (EditText) view.findViewById(R.id.function_edit_name);
String name = editName.getText().toString();
final EditText editValue = (EditText) view.findViewById(R.id.function_edit_value);
String content = editValue.getText().toString();
final EditText editDescription = (EditText) view.findViewById(R.id.function_edit_description);
String description = editDescription.getText().toString();
final FunctionParamsView editParams = (FunctionParamsView) view.findViewById(R.id.function_params_layout);
List<String> parameterNames = editParams.getParameterNames();
if (VarEditorSaver.isValidName(name)) {
boolean canBeSaved = false;
final Function entityFromRegistry = mathRegistry.get(name);
if (entityFromRegistry == null) {
canBeSaved = true;
} else if (editedInstance != null && entityFromRegistry.getId().equals(editedInstance.getId())) {
canBeSaved = true;
}
if (canBeSaved) {
if (validateParameters(parameterNames)) {
final MathType.Result mathType = MathType.getType(name, 0, false);
if (mathType.getMathType() == MathType.text || mathType.getMathType() == MathType.function ) {
if (!StringUtils.isEmpty(content)) {
builder.setParameterNames(parameterNames);
builder.setName(name);
builder.setDescription(description);
builder.setValue(content);
error = null;
} else {
error = R.string.function_is_empty;
}
} else {
error = R.string.function_name_clashes;
}
} else {
error = R.string.function_param_not_empty;
}
} else {
error = R.string.function_already_exists;
}
} else {
error = R.string.function_name_is_not_valid;
}
if (error != null) {
CalculatorLocatorImpl.getInstance().getNotifier().showMessage(error, MessageType.error);
} else {
CalculatorFunctionsMathRegistry.saveFunction(mathRegistry, new BuilderAdapter(builder), editedInstance, source, true);
}
}
private boolean validateParameters(@NotNull List<String> parameterNames) {
for (String parameterName : parameterNames) {
if ( !VarEditorSaver.isValidName(parameterName) ) {
return false;
}
}
return true;
}
private static final class BuilderAdapter implements MathEntityBuilder<Function> {
@NotNull
private final AFunction.Builder nestedBuilder;
public BuilderAdapter(@NotNull AFunction.Builder nestedBuilder) {
this.nestedBuilder = nestedBuilder;
}
@NotNull
@Override
public MathEntityBuilder<Function> setName(@NotNull String name) {
nestedBuilder.setName(name);
return this;
}
@NotNull
@Override
public MathEntityBuilder<Function> setDescription(@Nullable String description) {
nestedBuilder.setDescription(description);
return this;
}
@NotNull
@Override
public MathEntityBuilder<Function> setValue(@Nullable String value) {
nestedBuilder.setValue(value);
return this;
}
@NotNull
@Override
public Function create() {
final AFunction function = nestedBuilder.create();
return new CustomFunction.Builder(function).create();
}
}
}

View File

@ -0,0 +1,186 @@
package org.solovyev.android.calculator.function;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import jscl.text.MutableInt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class FunctionParamsView extends LinearLayout {
@NotNull
private final MutableInt paramsCount = new MutableInt(0);
@NotNull
private final List<Integer> paramIds = new ArrayList<Integer>(10);
private static final String PARAM_TAG_PREFIX = "function_param_";
public FunctionParamsView(Context context) {
super(context);
}
public FunctionParamsView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FunctionParamsView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void init() {
init(Collections.<String>emptyList());
}
public void init(@NotNull List<String> parameters) {
this.setOrientation(VERTICAL);
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View addParamView = inflater.inflate(R.layout.function_add_param, null);
final View addParamButton = addParamView.findViewById(R.id.function_add_param_button);
addParamButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addParam(null);
}
});
this.addView(addParamView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
for (String parameter : parameters) {
addParam(parameter);
}
}
public void addParam(@Nullable String name) {
synchronized (paramsCount) {
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final Integer id = paramsCount.intValue();
final View editParamView = inflater.inflate(R.layout.function_edit_param, null);
editParamView.setTag(getParamTag(id));
final View removeParamButton = editParamView.findViewById(R.id.function_remove_param_button);
removeParamButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
removeParam(id);
}
});
final View upParamButton = editParamView.findViewById(R.id.function_up_param_button);
upParamButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
upParam(id);
}
});
final View downParamButton = editParamView.findViewById(R.id.function_down_param_button);
downParamButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
downParam(id);
}
});
this.addView(editParamView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
paramIds.add(id);
paramsCount.increment();
}
}
private void downParam(@NotNull Integer id) {
synchronized (paramsCount) {
int index = paramIds.indexOf(id);
if (index < paramIds.size() - 1) {
swap(index, index + 1);
}
}
}
private void upParam(@NotNull Integer id) {
synchronized (paramsCount) {
int index = paramIds.indexOf(id);
if (index > 0) {
swap(index, index - 1);
}
}
}
private void swap(int index1, int index2) {
final View editParamView1 = getParamView(paramIds.get(index1));
final View editParamView2 = getParamView(paramIds.get(index2));
if (editParamView1 != null && editParamView2 != null) {
final EditText paramNameEditText1 = (EditText) editParamView1.findViewById(R.id.function_param_edit_text);
final EditText paramNameEditText2 = (EditText) editParamView2.findViewById(R.id.function_param_edit_text);
swap(paramNameEditText1, paramNameEditText2);
}
}
private void swap(@NotNull TextView first,
@NotNull TextView second) {
final CharSequence tmp = first.getText();
first.setText(second.getText());
second.setText(tmp);
}
@Nullable
private View getParamView(@NotNull Integer id) {
final String tag = getParamTag(id);
return this.findViewWithTag(tag);
}
@NotNull
private String getParamTag(@NotNull Integer index) {
return PARAM_TAG_PREFIX + index;
}
public void removeParam(@NotNull Integer id) {
synchronized (paramsCount) {
if (paramIds.contains(id)) {
final View editParamView = getParamView(id);
if (editParamView != null) {
this.removeView(editParamView);
paramIds.remove(id);
}
}
}
}
@NotNull
public List<String> getParameterNames() {
synchronized (paramsCount) {
final List<String> result = new ArrayList<String>(paramsCount.intValue());
for (Integer id : paramIds) {
final View paramView = getParamView(id);
if ( paramView != null ) {
final EditText paramNameEditText = (EditText) paramView.findViewById(R.id.function_param_edit_text);
result.add(paramNameEditText.getText().toString());
}
}
return result;
}
}
}

View File

@ -16,6 +16,7 @@ import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.MenuItem;
import jscl.math.function.CustomFunction; import jscl.math.function.CustomFunction;
import jscl.math.function.Function; import jscl.math.function.Function;
import jscl.math.function.IFunction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.CalculatorEventType; import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CalculatorLocatorImpl; import org.solovyev.android.calculator.CalculatorLocatorImpl;
@ -244,24 +245,24 @@ public class CalculatorFunctionsFragment extends AbstractMathEntityListFragment<
private static enum LongClickMenuItem implements LabeledMenuItem<Function> { private static enum LongClickMenuItem implements LabeledMenuItem<Function> {
use(R.string.c_use) { use(R.string.c_use) {
@Override @Override
public void onClick(@NotNull Function data, @NotNull Context context) { public void onClick(@NotNull Function function, @NotNull Context context) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.use_function, data); CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.use_function, function);
} }
}, },
edit(R.string.c_edit) { edit(R.string.c_edit) {
@Override @Override
public void onClick(@NotNull Function function, @NotNull Context context) { public void onClick(@NotNull Function function, @NotNull Context context) {
if (function instanceof CustomFunction) { if (function instanceof IFunction) {
FunctionEditDialogFragment.showDialog(FunctionEditDialogFragment.Input.newFromFunction((CustomFunction) function), ((SherlockFragmentActivity) context).getSupportFragmentManager()); FunctionEditDialogFragment.showDialog(FunctionEditDialogFragment.Input.newFromFunction((IFunction) function), ((SherlockFragmentActivity) context).getSupportFragmentManager());
} }
} }
}, },
copy_description(R.string.c_copy_description) { copy_description(R.string.c_copy_description) {
@Override @Override
public void onClick(@NotNull Function data, @NotNull Context context) { public void onClick(@NotNull Function function, @NotNull Context context) {
final String text = CalculatorLocatorImpl.getInstance().getEngine().getFunctionsRegistry().getDescription(data.getName()); final String text = CalculatorLocatorImpl.getInstance().getEngine().getFunctionsRegistry().getDescription(function.getName());
if (!StringUtils.isEmpty(text)) { if (!StringUtils.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text); clipboard.setText(text);

View File

@ -24,7 +24,7 @@ import org.solovyev.common.math.MathEntity;
* Date: 12/22/11 * Date: 12/22/11
* Time: 9:36 PM * Time: 9:36 PM
*/ */
class MathEntityRemover<T extends MathEntity> implements View.OnClickListener, DialogInterface.OnClickListener { public class MathEntityRemover<T extends MathEntity> implements View.OnClickListener, DialogInterface.OnClickListener {
@NotNull @NotNull
private final T mathEntity; private final T mathEntity;

View File

@ -29,7 +29,7 @@ import org.solovyev.common.text.StringUtils;
* Date: 12/22/11 * Date: 12/22/11
* Time: 9:52 PM * Time: 9:52 PM
*/ */
class VarEditorSaver<T extends MathEntity> implements View.OnClickListener { public class VarEditorSaver<T extends MathEntity> implements View.OnClickListener {
@NotNull @NotNull
private final MathEntityBuilder<? extends T> varBuilder; private final MathEntityBuilder<? extends T> varBuilder;
@ -123,7 +123,7 @@ class VarEditorSaver<T extends MathEntity> implements View.OnClickListener {
} }
} }
boolean isValidName(@Nullable String name) { public static boolean isValidName(@Nullable String name) {
boolean result = false; boolean result = false;
if (!StringUtils.isEmpty(name)) { if (!StringUtils.isEmpty(name)) {

View File

@ -17,7 +17,16 @@ 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 org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.CalculatorEngine;
import org.solovyev.android.calculator.CalculatorEngineImpl;
import org.solovyev.android.calculator.CalculatorFunctionsMathRegistry;
import org.solovyev.android.calculator.CalculatorMathEngine;
import org.solovyev.android.calculator.CalculatorMathRegistry;
import org.solovyev.android.calculator.CalculatorOperatorsMathRegistry;
import org.solovyev.android.calculator.CalculatorPostfixFunctionsRegistry;
import org.solovyev.android.calculator.CalculatorVarsRegistry;
import org.solovyev.android.calculator.MathPersistenceEntity;
import org.solovyev.android.calculator.R;
import org.solovyev.android.prefs.BooleanPreference; import org.solovyev.android.prefs.BooleanPreference;
import org.solovyev.android.prefs.Preference; import org.solovyev.android.prefs.Preference;
import org.solovyev.android.prefs.StringPreference; import org.solovyev.android.prefs.StringPreference;