Display refactored

This commit is contained in:
serso 2016-01-09 23:53:41 +01:00
parent 5e1c47963c
commit b120283adb
41 changed files with 320 additions and 709 deletions

View File

@ -22,13 +22,10 @@
package org.solovyev.android; package org.solovyev.android;
import android.os.Looper;
import java.util.Collection;
import java.util.Map;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;
import static java.lang.Thread.currentThread; import static java.lang.Thread.currentThread;
@ -51,9 +48,9 @@ public final class Check {
} }
public static void isMainThread() { public static void isMainThread() {
if (!junit && Looper.getMainLooper() != Looper.myLooper()) { /*if (!junit && Looper.getMainLooper() != Looper.myLooper()) {
throw new AssertionException("Should be called on the main thread"); throw new AssertionException("Should be called on the main thread");
} }*/
} }
public static void isNotNull(@Nullable Object o) { public static void isNotNull(@Nullable Object o) {

View File

@ -72,7 +72,7 @@ public class AndroidCalculator implements Calculator, CalculatorEventListener, S
@Override @Override
@Nonnull @Nonnull
public CalculatorEventData evaluate(@Nonnull JsclOperation operation, @Nonnull String expression, @Nonnull Long sequenceId) { public CalculatorEventData evaluate(@Nonnull JsclOperation operation, @Nonnull String expression, long sequenceId) {
return calculator.evaluate(operation, expression, sequenceId); return calculator.evaluate(operation, expression, sequenceId);
} }

View File

@ -1,200 +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;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.util.AttributeSet;
import android.util.TypedValue;
import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.calculator.text.TextProcessorEditorResult;
import org.solovyev.android.calculator.view.TextHighlighter;
import org.solovyev.android.view.AutoResizeTextView;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 9/17/11
* Time: 10:58 PM
*/
public class AndroidCalculatorDisplayView extends AutoResizeTextView implements CalculatorDisplayView {
/*
**********************************************************************
*
* STATIC FIELDS
*
**********************************************************************
*/
@Nonnull
private final TextProcessor<TextProcessorEditorResult, String> textHighlighter;
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
@Nonnull
private final Object lock = new Object();
@Nonnull
private final Handler uiHandler = new Handler();
@Nonnull
private volatile DisplayState state = DisplayState.empty();
private volatile boolean initialized = false;
/*
**********************************************************************
*
* CONSTRUCTORS
*
**********************************************************************
*/
public AndroidCalculatorDisplayView(Context context) {
super(context);
textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false);
}
public AndroidCalculatorDisplayView(Context context, AttributeSet attrs) {
super(context, attrs);
textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false);
}
public AndroidCalculatorDisplayView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false);
}
/*
**********************************************************************
*
* METHODS
*
**********************************************************************
*/
private Preferences.Gui.TextColor getTextColor() {
final Context context = getContext();
return App.getThemeIn(context).getTextColor(context);
}
@Nonnull
@Override
public DisplayState getState() {
synchronized (lock) {
return this.state;
}
}
@Override
public void setState(@Nonnull final DisplayState state) {
uiHandler.post(new Runnable() {
@Override
public void run() {
synchronized (lock) {
final CharSequence text = prepareText(state.getStringResult(), state.isValid());
AndroidCalculatorDisplayView.this.state = state;
if (state.isValid()) {
setTextColor(getTextColor().normal);
setText(text);
adjustTextSize();
} else {
// update text in order to get rid of HTML tags
setText(getText().toString());
setTextColor(getTextColor().error);
// error messages are never shown -> just greyed out text (error message will be shown on click)
//setText(state.getErrorMessage());
//redraw();
}
}
}
});
}
@Nullable
private CharSequence prepareText(@Nullable String text, boolean valid) {
CharSequence result;
if (valid && text != null) {
try {
final TextProcessorEditorResult processedText = textHighlighter.process(text);
text = processedText.toString();
result = processedText.getCharSequence();
} catch (CalculatorParseException e) {
result = text;
}
} else {
result = text;
}
return result;
}
private void adjustTextSize() {
// todo serso: think where to move it (keep in mind org.solovyev.android.view.AutoResizeTextView.resetTextSize())
setAddEllipsis(false);
setMinTextSize(10);
resizeText();
}
public synchronized void init(@Nonnull Context context) {
this.init(context, true);
}
public synchronized void init(@Nonnull Context context, boolean fromApp) {
if (!initialized) {
if (fromApp) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(preferences);
if (!layout.isOptimized()) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, getResources().getDimension(R.dimen.cpp_display_text_size_mobile));
}
if (context instanceof FragmentActivity) {
this.setOnClickListener(new CalculatorDisplayOnClickListener((FragmentActivity) context));
} else {
throw new IllegalArgumentException("Must be fragment activity, got " + context.getClass());
}
}
this.initialized = true;
}
}
}

View File

@ -255,7 +255,7 @@ public final class App {
} }
@Nonnull @Nonnull
public static Preferences.Gui.Theme getThemeIn(@Nonnull Context context) { public static Preferences.Gui.Theme getThemeFor(@Nonnull Context context) {
if (context instanceof CalculatorOnscreenService) { if (context instanceof CalculatorOnscreenService) {
final SharedPreferences p = getPreferences(); final SharedPreferences p = getPreferences();
final Preferences.SimpleTheme onscreenTheme = Preferences.Onscreen.getTheme(p); final Preferences.SimpleTheme onscreenTheme = Preferences.Onscreen.getTheme(p);
@ -324,6 +324,11 @@ public final class App {
return context.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) == PackageManager.PERMISSION_GRANTED; return context.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) == PackageManager.PERMISSION_GRANTED;
} }
@NonNull
public static String unspan(@Nonnull CharSequence spannable) {
return spannable.toString();
}
private static class MyBus extends Bus { private static class MyBus extends Bus {
@Override @Override
public void post(final Object event) { public void post(final Object event) {

View File

@ -22,6 +22,8 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import jscl.NumeralBase;
import jscl.math.Generic;
import org.solovyev.android.calculator.history.HistoryState; import org.solovyev.android.calculator.history.HistoryState;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.history.HistoryControl; import org.solovyev.common.history.HistoryControl;
@ -29,9 +31,6 @@ import org.solovyev.common.history.HistoryControl;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import jscl.NumeralBase;
import jscl.math.Generic;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 20.09.12 * Date: 20.09.12
@ -62,7 +61,7 @@ public interface Calculator extends CalculatorEventContainer, HistoryControl<His
@Nonnull @Nonnull
CalculatorEventData evaluate(@Nonnull JsclOperation operation, CalculatorEventData evaluate(@Nonnull JsclOperation operation,
@Nonnull String expression, @Nonnull String expression,
@Nonnull Long sequenceId); long sequenceId);
boolean isCalculateOnFly(); boolean isCalculateOnFly();

View File

@ -129,8 +129,8 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
} }
public static void tryCreateVar(@Nonnull final Context context) { public static void tryCreateVar(@Nonnull final Context context) {
final CalculatorDisplay display = Locator.getInstance().getDisplay(); final Display display = Locator.getInstance().getDisplay();
final DisplayState viewState = display.getViewState(); final DisplayState viewState = display.getState();
if (viewState.isValid()) { if (viewState.isValid()) {
final String varValue = viewState.getText(); final String varValue = viewState.getText();
if (!Strings.isEmpty(varValue)) { if (!Strings.isEmpty(varValue)) {
@ -155,8 +155,8 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
} }
public static void tryCreateFunction(@Nonnull final Context context) { public static void tryCreateFunction(@Nonnull final Context context) {
final CalculatorDisplay display = Locator.getInstance().getDisplay(); final Display display = Locator.getInstance().getDisplay();
final DisplayState viewState = display.getViewState(); final DisplayState viewState = display.getState();
if (viewState.isValid()) { if (viewState.isValid()) {
final String functionValue = viewState.getText(); final String functionValue = viewState.getText();
@ -179,8 +179,8 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
public static void tryPlot() { public static void tryPlot() {
final CalculatorPlotter plotter = Locator.getInstance().getPlotter(); final CalculatorPlotter plotter = Locator.getInstance().getPlotter();
final CalculatorDisplay display = Locator.getInstance().getDisplay(); final Display display = Locator.getInstance().getDisplay();
final DisplayState viewState = display.getViewState(); final DisplayState viewState = display.getState();
if (viewState.isValid()) { if (viewState.isValid()) {
final String functionValue = viewState.getText(); final String functionValue = viewState.getText();

View File

@ -7,7 +7,6 @@ import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -17,10 +16,8 @@ public final class CalculatorBroadcaster implements SharedPreferences.OnSharedPr
public static final String ACTION_EDITOR_STATE_CHANGED = "org.solovyev.android.calculator.EDITOR_STATE_CHANGED"; public static final String ACTION_EDITOR_STATE_CHANGED = "org.solovyev.android.calculator.EDITOR_STATE_CHANGED";
public static final String ACTION_DISPLAY_STATE_CHANGED = "org.solovyev.android.calculator.DISPLAY_STATE_CHANGED"; public static final String ACTION_DISPLAY_STATE_CHANGED = "org.solovyev.android.calculator.DISPLAY_STATE_CHANGED";
public static final String ACTION_THEME_CHANGED = "org.solovyev.android.calculator.THEME_CHANGED"; public static final String ACTION_THEME_CHANGED = "org.solovyev.android.calculator.THEME_CHANGED";
@Nonnull @Nonnull
private final Context context; private final Context context;
@Nonnull @Nonnull
private final Intents intents = new Intents(); private final Intents intents = new Intents();
@ -36,16 +33,13 @@ public final class CalculatorBroadcaster implements SharedPreferences.OnSharedPr
} }
@Subscribe @Subscribe
public void onCursorMoved(@Nonnull Editor.CursorMovedEvent e) { public void onDisplayChanged(@Nonnull Display.ChangedEvent e) {
sendBroadcastIntent(ACTION_EDITOR_STATE_CHANGED); sendBroadcastIntent(ACTION_DISPLAY_STATE_CHANGED);
} }
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { @Subscribe
switch (calculatorEventType) { public void onCursorMoved(@Nonnull Editor.CursorMovedEvent e) {
case display_state_changed: sendBroadcastIntent(ACTION_EDITOR_STATE_CHANGED);
sendBroadcastIntent(ACTION_DISPLAY_STATE_CHANGED);
break;
}
} }
public void sendInitIntent() { public void sendInitIntent() {

View File

@ -1,49 +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;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 12/17/11
* Time: 9:45 PM
*/
public interface CalculatorDisplay extends CalculatorEventListener {
void clearView(@Nonnull CalculatorDisplayView view);
@Nullable
CalculatorDisplayView getView();
void setView(@Nonnull CalculatorDisplayView view);
@Nonnull
DisplayState getViewState();
void setViewState(@Nonnull DisplayState viewState);
@Nonnull
CalculatorEventData getLastEventData();
}

View File

@ -1,31 +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;
/**
* User: serso
* Date: 9/21/12
* Time: 9:49 PM
*/
public interface CalculatorDisplayChangeEventData extends Change<DisplayState> {
}

View File

@ -1,56 +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;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 9/21/12
* Time: 9:50 PM
*/
public class CalculatorDisplayChangeEventDataImpl implements CalculatorDisplayChangeEventData {
@Nonnull
private final DisplayState oldState;
@Nonnull
private final DisplayState newState;
public CalculatorDisplayChangeEventDataImpl(@Nonnull DisplayState oldState, @Nonnull DisplayState newState) {
this.oldState = oldState;
this.newState = newState;
}
@Nonnull
@Override
public DisplayState getOldValue() {
return this.oldState;
}
@Nonnull
@Override
public DisplayState getNewValue() {
return this.newState;
}
}

View File

@ -42,7 +42,7 @@ public class CalculatorDisplayFragment extends Fragment {
@Nonnull @Nonnull
private FragmentUi fragmentUi; private FragmentUi fragmentUi;
@Nonnull @Nonnull
private AndroidCalculatorDisplayView displayView; private DisplayView displayView;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -68,8 +68,7 @@ public class CalculatorDisplayFragment extends Fragment {
public void onViewCreated(View root, Bundle savedInstanceState) { public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState); super.onViewCreated(root, savedInstanceState);
displayView = (AndroidCalculatorDisplayView) root.findViewById(R.id.calculator_display); displayView = (DisplayView) root.findViewById(R.id.calculator_display);
displayView.init(getActivity());
Locator.getInstance().getDisplay().setView(displayView); Locator.getInstance().getDisplay().setView(displayView);
fragmentUi.onViewCreated(this, root); fragmentUi.onViewCreated(this, root);

View File

@ -24,15 +24,13 @@ package org.solovyev.android.calculator;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.view.View; import android.view.View;
import org.solovyev.android.menu.ContextMenuBuilder; import org.solovyev.android.menu.ContextMenuBuilder;
import org.solovyev.android.menu.ListContextMenu; import org.solovyev.android.menu.ListContextMenu;
import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 21.09.12 * Date: 21.09.12
@ -49,10 +47,10 @@ public class CalculatorDisplayOnClickListener implements View.OnClickListener {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (v instanceof CalculatorDisplayView) { if (v instanceof DisplayView) {
final CalculatorDisplay cd = Locator.getInstance().getDisplay(); final Display cd = Locator.getInstance().getDisplay();
final DisplayState displayViewState = cd.getViewState(); final DisplayState displayViewState = cd.getState();
if (displayViewState.isValid()) { if (displayViewState.isValid()) {
final List<CalculatorDisplayMenuItem> filteredMenuItems = new ArrayList<CalculatorDisplayMenuItem>(CalculatorDisplayMenuItem.values().length); final List<CalculatorDisplayMenuItem> filteredMenuItems = new ArrayList<CalculatorDisplayMenuItem>(CalculatorDisplayMenuItem.values().length);

View File

@ -1,38 +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;
import javax.annotation.Nonnull;
/**
* User: serso
* Date: 9/20/12
* Time: 8:25 PM
*/
public interface CalculatorDisplayView {
@Nonnull
DisplayState getState();
void setState(@Nonnull DisplayState state);
}

View File

@ -70,17 +70,6 @@ public enum CalculatorEventType {
conversion_finished, conversion_finished,
/*
**********************************************************************
*
* EDITOR
*
**********************************************************************
*/
// @Nonnull CalculatorDisplayChangeEventData
display_state_changed,
/* /*
********************************************************************** **********************************************************************
* *

View File

@ -95,7 +95,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
// NOTE: only one thread is responsible for events as all events must be done in order of their creating // NOTE: only one thread is responsible for events as all events must be done in order of their creating
@Nonnull @Nonnull
private final Executor eventExecutor = Executors.newFixedThreadPool(1); private final Executor eventExecutor = App.getUiThreadExecutor();
private volatile boolean calculateOnFly = true; private volatile boolean calculateOnFly = true;
@ -191,7 +191,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
@Nonnull @Nonnull
@Override @Override
public CalculatorEventData evaluate(@Nonnull final JsclOperation operation, @Nonnull final String expression, @Nonnull Long sequenceId) { public CalculatorEventData evaluate(@Nonnull final JsclOperation operation, @Nonnull final String expression, long sequenceId) {
final CalculatorEventData eventDataId = nextEventData(sequenceId); final CalculatorEventData eventDataId = nextEventData(sequenceId);
calculationsExecutor.execute(new Runnable() { calculationsExecutor.execute(new Runnable() {
@ -373,7 +373,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
@Nonnull final NumeralBase to) { @Nonnull final NumeralBase to) {
final CalculatorEventData eventDataId = nextEventData(); final CalculatorEventData eventDataId = nextEventData();
final DisplayState displayViewState = Locator.getInstance().getDisplay().getViewState(); final DisplayState displayViewState = Locator.getInstance().getDisplay().getState();
final NumeralBase from = Locator.getInstance().getEngine().getNumeralBase(); final NumeralBase from = Locator.getInstance().getEngine().getNumeralBase();
calculationsExecutor.execute(new Runnable() { calculationsExecutor.execute(new Runnable() {
@ -483,17 +483,34 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
if (TextUtils.equals(e.newState.text, e.oldState.text)) { if (TextUtils.equals(e.newState.text, e.oldState.text)) {
return; return;
} }
evaluate(JsclOperation.numeric, e.newState.getTextString(), e.newState.id); evaluate(JsclOperation.numeric, e.newState.getTextString(), e.newState.sequence);
}
@Subscribe
public void onDisplayChanged(@Nonnull Display.ChangedEvent e) {
final DisplayState newState = e.newState;
if (!newState.isValid()) {
return;
}
final String result = newState.getStringResult();
if (TextUtils.isEmpty(result)) {
return;
}
final CalculatorMathRegistry<IConstant> varsRegistry = Locator.getInstance().getEngine().getVarsRegistry();
final IConstant ansVar = varsRegistry.get(CalculatorVarsRegistry.ANS);
final Var.Builder builder = ansVar != null ? new Var.Builder(ansVar) : new Var.Builder();
builder.setName(CalculatorVarsRegistry.ANS);
builder.setValue(result);
builder.setDescription(CalculatorMessages.getBundle().getString(CalculatorMessages.ans_description));
CalculatorVarsRegistry.saveVariable(varsRegistry, builder, ansVar, this, false);
} }
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) { switch (calculatorEventType) {
case display_state_changed:
onDisplayStateChanged((CalculatorDisplayChangeEventData) data);
break;
case constant_changed: case constant_changed:
final IConstant newConstant = ((Change<IConstant>) data).getNewValue(); final IConstant newConstant = ((Change<IConstant>) data).getNewValue();
if (!newConstant.getName().equals(CalculatorVarsRegistry.ANS)) { if (!newConstant.getName().equals(CalculatorVarsRegistry.ANS)) {
@ -531,30 +548,6 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
} }
} }
private void onDisplayStateChanged(@Nonnull CalculatorDisplayChangeEventData displayChangeEventData) {
final DisplayState newState = displayChangeEventData.getNewValue();
if (newState.isValid()) {
final String result = newState.getStringResult();
if (!Strings.isEmpty(result)) {
final CalculatorMathRegistry<IConstant> varsRegistry = Locator.getInstance().getEngine().getVarsRegistry();
final IConstant ansVar = varsRegistry.get(CalculatorVarsRegistry.ANS);
final Var.Builder varBuilder;
if (ansVar != null) {
varBuilder = new Var.Builder(ansVar);
} else {
varBuilder = new Var.Builder();
}
varBuilder.setName(CalculatorVarsRegistry.ANS);
varBuilder.setValue(result);
varBuilder.setDescription(CalculatorMessages.getBundle().getString(CalculatorMessages.ans_description));
CalculatorVarsRegistry.saveVariable(varsRegistry, varBuilder, ansVar, this, false);
}
}
}
/* /*
********************************************************************** **********************************************************************
* *
@ -599,7 +592,7 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
} }
@Nonnull @Nonnull
private CalculatorDisplay getDisplay() { private Display getDisplay() {
return Locator.getInstance().getDisplay(); return Locator.getInstance().getDisplay();
} }
} }

View File

@ -116,7 +116,7 @@ public class CalculatorKeyboard {
} }
public void copyButtonPressed() { public void copyButtonPressed() {
final DisplayState displayViewState = Locator.getInstance().getDisplay().getViewState(); final DisplayState displayViewState = Locator.getInstance().getDisplay().getState();
if (displayViewState.isValid()) { if (displayViewState.isValid()) {
final CharSequence text = displayViewState.getText(); final CharSequence text = displayViewState.getText();
if (!Strings.isEmpty(text)) { if (!Strings.isEmpty(text)) {

View File

@ -55,7 +55,7 @@ public interface CalculatorLocator {
CalculatorEngine getEngine(); CalculatorEngine getEngine();
@Nonnull @Nonnull
CalculatorDisplay getDisplay(); Display getDisplay();
@Nonnull @Nonnull
Editor getEditor(); Editor getEditor();

View File

@ -115,7 +115,7 @@ public enum CalculatorSpecialButton {
return; return;
} }
final DisplayState displayViewState = Locator.getInstance().getDisplay().getViewState(); final DisplayState displayViewState = Locator.getInstance().getDisplay().getState();
if (displayViewState.isValid()) { if (displayViewState.isValid()) {
final CharSequence text = displayViewState.getText(); final CharSequence text = displayViewState.getText();
if (!Strings.isEmpty(text)) { if (!Strings.isEmpty(text)) {

View File

@ -22,97 +22,70 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import org.solovyev.android.Check;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static org.solovyev.android.calculator.CalculatorEventType.calculation_cancelled; import static org.solovyev.android.calculator.CalculatorEventType.*;
import static org.solovyev.android.calculator.CalculatorEventType.calculation_failed;
import static org.solovyev.android.calculator.CalculatorEventType.calculation_result;
import static org.solovyev.android.calculator.CalculatorEventType.conversion_failed;
import static org.solovyev.android.calculator.CalculatorEventType.conversion_result;
import static org.solovyev.android.calculator.CalculatorEventType.display_state_changed;
public class CalculatorDisplayImpl implements CalculatorDisplay { public class Display implements CalculatorEventListener {
public static class ChangedEvent {
@Nonnull
public final DisplayState oldState;
@Nonnull
public final DisplayState newState;
public ChangedEvent(@Nonnull DisplayState oldState, @Nonnull DisplayState newState) {
this.oldState = oldState;
this.newState = newState;
}
}
@Nonnull @Nonnull
private final CalculatorEventHolder lastEvent; private final CalculatorEventHolder lastEvent;
@Nonnull
private final Object viewLock = new Object();
@Nonnull
private final Calculator calculator;
@Nullable @Nullable
private CalculatorDisplayView view; private DisplayView view;
@Nonnull @Nonnull
private DisplayState viewState = DisplayState.empty(); private DisplayState state = DisplayState.empty();
public CalculatorDisplayImpl(@Nonnull Calculator calculator) { public Display(@Nonnull Calculator calculator) {
this.calculator = calculator;
this.lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId()); this.lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
this.calculator.addCalculatorEventListener(this); calculator.addCalculatorEventListener(this);
} }
@Override public void clearView(@Nonnull DisplayView view) {
public void clearView(@Nonnull CalculatorDisplayView view) { Check.isMainThread();
synchronized (viewLock) { if (this.view != view) {
if (this.view == view) { return;
}
this.view = null; this.view = null;
} }
}
}
@Nullable public void setView(@Nonnull DisplayView view) {
@Override Check.isMainThread();
public CalculatorDisplayView getView() {
return this.view;
}
@Override
public void setView(@Nonnull CalculatorDisplayView view) {
synchronized (viewLock) {
this.view = view; this.view = view;
this.view.setState(viewState); this.view.setState(state);
}
} }
@Nonnull @Nonnull
@Override public DisplayState getState() {
public DisplayState getViewState() { Check.isMainThread();
return this.viewState; return state;
} }
@Override public void setState(@Nonnull DisplayState newState) {
public void setViewState(@Nonnull DisplayState newViewState) { Check.isMainThread();
synchronized (viewLock) {
final DisplayState oldViewState = setViewState0(newViewState);
this.calculator.fireCalculatorEvent(display_state_changed, new CalculatorDisplayChangeEventDataImpl(oldViewState, newViewState)); final DisplayState oldState = state;
state = newState;
if (view != null) {
view.setState(newState);
} }
} App.getBus().post(new ChangedEvent(oldState, newState));
private void setViewStateForSequence(@Nonnull DisplayState newViewState, @Nonnull Long sequenceId) {
synchronized (viewLock) {
final DisplayState oldViewState = setViewState0(newViewState);
this.calculator.fireCalculatorEvent(display_state_changed, new CalculatorDisplayChangeEventDataImpl(oldViewState, newViewState), sequenceId);
}
}
// must be synchronized with viewLock
@Nonnull
private DisplayState setViewState0(@Nonnull DisplayState newViewState) {
final DisplayState oldViewState = this.viewState;
this.viewState = newViewState;
if (this.view != null) {
this.view.setState(newViewState);
}
return oldViewState;
}
@Override
@Nonnull
public CalculatorEventData getLastEventData() {
return lastEvent.getLastEventData();
} }
@Override @Override
@ -147,7 +120,7 @@ public class CalculatorDisplayImpl implements CalculatorDisplay {
private void processConversationFailed(@Nonnull CalculatorConversionEventData calculatorEventData, private void processConversationFailed(@Nonnull CalculatorConversionEventData calculatorEventData,
@Nonnull ConversionFailure data) { @Nonnull ConversionFailure data) {
this.setViewStateForSequence(DisplayState.createError(calculatorEventData.getDisplayState().getOperation(), CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error)), calculatorEventData.getSequenceId()); setState(DisplayState.createError(calculatorEventData.getDisplayState().getOperation(), CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error), calculatorEventData.getSequenceId()));
} }
@ -167,18 +140,17 @@ public class CalculatorDisplayImpl implements CalculatorDisplay {
} }
} }
this.setViewStateForSequence(DisplayState.createError(calculatorEventData.getOperation(), errorMessage), calculatorEventData.getSequenceId()); setState(DisplayState.createError(calculatorEventData.getOperation(), errorMessage, calculatorEventData.getSequenceId()));
} }
private void processCalculationCancelled(@Nonnull CalculatorEvaluationEventData calculatorEventData) { private void processCalculationCancelled(@Nonnull CalculatorEvaluationEventData calculatorEventData) {
final String errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error); final String errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
setState(DisplayState.createError(calculatorEventData.getOperation(), errorMessage, calculatorEventData.getSequenceId()));
this.setViewStateForSequence(DisplayState.createError(calculatorEventData.getOperation(), errorMessage), calculatorEventData.getSequenceId());
} }
private void processCalculationResult(@Nonnull CalculatorEvaluationEventData calculatorEventData, @Nonnull CalculatorOutput data) { private void processCalculationResult(@Nonnull CalculatorEvaluationEventData calculatorEventData, @Nonnull CalculatorOutput data) {
final String stringResult = data.getStringResult(); final String stringResult = data.getStringResult();
this.setViewStateForSequence(DisplayState.createValid(calculatorEventData.getOperation(), data.getResult(), stringResult, 0), calculatorEventData.getSequenceId()); setState(DisplayState.createValid(calculatorEventData.getOperation(), data.getResult(), stringResult, 0, calculatorEventData.getSequenceId()));
} }
private void processConversationResult(@Nonnull CalculatorConversionEventData calculatorEventData, @Nonnull String result) { private void processConversationResult(@Nonnull CalculatorConversionEventData calculatorEventData, @Nonnull String result) {
@ -188,6 +160,6 @@ public class CalculatorDisplayImpl implements CalculatorDisplay {
} }
final DisplayState displayState = calculatorEventData.getDisplayState(); final DisplayState displayState = calculatorEventData.getDisplayState();
this.setViewStateForSequence(DisplayState.createValid(displayState.getOperation(), displayState.getResult(), result, 0), calculatorEventData.getSequenceId()); setState(DisplayState.createValid(displayState.getOperation(), displayState.getResult(), result, 0, calculatorEventData.getSequenceId()));
} }
} }

View File

@ -22,17 +22,14 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import jscl.math.Generic;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import java.io.Serializable;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import jscl.math.Generic; public class DisplayState {
public class DisplayState implements Serializable {
@Nonnull @Nonnull
private JsclOperation operation = JsclOperation.numeric; private JsclOperation operation = JsclOperation.numeric;
@ -48,7 +45,9 @@ public class DisplayState implements Serializable {
@Nullable @Nullable
private String errorMessage; private String errorMessage;
private int selection = 0; private int selection;
private long sequence;
private DisplayState() { private DisplayState() {
} }
@ -60,27 +59,30 @@ public class DisplayState implements Serializable {
@Nonnull @Nonnull
public static DisplayState createError(@Nonnull JsclOperation operation, public static DisplayState createError(@Nonnull JsclOperation operation,
@Nonnull String errorMessage) { @Nonnull String errorMessage,
final DisplayState calculatorDisplayState = new DisplayState(); long sequence) {
calculatorDisplayState.valid = false; final DisplayState state = new DisplayState();
calculatorDisplayState.errorMessage = errorMessage; state.valid = false;
calculatorDisplayState.operation = operation; state.errorMessage = errorMessage;
return calculatorDisplayState; state.operation = operation;
state.sequence = sequence;
return state;
} }
@Nonnull @Nonnull
public static DisplayState createValid(@Nonnull JsclOperation operation, public static DisplayState createValid(@Nonnull JsclOperation operation,
@Nullable Generic result, @Nullable Generic result,
@Nonnull String stringResult, @Nonnull String stringResult,
int selection) { int selection,
final DisplayState calculatorDisplayState = new DisplayState(); long sequence) {
calculatorDisplayState.valid = true; final DisplayState state = new DisplayState();
calculatorDisplayState.result = result; state.valid = true;
calculatorDisplayState.stringResult = stringResult; state.result = result;
calculatorDisplayState.operation = operation; state.stringResult = stringResult;
calculatorDisplayState.selection = selection; state.operation = operation;
state.selection = selection;
return calculatorDisplayState; state.sequence = sequence;
return state;
} }
@Nonnull @Nonnull
@ -115,4 +117,8 @@ public class DisplayState implements Serializable {
public JsclOperation getOperation() { public JsclOperation getOperation() {
return this.operation; return this.operation;
} }
public long getSequence() {
return sequence;
}
} }

View File

@ -0,0 +1,113 @@
/*
* 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;
import android.app.Service;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.calculator.text.TextProcessorEditorResult;
import org.solovyev.android.calculator.view.TextHighlighter;
import org.solovyev.android.view.AutoResizeTextView;
import javax.annotation.Nonnull;
public class DisplayView extends AutoResizeTextView {
@Nonnull
private final TextProcessor<TextProcessorEditorResult, String> textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false);
@Nonnull
private DisplayState state = DisplayState.empty();
public DisplayView(Context context) {
super(context);
init(context);
}
public DisplayView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DisplayView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(@Nonnull Context context) {
setAddEllipsis(false);
setMinTextSize(10);
if (context instanceof Service) {
return;
}
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(App.getPreferences());
if (!layout.isOptimized()) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, getResources().getDimension(R.dimen.cpp_display_text_size_mobile));
}
setOnClickListener(new CalculatorDisplayOnClickListener((FragmentActivity) context));
}
@Nonnull
private Preferences.Gui.TextColor getTextColor() {
final Context context = getContext();
return App.getThemeFor(context).getTextColorFor(context);
}
@Nonnull
public DisplayState getState() {
Check.isMainThread();
return state;
}
public void setState(@Nonnull final DisplayState newState) {
Check.isMainThread();
state = newState;
if (state.isValid()) {
setText(highlightText(state));
setTextColor(getTextColor().normal);
} else {
setText(App.unspan(getText()));
setTextColor(getTextColor().error);
}
}
@NonNull
private CharSequence highlightText(@Nonnull DisplayState state) {
final String text = state.getStringResult();
if (TextUtils.isEmpty(text)) {
return "";
}
try {
return textHighlighter.process(text).getCharSequence();
} catch (CalculatorParseException e) {
return text;
}
}
}

View File

@ -29,9 +29,10 @@ import javax.annotation.Nullable;
public class EditorState { public class EditorState {
private static long counter; public static final long NO_SEQUENCE = -1;
private static long counter = NO_SEQUENCE + 1;
public final long id; public final long sequence;
@Nonnull @Nonnull
public final CharSequence text; public final CharSequence text;
public final int selection; public final int selection;
@ -44,7 +45,7 @@ public class EditorState {
private EditorState(@Nonnull CharSequence text, int selection) { private EditorState(@Nonnull CharSequence text, int selection) {
Check.isMainThread(); Check.isMainThread();
this.id = counter++; this.sequence = counter++;
this.text = text; this.text = text;
this.selection = selection; this.selection = selection;
} }

View File

@ -46,7 +46,7 @@ public class Locator implements CalculatorLocator {
@Nonnull @Nonnull
private Editor editor; private Editor editor;
@Nonnull @Nonnull
private CalculatorDisplay calculatorDisplay; private Display display;
@Nonnull @Nonnull
private CalculatorKeyboard calculatorKeyboard; private CalculatorKeyboard calculatorKeyboard;
@Nonnull @Nonnull
@ -93,7 +93,7 @@ public class Locator implements CalculatorLocator {
this.calculatorPlotter = plotter; this.calculatorPlotter = plotter;
editor = new Editor(this.calculator, editorTextProcessor); editor = new Editor(this.calculator, editorTextProcessor);
calculatorDisplay = new CalculatorDisplayImpl(this.calculator); display = new Display(this.calculator);
calculatorKeyboard = keyboard; calculatorKeyboard = keyboard;
} }
@ -111,8 +111,8 @@ public class Locator implements CalculatorLocator {
@Override @Override
@Nonnull @Nonnull
public CalculatorDisplay getDisplay() { public Display getDisplay() {
return calculatorDisplay; return display;
} }
@Nonnull @Nonnull

View File

@ -315,7 +315,7 @@ public final class Preferences {
} }
@Nonnull @Nonnull
public TextColor getTextColor(@Nonnull Context context) { public TextColor getTextColorFor(@Nonnull Context context) {
final int themeId = getThemeFor(context); final int themeId = getThemeFor(context);
TextColor textColor = textColors.get(themeId); TextColor textColor = textColors.get(themeId);
if (textColor == null) { if (textColor == null) {

View File

@ -35,7 +35,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static org.solovyev.android.calculator.CalculatorEventType.*; import static org.solovyev.android.calculator.CalculatorEventType.manual_calculation_requested;
public class CalculatorHistoryImpl implements CalculatorHistory { public class CalculatorHistoryImpl implements CalculatorHistory {
@ -51,7 +51,7 @@ public class CalculatorHistoryImpl implements CalculatorHistory {
private final CalculatorEventHolder lastEventData = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId()); private final CalculatorEventHolder lastEventData = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
@Nullable @Nullable
private volatile EditorState lastEditorViewState; private EditorState lastEditorState;
public CalculatorHistoryImpl(@Nonnull Calculator calculator) { public CalculatorHistoryImpl(@Nonnull Calculator calculator) {
calculator.addCalculatorEventListener(this); calculator.addCalculatorEventListener(this);
@ -246,33 +246,31 @@ public class CalculatorHistoryImpl implements CalculatorHistory {
@Subscribe @Subscribe
public void onEditorChanged(@Nonnull Editor.ChangedEvent e) { public void onEditorChanged(@Nonnull Editor.ChangedEvent e) {
lastEditorViewState = e.newState; lastEditorState = e.newState;
}
@Subscribe
public void onDisplayChanged(@Nonnull Display.ChangedEvent e) {
if (lastEditorState == null) {
return;
}
if (lastEditorState.sequence != e.newState.getSequence()) {
return;
}
addState(HistoryState.create(lastEditorState, e.newState));
lastEditorState = null;
} }
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData,
@Nonnull CalculatorEventType calculatorEventType, @Nonnull CalculatorEventType calculatorEventType,
@Nullable Object data) { @Nullable Object data) {
if (calculatorEventType.isOfType(display_state_changed, manual_calculation_requested)) { if (calculatorEventType.isOfType(manual_calculation_requested)) {
final CalculatorEventHolder.Result result = lastEventData.apply(calculatorEventData); final CalculatorEventHolder.Result result = lastEventData.apply(calculatorEventData);
if (result.isNewAfter() && result.isNewSameOrAfterSequence()) { if (result.isNewAfter() && result.isNewSameOrAfterSequence()) {
switch (calculatorEventType) { switch (calculatorEventType) {
case manual_calculation_requested: case manual_calculation_requested:
lastEditorViewState = (EditorState) data; lastEditorState = (EditorState) data;
break;
case display_state_changed:
if (result.isSameSequence()) {
if (lastEditorViewState != null) {
final EditorState editorViewState = lastEditorViewState;
final CalculatorDisplayChangeEventData displayChangeData = (CalculatorDisplayChangeEventData) data;
final DisplayState displayViewState = displayChangeData.getNewValue();
addState(HistoryState.create(editorViewState, displayViewState));
}
} else {
lastEditorViewState = null;
}
break; break;
} }
} }

View File

@ -22,25 +22,19 @@
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import jscl.math.Generic;
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.simpleframework.xml.Transient;
import org.solovyev.android.calculator.CalculatorDisplay; import org.solovyev.android.calculator.Display;
import org.solovyev.android.calculator.DisplayState; import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.EditorState;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import jscl.math.Generic;
/**
* User: serso
* Date: 9/17/11
* Time: 11:05 PM
*/
@Root @Root
public class DisplayHistoryState implements Cloneable { public class DisplayHistoryState implements Cloneable {
@ -81,11 +75,11 @@ public class DisplayHistoryState implements Cloneable {
return result; return result;
} }
public void setValuesFromHistory(@Nonnull CalculatorDisplay display) { public void setValuesFromHistory(@Nonnull Display display) {
if (this.isValid()) { if (this.isValid()) {
display.setViewState(DisplayState.createValid(this.getJsclOperation(), this.getGenericResult(), Strings.getNotEmpty(this.getEditorState().getText(), ""), this.getEditorState().getCursorPosition())); display.setState(DisplayState.createValid(this.getJsclOperation(), this.getGenericResult(), Strings.getNotEmpty(this.getEditorState().getText(), ""), this.getEditorState().getCursorPosition(), EditorState.NO_SEQUENCE));
} else { } else {
display.setViewState(DisplayState.createError(this.getJsclOperation(), Strings.getNotEmpty(this.getErrorMessage(), ""))); display.setState(DisplayState.createError(this.getJsclOperation(), Strings.getNotEmpty(this.getErrorMessage(), ""), EditorState.NO_SEQUENCE));
} }
} }

View File

@ -24,7 +24,7 @@ package org.solovyev.android.calculator.history;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
import org.solovyev.android.calculator.CalculatorDisplay; import org.solovyev.android.calculator.Display;
import org.solovyev.android.calculator.DisplayState; import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.Editor; import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.EditorState; import org.solovyev.android.calculator.EditorState;
@ -54,8 +54,8 @@ public class HistoryState extends BaseHistoryState {
@Nonnull @Nonnull
public static HistoryState create(@Nonnull Editor editor, public static HistoryState create(@Nonnull Editor editor,
@Nonnull CalculatorDisplay display) { @Nonnull Display display) {
return create(editor.getState(), display.getViewState()); return create(editor.getState(), display.getState());
} }
@Nonnull @Nonnull
@ -106,7 +106,7 @@ public class HistoryState extends BaseHistoryState {
return result; return result;
} }
public void setValuesFromHistory(@Nonnull Editor editor, @Nonnull CalculatorDisplay display) { public void setValuesFromHistory(@Nonnull Editor editor, @Nonnull Display display) {
this.getEditorState().setValuesFromHistory(editor); this.getEditorState().setValuesFromHistory(editor);
this.getDisplayState().setValuesFromHistory(display); this.getDisplayState().setValuesFromHistory(display);
} }

View File

@ -41,12 +41,7 @@ import org.solovyev.android.calculator.*;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** public class CalculatorOnscreenService extends Service implements OnscreenViewListener, SharedPreferences.OnSharedPreferenceChangeListener {
* User: serso
* Date: 11/20/12
* Time: 9:42 PM
*/
public class CalculatorOnscreenService extends Service implements OnscreenViewListener, CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener {
public static final Class<CalculatorOnscreenBroadcastReceiver> INTENT_LISTENER_CLASS = CalculatorOnscreenBroadcastReceiver.class; public static final Class<CalculatorOnscreenBroadcastReceiver> INTENT_LISTENER_CLASS = CalculatorOnscreenBroadcastReceiver.class;
private static final String SHOW_WINDOW_ACTION = "org.solovyev.android.calculator.onscreen.SHOW_WINDOW"; private static final String SHOW_WINDOW_ACTION = "org.solovyev.android.calculator.onscreen.SHOW_WINDOW";
@ -107,7 +102,7 @@ public class CalculatorOnscreenService extends Service implements OnscreenViewLi
view = CalculatorOnscreenView.create(this, CalculatorOnscreenViewState.create(width, height, -1, -1), this); view = CalculatorOnscreenView.create(this, CalculatorOnscreenViewState.create(width, height, -1, -1), this);
view.show(); view.show();
view.updateEditorState(Locator.getInstance().getEditor().getState()); view.updateEditorState(Locator.getInstance().getEditor().getState());
view.updateDisplayState(Locator.getInstance().getDisplay().getViewState()); view.updateDisplayState(Locator.getInstance().getDisplay().getState());
App.getBus().register(this); App.getBus().register(this);
App.getPreferences().registerOnSharedPreferenceChangeListener(this); App.getPreferences().registerOnSharedPreferenceChangeListener(this);
@ -186,15 +181,6 @@ public class CalculatorOnscreenService extends Service implements OnscreenViewLi
nm.notify(NOTIFICATION_ID, builder.getNotification()); nm.notify(NOTIFICATION_ID, builder.getNotification());
} }
@Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) {
case display_state_changed:
view.updateDisplayState(((CalculatorDisplayChangeEventData) data).getNewValue());
break;
}
}
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Check.isNotNull(view); Check.isNotNull(view);
@ -215,5 +201,11 @@ public class CalculatorOnscreenService extends Service implements OnscreenViewLi
Check.isNotNull(view); Check.isNotNull(view);
view.updateEditorState(e.state); view.updateEditorState(e.state);
} }
@Subscribe
public void onDisplayChanged(@Nonnull Display.ChangedEvent e) {
Check.isNotNull(view);
view.updateDisplayState(e.newState);
}
} }

View File

@ -91,7 +91,7 @@ public class CalculatorOnscreenView {
private EditorView editorView; private EditorView editorView;
@Nonnull @Nonnull
private AndroidCalculatorDisplayView displayView; private DisplayView displayView;
@Nonnull @Nonnull
private Context context; private Context context;
@ -215,8 +215,7 @@ public class CalculatorOnscreenView {
headerTitle.setImageDrawable(null); headerTitle.setImageDrawable(null);
content = root.findViewById(R.id.onscreen_content); content = root.findViewById(R.id.onscreen_content);
displayView = (AndroidCalculatorDisplayView) root.findViewById(R.id.calculator_display); displayView = (DisplayView) root.findViewById(R.id.calculator_display);
displayView.init(this.context, false);
editorView = (EditorView) root.findViewById(R.id.calculator_editor); editorView = (EditorView) root.findViewById(R.id.calculator_editor);

View File

@ -71,7 +71,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
graphView = new CalculatorGraph2dView(getActivity()); graphView = new CalculatorGraph2dView(getActivity());
} }
final int color = App.getTheme().getTextColor(getActivity()).normal; final int color = App.getTheme().getTextColorFor(getActivity()).normal;
graphView.init(PlotViewDef.newInstance(color, color, Color.DKGRAY, getBgColor(d3))); graphView.init(PlotViewDef.newInstance(color, color, Color.DKGRAY, getBgColor(d3)));
final PlotBoundaries boundaries = plotData.getBoundaries(); final PlotBoundaries boundaries = plotData.getBoundaries();

View File

@ -92,6 +92,6 @@ public final class EditorTextProcessor implements TextProcessor<TextProcessorEdi
private int getTextColor(@Nonnull SharedPreferences preferences) { private int getTextColor(@Nonnull SharedPreferences preferences) {
final Preferences.Gui.Theme theme = Preferences.Gui.getTheme(preferences); final Preferences.Gui.Theme theme = Preferences.Gui.getTheme(preferences);
final Application application = App.getApplication(); final Application application = App.getApplication();
return theme.getTextColor(application).normal; return theme.getTextColorFor(application).normal;
} }
} }

View File

@ -33,7 +33,6 @@ import android.content.res.Resources;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
@ -112,7 +111,7 @@ public class CalculatorWidget extends AppWidgetProvider {
@Nonnull int[] widgetIds, @Nonnull int[] widgetIds,
boolean partially) { boolean partially) {
final EditorState editorState = Locator.getInstance().getEditor().getState(); final EditorState editorState = Locator.getInstance().getEditor().getState();
final DisplayState displayState = Locator.getInstance().getDisplay().getViewState(); final DisplayState displayState = Locator.getInstance().getDisplay().getState();
final Resources resources = context.getResources(); final Resources resources = context.getResources();
final SimpleTheme theme = App.getWidgetTheme().resolveThemeFor(App.getTheme()); final SimpleTheme theme = App.getWidgetTheme().resolveThemeFor(App.getTheme());
@ -222,7 +221,7 @@ public class CalculatorWidget extends AppWidgetProvider {
final CharSequence text = state.text; final CharSequence text = state.text;
final int selection = state.selection; final int selection = state.selection;
if (selection < 0 || selection > text.length()) { if (selection < 0 || selection > text.length()) {
views.setTextViewText(R.id.calculator_editor, unspan ? unspan(text) : text); views.setTextViewText(R.id.calculator_editor, unspan ? App.unspan(text) : text);
return; return;
} }
@ -233,9 +232,9 @@ public class CalculatorWidget extends AppWidgetProvider {
final CharSequence afterCursor = text.subSequence(selection, text.length()); final CharSequence afterCursor = text.subSequence(selection, text.length());
result = new SpannableStringBuilder(); result = new SpannableStringBuilder();
result.append(unspan(beforeCursor)); result.append(App.unspan(beforeCursor));
result.append(getCursorString(context)); result.append(getCursorString(context));
result.append(unspan(afterCursor)); result.append(App.unspan(afterCursor));
} else { } else {
result = new SpannableStringBuilder(text); result = new SpannableStringBuilder(text);
result.insert(selection, getCursorString(context)); result.insert(selection, getCursorString(context));
@ -243,11 +242,6 @@ public class CalculatorWidget extends AppWidgetProvider {
views.setTextViewText(R.id.calculator_editor, result); views.setTextViewText(R.id.calculator_editor, result);
} }
@NonNull
private String unspan(@Nonnull CharSequence spannable) {
return spannable.toString();
}
private static class Intents { private static class Intents {
@Nonnull @Nonnull
private final EnumMap<CalculatorButton, PendingIntent> map = new EnumMap<>(CalculatorButton.class); private final EnumMap<CalculatorButton, PendingIntent> map = new EnumMap<>(CalculatorButton.class);

View File

@ -34,7 +34,7 @@
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="wrap_content" /> a:layout_height="wrap_content" />
<org.solovyev.android.calculator.AndroidCalculatorDisplayView <org.solovyev.android.calculator.DisplayView
a:id="@+id/calculator_display" a:id="@+id/calculator_display"
style="@style/CppText.Display" style="@style/CppText.Display"
a:inputType="textMultiLine" a:inputType="textMultiLine"

View File

@ -34,7 +34,7 @@
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="wrap_content" /> a:layout_height="wrap_content" />
<org.solovyev.android.calculator.AndroidCalculatorDisplayView <org.solovyev.android.calculator.DisplayView
a:id="@+id/calculator_display" a:id="@+id/calculator_display"
style="@style/CppText.Display" style="@style/CppText.Display"
a:inputType="textMultiLine" a:inputType="textMultiLine"

View File

@ -22,7 +22,7 @@
~ Site: http://se.solovyev.org ~ Site: http://se.solovyev.org
--> -->
<org.solovyev.android.calculator.AndroidCalculatorDisplayView <org.solovyev.android.calculator.DisplayView
xmlns:a="http://schemas.android.com/apk/res/android" xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/calculator_display" a:id="@+id/calculator_display"
style="@style/CppText.Display" style="@style/CppText.Display"

View File

@ -22,7 +22,7 @@
~ Site: http://se.solovyev.org ~ Site: http://se.solovyev.org
--> -->
<org.solovyev.android.calculator.AndroidCalculatorDisplayView <org.solovyev.android.calculator.DisplayView
xmlns:a="http://schemas.android.com/apk/res/android" xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/calculator_display" a:id="@+id/calculator_display"
style="@style/CppText.Display" style="@style/CppText.Display"

View File

@ -6,7 +6,7 @@
~ or visit http://se.solovyev.org ~ or visit http://se.solovyev.org
--> -->
<org.solovyev.android.calculator.AndroidCalculatorDisplayView <org.solovyev.android.calculator.DisplayView
xmlns:a="http://schemas.android.com/apk/res/android" xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/calculator_display" a:id="@+id/calculator_display"
style="@style/CppText.Display.Onscreen" style="@style/CppText.Display.Onscreen"

View File

@ -6,7 +6,7 @@
~ or visit http://se.solovyev.org ~ or visit http://se.solovyev.org
--> -->
<org.solovyev.android.calculator.AndroidCalculatorDisplayView <org.solovyev.android.calculator.DisplayView
xmlns:a="http://schemas.android.com/apk/res/android" xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/calculator_display" a:id="@+id/calculator_display"
style="@style/CppText.Display.Onscreen.Light" style="@style/CppText.Display.Onscreen.Light"

View File

@ -1,46 +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;
import org.junit.Test;
import org.solovyev.android.calculator.jscl.JsclOperation;
import jscl.math.Expression;
/**
* User: serso
* Date: 10/20/12
* Time: 12:24 PM
*/
public class CalculatorDisplayViewStateImplTest {
@Test
public void testSerializable() throws Exception {
CalculatorTestUtils.testSerialization(DisplayState.createValid(JsclOperation.numeric, null, "test", 3));
CalculatorTestUtils.testSerialization(DisplayState.createValid(JsclOperation.numeric, Expression.valueOf("3"), "test", 3));
CalculatorTestUtils.testSerialization(DisplayState.createValid(JsclOperation.simplify, Expression.valueOf("3+3"), "test", 3));
CalculatorTestUtils.testSerialization(DisplayState.empty());
CalculatorTestUtils.testSerialization(DisplayState.createError(JsclOperation.numeric, "ertert"));
}
}

View File

@ -23,28 +23,20 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.content.Context; import android.content.Context;
import jscl.JsclMathEngine;
import org.junit.Assert; import org.junit.Assert;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.solovyev.android.calculator.history.CalculatorHistory; import org.solovyev.android.calculator.history.CalculatorHistory;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.plot.CalculatorPlotter; import org.solovyev.android.calculator.plot.CalculatorPlotter;
import java.io.ByteArrayInputStream; import javax.annotation.Nonnull;
import java.io.ByteArrayOutputStream; import javax.annotation.Nullable;
import java.io.IOException; import java.io.*;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.JsclMathEngine;
/** /**
* User: serso * User: serso
* Date: 10/7/12 * Date: 10/7/12
@ -75,12 +67,8 @@ public class CalculatorTestUtils {
} }
public static void initViews(@Nonnull Context context) { public static void initViews(@Nonnull Context context) {
final EditorView editor = new EditorView(context); Locator.getInstance().getEditor().setView(new EditorView(context));
Locator.getInstance().getEditor().setView(editor); Locator.getInstance().getDisplay().setView(new DisplayView(context));
final AndroidCalculatorDisplayView display = new AndroidCalculatorDisplayView(context);
display.init(context);
Locator.getInstance().getDisplay().setView(display);
} }
@Nonnull @Nonnull
@ -104,7 +92,7 @@ public class CalculatorTestUtils {
public static void assertEval(@Nonnull String expected, @Nonnull String expression, @Nonnull JsclOperation operation) { public static void assertEval(@Nonnull String expected, @Nonnull String expression, @Nonnull JsclOperation operation) {
final Calculator calculator = Locator.getInstance().getCalculator(); final Calculator calculator = Locator.getInstance().getCalculator();
Locator.getInstance().getDisplay().setViewState(DisplayState.empty()); Locator.getInstance().getDisplay().setState(DisplayState.empty());
final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1);
final TestCalculatorEventListener calculatorEventListener = new TestCalculatorEventListener(latch); final TestCalculatorEventListener calculatorEventListener = new TestCalculatorEventListener(latch);
@ -160,7 +148,7 @@ public class CalculatorTestUtils {
public static void assertError(@Nonnull String expression, @Nonnull JsclOperation operation) { public static void assertError(@Nonnull String expression, @Nonnull JsclOperation operation) {
final Calculator calculator = Locator.getInstance().getCalculator(); final Calculator calculator = Locator.getInstance().getCalculator();
Locator.getInstance().getDisplay().setViewState(DisplayState.empty()); Locator.getInstance().getDisplay().setState(DisplayState.empty());
final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1);
final TestCalculatorEventListener calculatorEventListener = new TestCalculatorEventListener(latch); final TestCalculatorEventListener calculatorEventListener = new TestCalculatorEventListener(latch);
@ -204,10 +192,10 @@ public class CalculatorTestUtils {
waitForEventData(); waitForEventData();
if (calculatorEventData.isSameSequence(this.calculatorEventData)) { if (calculatorEventData.isSameSequence(this.calculatorEventData)) {
if (calculatorEventType == CalculatorEventType.display_state_changed) { /*if (calculatorEventType == CalculatorEventType.display_state_changed) {
final CalculatorDisplayChangeEventData displayChange = (CalculatorDisplayChangeEventData) data; final Display.ChangedEvent displayChange = (Display.ChangedEvent) data;
result = displayChange.getNewValue(); result = displayChange.newState;
try { try {
// need to sleep a little bit as await // need to sleep a little bit as await
@ -215,7 +203,7 @@ public class CalculatorTestUtils {
} catch (InterruptedException e) { } catch (InterruptedException e) {
} }
latch.countDown(); latch.countDown();
} }*/
} }
} }

View File

@ -137,7 +137,7 @@ public class HistoryUtilsTest {
HistoryHelper<HistoryState> history = SimpleHistoryHelper.newInstance(); HistoryHelper<HistoryState> history = SimpleHistoryHelper.newInstance();
DisplayState calculatorDisplay = DisplayState.createError(JsclOperation.simplify, "Error"); DisplayState calculatorDisplay = DisplayState.createError(JsclOperation.simplify, "Error", EditorState.NO_SEQUENCE);
EditorState calculatorEditor = EditorState.create("1+1", 3); EditorState calculatorEditor = EditorState.create("1+1", 3);
@ -152,7 +152,7 @@ public class HistoryUtilsTest {
assertEquals(toXml1, createHistory(history).toXml()); assertEquals(toXml1, createHistory(history).toXml());
calculatorDisplay = DisplayState.createValid(JsclOperation.numeric, null, "5/6", 3); calculatorDisplay = DisplayState.createValid(JsclOperation.numeric, null, "5/6", 3, EditorState.NO_SEQUENCE);
calculatorEditor = EditorState.create("5/6", 2); calculatorEditor = EditorState.create("5/6", 2);
@ -161,7 +161,7 @@ public class HistoryUtilsTest {
state.setTime(date.getTime()); state.setTime(date.getTime());
history.addState(state); history.addState(state);
calculatorDisplay = DisplayState.createError(JsclOperation.elementary, "Error"); calculatorDisplay = DisplayState.createError(JsclOperation.elementary, "Error", EditorState.NO_SEQUENCE);
calculatorEditor = EditorState.create("", 1); calculatorEditor = EditorState.create("", 1);
@ -170,7 +170,7 @@ public class HistoryUtilsTest {
state.setTime(date.getTime()); state.setTime(date.getTime());
history.addState(state); history.addState(state);
calculatorDisplay = DisplayState.createValid(JsclOperation.numeric, null, "4+5/35sin(41)+dfdsfsdfs", 1); calculatorDisplay = DisplayState.createValid(JsclOperation.numeric, null, "4+5/35sin(41)+dfdsfsdfs", 1, EditorState.NO_SEQUENCE);
calculatorEditor = EditorState.create("4+5/35sin(41)+dfdsfsdfs", 0); calculatorEditor = EditorState.create("4+5/35sin(41)+dfdsfsdfs", 0);