android-app -> app
android-app-tests -> app-tests
This commit is contained in:
172
app/src/main/java/org/solovyev/android/Check.java
Normal file
172
app/src/main/java/org/solovyev/android/Check.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import android.os.Looper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.lang.Thread.currentThread;
|
||||
|
||||
public final class Check {
|
||||
|
||||
private static final boolean junit = isJunit();
|
||||
|
||||
private Check() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
private static boolean isJunit() {
|
||||
final StackTraceElement[] stackTrace = currentThread().getStackTrace();
|
||||
for (StackTraceElement element : stackTrace) {
|
||||
if (element.getClassName().startsWith("org.junit.")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void isMainThread() {
|
||||
if (!junit && Looper.getMainLooper() != Looper.myLooper()) {
|
||||
throw new AssertionException("Should be called on the main thread");
|
||||
}
|
||||
}
|
||||
|
||||
public static void isNotNull(@Nullable Object o) {
|
||||
isNotNull(o, "Object should not be null");
|
||||
}
|
||||
|
||||
public static void isNotNull(@Nullable Object o, @Nonnull String message) {
|
||||
if (o == null) {
|
||||
throw new AssertionException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notEquals(int expected, int actual) {
|
||||
if (expected == actual) {
|
||||
throw new AssertionException("Should not be equal");
|
||||
}
|
||||
}
|
||||
|
||||
public static void equals(int expected, int actual) {
|
||||
if (expected != actual) {
|
||||
throw new AssertionException("Should be equal");
|
||||
}
|
||||
}
|
||||
|
||||
public static void equals(@Nullable Object expected, @Nullable Object actual) {
|
||||
equals(expected, actual, "Should be equal");
|
||||
}
|
||||
|
||||
public static void equals(@Nullable Object expected, @Nullable Object actual, @Nonnull String message) {
|
||||
if (expected == actual) {
|
||||
// both nulls or same
|
||||
return;
|
||||
}
|
||||
|
||||
if (expected != null && actual != null && expected.equals(actual)) {
|
||||
// equals
|
||||
return;
|
||||
}
|
||||
|
||||
throw new AssertionException(message);
|
||||
}
|
||||
|
||||
public static void isTrue(boolean expression) {
|
||||
if (!expression) {
|
||||
throw new AssertionException("");
|
||||
}
|
||||
}
|
||||
|
||||
public static void isTrue(boolean expression, @Nonnull String message) {
|
||||
if (!expression) {
|
||||
throw new AssertionException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void isFalse(boolean expression, @Nonnull String message) {
|
||||
if (expression) {
|
||||
throw new AssertionException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void isNull(@Nullable Object o) {
|
||||
isNull(o, "Object should be null");
|
||||
}
|
||||
|
||||
public static void isNull(@Nullable Object o, @Nonnull String message) {
|
||||
if (o != null) {
|
||||
throw new AssertionException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void isNotEmpty(@Nullable String s) {
|
||||
if (s == null || s.length() == 0) {
|
||||
throw new AssertionException("String should not be empty");
|
||||
}
|
||||
}
|
||||
|
||||
public static void isNotEmpty(@Nullable String[] array) {
|
||||
if (array == null || array.length == 0) {
|
||||
throw new AssertionException("Array should not be empty");
|
||||
}
|
||||
}
|
||||
|
||||
public static void isNotEmpty(@Nullable Collection<?> c) {
|
||||
if (c == null || c.size() == 0) {
|
||||
throw new AssertionException("Collection should not be empty");
|
||||
}
|
||||
}
|
||||
|
||||
public static void isNotEmpty(@Nullable Map<?, ?> c) {
|
||||
if (c == null || c.size() == 0) {
|
||||
throw new AssertionException("Map should not be empty");
|
||||
}
|
||||
}
|
||||
|
||||
public static void same(Object expected, Object actual) {
|
||||
if (expected != actual) {
|
||||
throw new AssertionException("Objects should be the same");
|
||||
}
|
||||
}
|
||||
|
||||
public static void isEmpty(@Nullable Collection<?> c) {
|
||||
if (c != null && !c.isEmpty()) {
|
||||
throw new AssertionException("Collection should be empty");
|
||||
}
|
||||
}
|
||||
|
||||
public static void shouldNotHappen() {
|
||||
throw new AssertionException("Should not happen");
|
||||
}
|
||||
|
||||
private static final class AssertionException extends RuntimeException {
|
||||
private AssertionException(@Nonnull String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.solovyev.common.JBuilder;
|
||||
import org.solovyev.common.math.MathEntity;
|
||||
import org.solovyev.common.math.MathRegistry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/30/11
|
||||
* Time: 1:03 AM
|
||||
*/
|
||||
public abstract class AbstractCalculatorMathRegistry<T extends MathEntity, P extends MathPersistenceEntity> implements CalculatorMathRegistry<T> {
|
||||
|
||||
@Nonnull
|
||||
private final MathRegistry<T> mathRegistry;
|
||||
|
||||
@Nonnull
|
||||
private final String prefix;
|
||||
|
||||
@Nonnull
|
||||
private final MathEntityDao<P> mathEntityDao;
|
||||
|
||||
protected AbstractCalculatorMathRegistry(@Nonnull MathRegistry<T> mathRegistry,
|
||||
@Nonnull String prefix,
|
||||
@Nonnull MathEntityDao<P> mathEntityDao) {
|
||||
this.mathRegistry = mathRegistry;
|
||||
this.prefix = prefix;
|
||||
this.mathEntityDao = mathEntityDao;
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
protected abstract Map<String, String> getSubstitutes();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getDescription(@Nonnull String mathEntityName) {
|
||||
final String stringName;
|
||||
|
||||
final Map<String, String> substitutes = getSubstitutes();
|
||||
final String substitute = substitutes.get(mathEntityName);
|
||||
if (substitute == null) {
|
||||
stringName = prefix + mathEntityName;
|
||||
} else {
|
||||
stringName = prefix + substitute;
|
||||
}
|
||||
|
||||
return mathEntityDao.getDescription(stringName);
|
||||
}
|
||||
|
||||
public synchronized void load() {
|
||||
final MathEntityPersistenceContainer<P> persistenceContainer = mathEntityDao.load();
|
||||
|
||||
final List<P> notCreatedEntities = new ArrayList<P>();
|
||||
|
||||
if (persistenceContainer != null) {
|
||||
for (P entity : persistenceContainer.getEntities()) {
|
||||
if (!contains(entity.getName())) {
|
||||
try {
|
||||
final JBuilder<? extends T> builder = createBuilder(entity);
|
||||
add(builder);
|
||||
} catch (RuntimeException e) {
|
||||
Locator.getInstance().getLogger().error(null, e.getLocalizedMessage(), e);
|
||||
notCreatedEntities.add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (!notCreatedEntities.isEmpty()) {
|
||||
final StringBuilder errorMessage = new StringBuilder(notCreatedEntities.size() * 100);
|
||||
for (P notCreatedEntity : notCreatedEntities) {
|
||||
errorMessage.append(notCreatedEntity).append("\n\n");
|
||||
}
|
||||
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_message_dialog, MessageDialogData.newInstance(CalculatorMessages.newErrorMessage(CalculatorMessages.msg_007, errorMessage.toString()), null));
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
// just in case
|
||||
Locator.getInstance().getLogger().error(null, e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected abstract JBuilder<? extends T> createBuilder(@Nonnull P entity);
|
||||
|
||||
@Override
|
||||
public synchronized void save() {
|
||||
final MathEntityPersistenceContainer<P> container = createPersistenceContainer();
|
||||
|
||||
for (T entity : this.getEntities()) {
|
||||
if (!entity.isSystem()) {
|
||||
final P persistenceEntity = transform(entity);
|
||||
if (persistenceEntity != null) {
|
||||
container.getEntities().add(persistenceEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.mathEntityDao.save(container);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract P transform(@Nonnull T entity);
|
||||
|
||||
@Nonnull
|
||||
protected abstract MathEntityPersistenceContainer<P> createPersistenceContainer();
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<T> getEntities() {
|
||||
return mathRegistry.getEntities();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<T> getSystemEntities() {
|
||||
return mathRegistry.getSystemEntities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T add(@Nonnull JBuilder<? extends T> JBuilder) {
|
||||
return mathRegistry.add(JBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(@Nonnull T var) {
|
||||
mathRegistry.remove(var);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<String> getNames() {
|
||||
return mathRegistry.getNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nonnull String name) {
|
||||
return mathRegistry.contains(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(@Nonnull String name) {
|
||||
return mathRegistry.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getById(@Nonnull Integer id) {
|
||||
return mathRegistry.getById(id);
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.Nullable;
|
||||
|
||||
public abstract class AbstractFixableError implements FixableError {
|
||||
|
||||
@Nullable
|
||||
private String fixCaption;
|
||||
|
||||
protected AbstractFixableError() {
|
||||
}
|
||||
|
||||
protected AbstractFixableError(@Nullable String fixCaption) {
|
||||
this.fixCaption = fixCaption;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CharSequence getFixCaption() {
|
||||
return fixCaption;
|
||||
}
|
||||
}
|
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.math.MathType;
|
||||
import org.solovyev.common.text.Strings;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.NumeralBase;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 12/15/11
|
||||
* Time: 9:01 PM
|
||||
*/
|
||||
public abstract class AbstractNumberBuilder {
|
||||
|
||||
@Nonnull
|
||||
protected final CalculatorEngine engine;
|
||||
|
||||
@Nullable
|
||||
protected StringBuilder numberBuilder = null;
|
||||
|
||||
@Nullable
|
||||
protected NumeralBase nb;
|
||||
|
||||
protected AbstractNumberBuilder(@Nonnull CalculatorEngine engine) {
|
||||
this.engine = engine;
|
||||
this.nb = engine.getNumeralBase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method determines if we can continue to process current number
|
||||
*
|
||||
* @param mathTypeResult current math type result
|
||||
* @return true if we can continue of processing of current number, if false - new number should be constructed
|
||||
*/
|
||||
protected boolean canContinue(@Nonnull MathType.Result mathTypeResult) {
|
||||
boolean result = mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number &&
|
||||
!spaceBefore(mathTypeResult) &&
|
||||
numeralBaseCheck(mathTypeResult) &&
|
||||
numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean spaceBefore(@Nonnull MathType.Result mathTypeResult) {
|
||||
return numberBuilder == null && Strings.isEmpty(mathTypeResult.getMatch().trim());
|
||||
}
|
||||
|
||||
private boolean numeralBaseInTheStart(@Nonnull MathType mathType) {
|
||||
return mathType != MathType.numeral_base || numberBuilder == null;
|
||||
}
|
||||
|
||||
private boolean numeralBaseCheck(@Nonnull MathType.Result mathType) {
|
||||
return mathType.getMathType() != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.getMatch().charAt(0));
|
||||
}
|
||||
|
||||
private boolean isSignAfterE(@Nonnull MathType.Result mathTypeResult) {
|
||||
if (!isHexMode()) {
|
||||
final String match = mathTypeResult.getMatch();
|
||||
if ("−".equals(match) || "-".equals(match) || "+".equals(match)) {
|
||||
final StringBuilder localNb = numberBuilder;
|
||||
if (localNb != null && localNb.length() > 0) {
|
||||
if (localNb.charAt(localNb.length() - 1) == MathType.POWER_10) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isHexMode() {
|
||||
return nb == NumeralBase.hex || (nb == null && engine.getNumeralBase() == NumeralBase.hex);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected NumeralBase getNumeralBase() {
|
||||
return nb == null ? engine.getNumeralBase() : nb;
|
||||
}
|
||||
}
|
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.solovyev.android.Activities;
|
||||
import org.solovyev.android.Views;
|
||||
import org.solovyev.android.calculator.language.Language;
|
||||
import org.solovyev.android.calculator.language.Languages;
|
||||
import org.solovyev.android.sherlock.tabs.ActionBarFragmentTabListener;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ActivityUi extends BaseUi {
|
||||
|
||||
private int layoutId;
|
||||
|
||||
@Nonnull
|
||||
private Preferences.Gui.Theme theme = Preferences.Gui.Theme.material_theme;
|
||||
|
||||
@Nonnull
|
||||
private Preferences.Gui.Layout layout = Preferences.Gui.Layout.main_calculator;
|
||||
|
||||
@Nonnull
|
||||
private Language language = Languages.SYSTEM_LANGUAGE;
|
||||
|
||||
private int selectedNavigationIndex = 0;
|
||||
|
||||
public ActivityUi(@LayoutRes int layoutId, @Nonnull String logTag) {
|
||||
super(logTag);
|
||||
this.layoutId = layoutId;
|
||||
}
|
||||
|
||||
public static boolean restartIfThemeChanged(@Nonnull Activity activity, @Nonnull Preferences.Gui.Theme oldTheme) {
|
||||
final Preferences.Gui.Theme newTheme = Preferences.Gui.theme.getPreference(App.getPreferences());
|
||||
final int themeId = oldTheme.getThemeId(activity);
|
||||
final int newThemeId = newTheme.getThemeId(activity);
|
||||
if (themeId != newThemeId) {
|
||||
Activities.restartActivity(activity);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean restartIfLanguageChanged(@Nonnull Activity activity, @Nonnull Language oldLanguage) {
|
||||
final Language current = App.getLanguages().getCurrent();
|
||||
if (!current.equals(oldLanguage)) {
|
||||
Activities.restartActivity(activity);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void reportActivityStop(@Nonnull Activity activity) {
|
||||
App.getGa().getAnalytics().reportActivityStop(activity);
|
||||
}
|
||||
|
||||
public static void reportActivityStart(@Nonnull Activity activity) {
|
||||
App.getGa().getAnalytics().reportActivityStart(activity);
|
||||
}
|
||||
|
||||
public void onPreCreate(@Nonnull Activity activity) {
|
||||
final SharedPreferences preferences = App.getPreferences();
|
||||
|
||||
theme = Preferences.Gui.getTheme(preferences);
|
||||
activity.setTheme(theme.getThemeId(activity));
|
||||
|
||||
layout = Preferences.Gui.getLayout(preferences);
|
||||
language = App.getLanguages().getCurrent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nonnull Activity activity) {
|
||||
super.onCreate(activity);
|
||||
App.getLanguages().updateLanguage(activity, false);
|
||||
|
||||
if (activity instanceof CalculatorEventListener) {
|
||||
Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) activity);
|
||||
}
|
||||
|
||||
activity.setContentView(layoutId);
|
||||
|
||||
final View root = activity.findViewById(R.id.main_layout);
|
||||
if (root != null) {
|
||||
processButtons(activity, root);
|
||||
fixFonts(root);
|
||||
addHelpInfo(activity, root);
|
||||
}
|
||||
}
|
||||
|
||||
public void onCreate(@Nonnull final ActionBarActivity activity) {
|
||||
onCreate((Activity) activity);
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
initActionBar(activity, actionBar);
|
||||
}
|
||||
}
|
||||
|
||||
private void initActionBar(@Nonnull Activity activity, @Nonnull ActionBar actionBar) {
|
||||
actionBar.setDisplayUseLogoEnabled(false);
|
||||
final boolean homeAsUp = !(activity instanceof CalculatorActivity);
|
||||
actionBar.setDisplayHomeAsUpEnabled(homeAsUp);
|
||||
actionBar.setHomeButtonEnabled(false);
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
actionBar.setElevation(0);
|
||||
|
||||
toggleTitle(activity, actionBar, true);
|
||||
|
||||
if (!homeAsUp) {
|
||||
actionBar.setIcon(R.drawable.ab_logo);
|
||||
}
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||
}
|
||||
|
||||
private void toggleTitle(@Nonnull Activity activity, @Nonnull ActionBar actionBar, boolean showTitle) {
|
||||
if (activity instanceof CalculatorActivity) {
|
||||
if (Views.getScreenOrientation(activity) == Configuration.ORIENTATION_PORTRAIT) {
|
||||
actionBar.setDisplayShowTitleEnabled(true);
|
||||
} else {
|
||||
actionBar.setDisplayShowTitleEnabled(false);
|
||||
}
|
||||
} else {
|
||||
actionBar.setDisplayShowTitleEnabled(showTitle);
|
||||
}
|
||||
}
|
||||
|
||||
public void restoreSavedTab(@Nonnull ActionBarActivity activity) {
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
if (selectedNavigationIndex >= 0 && selectedNavigationIndex < actionBar.getTabCount()) {
|
||||
actionBar.setSelectedNavigationItem(selectedNavigationIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSaveInstanceState(@Nonnull ActionBarActivity activity, @Nonnull Bundle outState) {
|
||||
onSaveInstanceState((Activity) activity, outState);
|
||||
}
|
||||
|
||||
public void onSaveInstanceState(@Nonnull Activity activity, @Nonnull Bundle outState) {
|
||||
}
|
||||
|
||||
public void onResume(@Nonnull Activity activity) {
|
||||
if (!restartIfThemeChanged(activity, theme)) {
|
||||
restartIfLanguageChanged(activity, language);
|
||||
}
|
||||
}
|
||||
|
||||
public void onPause(@Nonnull Activity activity) {
|
||||
}
|
||||
|
||||
public void onPause(@Nonnull ActionBarActivity activity) {
|
||||
onPause((Activity) activity);
|
||||
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
final int selectedNavigationIndex = actionBar.getSelectedNavigationIndex();
|
||||
if (selectedNavigationIndex >= 0) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
final SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt(getSavedTabPreferenceName(activity), selectedNavigationIndex);
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private String getSavedTabPreferenceName(@Nonnull Activity activity) {
|
||||
return "tab_" + activity.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(@Nonnull Activity activity) {
|
||||
super.onDestroy(activity);
|
||||
|
||||
if (activity instanceof CalculatorEventListener) {
|
||||
Locator.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) activity);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDestroy(@Nonnull ActionBarActivity activity) {
|
||||
this.onDestroy((Activity) activity);
|
||||
}
|
||||
|
||||
public void addTab(@Nonnull ActionBarActivity activity,
|
||||
@Nonnull String tag,
|
||||
@Nonnull Class<? extends Fragment> fragmentClass,
|
||||
@Nullable Bundle fragmentArgs,
|
||||
int captionResId,
|
||||
int parentViewId) {
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
|
||||
final ActionBar.Tab tab = actionBar.newTab();
|
||||
tab.setTag(tag);
|
||||
tab.setText(captionResId);
|
||||
|
||||
final ActionBarFragmentTabListener listener = new ActionBarFragmentTabListener(activity, tag, fragmentClass, fragmentArgs, parentViewId);
|
||||
tab.setTabListener(listener);
|
||||
actionBar.addTab(tab);
|
||||
}
|
||||
|
||||
public void addTab(@Nonnull ActionBarActivity activity, @Nonnull CalculatorFragmentType fragmentType, @Nullable Bundle fragmentArgs, int parentViewId) {
|
||||
addTab(activity, fragmentType.getFragmentTag(), fragmentType.getFragmentClass(), fragmentArgs, fragmentType.getDefaultTitleResId(), parentViewId);
|
||||
}
|
||||
|
||||
public void setFragment(@Nonnull ActionBarActivity activity, @Nonnull CalculatorFragmentType fragmentType, @Nullable Bundle fragmentArgs, int parentViewId) {
|
||||
final FragmentManager fm = activity.getSupportFragmentManager();
|
||||
|
||||
Fragment fragment = fm.findFragmentByTag(fragmentType.getFragmentTag());
|
||||
if (fragment == null) {
|
||||
fragment = Fragment.instantiate(activity, fragmentType.getFragmentClass().getName(), fragmentArgs);
|
||||
final FragmentTransaction ft = fm.beginTransaction();
|
||||
ft.add(parentViewId, fragment, fragmentType.getFragmentTag());
|
||||
ft.commit();
|
||||
} else {
|
||||
if (fragment.isDetached()) {
|
||||
final FragmentTransaction ft = fm.beginTransaction();
|
||||
ft.attach(fragment);
|
||||
ft.commit();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void selectTab(@Nonnull ActionBarActivity activity, @Nonnull CalculatorFragmentType fragmentType) {
|
||||
final ActionBar actionBar = activity.getSupportActionBar();
|
||||
for (int i = 0; i < actionBar.getTabCount(); i++) {
|
||||
final ActionBar.Tab tab = actionBar.getTabAt(i);
|
||||
if (tab != null && fragmentType.getFragmentTag().equals(tab.getTag())) {
|
||||
actionBar.setSelectedNavigationItem(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getLayoutId() {
|
||||
return layoutId;
|
||||
}
|
||||
|
||||
public void setLayoutId(int layoutId) {
|
||||
this.layoutId = layoutId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Preferences.Gui.Theme getTheme() {
|
||||
return theme;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Language getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Preferences.Gui.Layout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
public void onResume(@Nonnull ActionBarActivity activity) {
|
||||
onResume((Activity) activity);
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
selectedNavigationIndex = preferences.getInt(getSavedTabPreferenceName(activity), -1);
|
||||
restoreSavedTab(activity);
|
||||
}
|
||||
|
||||
private void addHelpInfo(@Nonnull Activity activity, @Nonnull View root) {
|
||||
if (CalculatorApplication.isMonkeyRunner(activity)) {
|
||||
if (root instanceof ViewGroup) {
|
||||
final TextView helperTextView = new TextView(activity);
|
||||
|
||||
final DisplayMetrics dm = new DisplayMetrics();
|
||||
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
|
||||
|
||||
helperTextView.setTextSize(15);
|
||||
helperTextView.setTextColor(Color.WHITE);
|
||||
|
||||
final Configuration c = activity.getResources().getConfiguration();
|
||||
|
||||
final StringBuilder helpText = new StringBuilder();
|
||||
helpText.append("Size: ");
|
||||
if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE, c)) {
|
||||
helpText.append("xlarge");
|
||||
} else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE, c)) {
|
||||
helpText.append("large");
|
||||
} else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_NORMAL, c)) {
|
||||
helpText.append("normal");
|
||||
} else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_SMALL, c)) {
|
||||
helpText.append("small");
|
||||
} else {
|
||||
helpText.append("unknown");
|
||||
}
|
||||
|
||||
helpText.append(" (").append(dm.widthPixels).append("x").append(dm.heightPixels).append(")");
|
||||
|
||||
helpText.append(" Density: ");
|
||||
switch (dm.densityDpi) {
|
||||
case DisplayMetrics.DENSITY_LOW:
|
||||
helpText.append("ldpi");
|
||||
break;
|
||||
case DisplayMetrics.DENSITY_MEDIUM:
|
||||
helpText.append("mdpi");
|
||||
break;
|
||||
case DisplayMetrics.DENSITY_HIGH:
|
||||
helpText.append("hdpi");
|
||||
break;
|
||||
case DisplayMetrics.DENSITY_XHIGH:
|
||||
helpText.append("xhdpi");
|
||||
break;
|
||||
case DisplayMetrics.DENSITY_TV:
|
||||
helpText.append("tv");
|
||||
break;
|
||||
}
|
||||
|
||||
helpText.append(" (").append(dm.densityDpi).append(")");
|
||||
|
||||
helperTextView.setText(helpText);
|
||||
|
||||
((ViewGroup) root).addView(helperTextView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onStop(@Nonnull Activity activity) {
|
||||
reportActivityStop(activity);
|
||||
}
|
||||
|
||||
public void onStart(@Nonnull Activity activity) {
|
||||
reportActivityStart(activity);
|
||||
}
|
||||
}
|
133
app/src/main/java/org/solovyev/android/calculator/AdView.java
Normal file
133
app/src/main/java/org/solovyev/android/calculator/AdView.java
Normal file
@@ -0,0 +1,133 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.google.android.gms.ads.AdListener;
|
||||
import com.google.android.gms.ads.AdRequest;
|
||||
|
||||
import org.solovyev.android.Check;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class AdView extends FrameLayout {
|
||||
|
||||
@Nullable
|
||||
private com.google.android.gms.ads.AdView admobView;
|
||||
@Nullable
|
||||
private AdView.AdViewListener admobListener;
|
||||
|
||||
public AdView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public AdView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public AdView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
destroyAdmobView();
|
||||
}
|
||||
|
||||
private void destroyAdmobView() {
|
||||
if (admobView != null) {
|
||||
admobView.destroy();
|
||||
admobView.setAdListener(null);
|
||||
admobView = null;
|
||||
}
|
||||
if (admobListener != null) {
|
||||
admobListener.destroy();
|
||||
admobListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
if (admobView != null) {
|
||||
admobView.pause();
|
||||
}
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
if (admobView != null) {
|
||||
admobView.resume();
|
||||
}
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (admobView != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
LayoutInflater.from(getContext()).inflate(R.layout.admob, this);
|
||||
admobView = (com.google.android.gms.ads.AdView) findViewById(R.id.admob);
|
||||
Check.isNotNull(admobView);
|
||||
if (admobView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
admobListener = new AdView.AdViewListener(this);
|
||||
admobView.setAdListener(admobListener);
|
||||
|
||||
final AdRequest.Builder b = new AdRequest.Builder();
|
||||
b.addTestDevice(AdRequest.DEVICE_ID_EMULATOR);
|
||||
if (BuildConfig.DEBUG) {
|
||||
// LG Nexus 5
|
||||
b.addTestDevice("B80E676D60CE6FDBE1B84A55464E3FE1");
|
||||
}
|
||||
admobView.loadAd(b.build());
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
if (admobView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setVisibility(GONE);
|
||||
|
||||
admobView.setVisibility(View.GONE);
|
||||
admobView.pause();
|
||||
destroyAdmobView();
|
||||
}
|
||||
|
||||
private static class AdViewListener extends AdListener {
|
||||
|
||||
@Nullable
|
||||
private AdView adView;
|
||||
|
||||
public AdViewListener(@Nonnull AdView adView) {
|
||||
this.adView = adView;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
adView = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdFailedToLoad(int errorCode) {
|
||||
if (adView != null) {
|
||||
adView.hide();
|
||||
adView = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdLoaded() {
|
||||
if (adView != null) {
|
||||
final com.google.android.gms.ads.AdView admobView = adView.admobView;
|
||||
if (admobView != null) {
|
||||
admobView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
adView.setVisibility(VISIBLE);
|
||||
adView = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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.Application;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import org.solovyev.android.calculator.history.CalculatorHistoryState;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
import org.solovyev.common.history.HistoryAction;
|
||||
import org.solovyev.common.msg.Message;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.NumeralBase;
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/22/12
|
||||
* Time: 5:42 PM
|
||||
*/
|
||||
public class AndroidCalculator implements Calculator, CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorImpl calculator = new CalculatorImpl();
|
||||
|
||||
@Nonnull
|
||||
private final Application context;
|
||||
|
||||
public AndroidCalculator(@Nonnull Application application) {
|
||||
this.context = application;
|
||||
this.calculator.addCalculatorEventListener(this);
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(application).registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* DELEGATED TO CALCULATOR
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public CalculatorEventData evaluate(@Nonnull JsclOperation operation, @Nonnull String expression) {
|
||||
return calculator.evaluate(operation, expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public CalculatorEventData evaluate(@Nonnull JsclOperation operation, @Nonnull String expression, @Nonnull Long sequenceId) {
|
||||
return calculator.evaluate(operation, expression, sequenceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCalculateOnFly() {
|
||||
return calculator.isCalculateOnFly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCalculateOnFly(boolean calculateOnFly) {
|
||||
calculator.setCalculateOnFly(calculateOnFly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConversionPossible(@Nonnull Generic generic, @Nonnull NumeralBase from, @Nonnull NumeralBase to) {
|
||||
return calculator.isConversionPossible(generic, from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public CalculatorEventData convert(@Nonnull Generic generic, @Nonnull NumeralBase to) {
|
||||
return calculator.convert(generic, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||
return calculator.fireCalculatorEvent(calculatorEventType, data);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data, @Nonnull Object source) {
|
||||
return calculator.fireCalculatorEvent(calculatorEventType, data, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data, @Nonnull Long sequenceId) {
|
||||
return calculator.fireCalculatorEvent(calculatorEventType, data, sequenceId);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public PreparedExpression prepareExpression(@Nonnull String expression) throws CalculatorParseException {
|
||||
return calculator.prepareExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
this.calculator.init();
|
||||
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
this.calculator.setCalculateOnFly(Preferences.Calculations.calculateOnFly.getPreference(prefs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener) {
|
||||
calculator.addCalculatorEventListener(calculatorEventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener) {
|
||||
calculator.removeCalculatorEventListener(calculatorEventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||
calculator.fireCalculatorEvent(calculatorEventData, calculatorEventType, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCalculatorEvents(@Nonnull List<CalculatorEvent> calculatorEvents) {
|
||||
calculator.fireCalculatorEvents(calculatorEvents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doHistoryAction(@Nonnull HistoryAction historyAction) {
|
||||
calculator.doHistoryAction(historyAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public CalculatorHistoryState getCurrentHistoryState() {
|
||||
return calculator.getCurrentHistoryState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentHistoryState(@Nonnull CalculatorHistoryState editorHistoryState) {
|
||||
calculator.setCurrentHistoryState(editorHistoryState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() {
|
||||
calculator.evaluate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate(@Nonnull Long sequenceId) {
|
||||
calculator.evaluate(sequenceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simplify() {
|
||||
calculator.simplify();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||
switch (calculatorEventType) {
|
||||
case calculation_messages:
|
||||
CalculatorActivityLauncher.showCalculationMessagesDialog(CalculatorApplication.getInstance(), (List<Message>) data);
|
||||
break;
|
||||
case show_history:
|
||||
CalculatorActivityLauncher.showHistory(CalculatorApplication.getInstance());
|
||||
break;
|
||||
case show_history_detached:
|
||||
CalculatorActivityLauncher.showHistory(CalculatorApplication.getInstance(), true);
|
||||
break;
|
||||
case show_functions:
|
||||
CalculatorActivityLauncher.showFunctions(CalculatorApplication.getInstance());
|
||||
break;
|
||||
case show_functions_detached:
|
||||
CalculatorActivityLauncher.showFunctions(CalculatorApplication.getInstance(), true);
|
||||
break;
|
||||
case show_operators:
|
||||
CalculatorActivityLauncher.showOperators(CalculatorApplication.getInstance());
|
||||
break;
|
||||
case show_operators_detached:
|
||||
CalculatorActivityLauncher.showOperators(CalculatorApplication.getInstance(), true);
|
||||
break;
|
||||
case show_vars:
|
||||
CalculatorActivityLauncher.showVars(CalculatorApplication.getInstance());
|
||||
break;
|
||||
case show_vars_detached:
|
||||
CalculatorActivityLauncher.showVars(CalculatorApplication.getInstance(), true);
|
||||
break;
|
||||
case show_settings:
|
||||
CalculatorActivityLauncher.showSettings(CalculatorApplication.getInstance());
|
||||
break;
|
||||
case show_settings_detached:
|
||||
CalculatorActivityLauncher.showSettings(CalculatorApplication.getInstance(), true);
|
||||
break;
|
||||
case show_like_dialog:
|
||||
CalculatorActivityLauncher.likeButtonPressed(CalculatorApplication.getInstance());
|
||||
break;
|
||||
case open_app:
|
||||
CalculatorActivityLauncher.openApp(CalculatorApplication.getInstance());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(@Nonnull SharedPreferences prefs, @Nonnull String key) {
|
||||
if (Preferences.Calculations.calculateOnFly.getKey().equals(key)) {
|
||||
this.calculator.setCalculateOnFly(Preferences.Calculations.calculateOnFly.getPreference(prefs));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.Application;
|
||||
import android.content.Context;
|
||||
import android.text.ClipboardManager;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/22/12
|
||||
* Time: 1:35 PM
|
||||
*/
|
||||
public class AndroidCalculatorClipboard implements CalculatorClipboard {
|
||||
|
||||
@Nonnull
|
||||
private final Context context;
|
||||
|
||||
public AndroidCalculatorClipboard(@Nonnull Application application) {
|
||||
this.context = application;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (clipboard.hasText()) {
|
||||
return String.valueOf(clipboard.getText());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(@Nonnull CharSequence text) {
|
||||
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboard.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(@Nonnull String text) {
|
||||
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboard.setText(text);
|
||||
}
|
||||
}
|
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.text.Html;
|
||||
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 CalculatorDisplayViewState state = CalculatorDisplayViewStateImpl.newDefaultInstance();
|
||||
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 CalculatorDisplayViewState getState() {
|
||||
synchronized (lock) {
|
||||
return this.state;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(@Nonnull final CalculatorDisplayViewState 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 = Html.fromHtml(text);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextMenu;
|
||||
import android.widget.EditText;
|
||||
|
||||
import org.solovyev.android.calculator.onscreen.CalculatorOnscreenService;
|
||||
import org.solovyev.common.collections.Collections;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/17/11
|
||||
* Time: 12:25 AM
|
||||
*/
|
||||
public class AndroidCalculatorEditorView extends EditText implements CalculatorEditorView {
|
||||
|
||||
@Nonnull
|
||||
private final Handler uiHandler = new Handler();
|
||||
private volatile boolean initialized = false;
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Nonnull
|
||||
private volatile CalculatorEditorViewState viewState = CalculatorEditorViewStateImpl.newDefaultInstance();
|
||||
private volatile boolean viewStateChange = false;
|
||||
|
||||
public AndroidCalculatorEditorView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public AndroidCalculatorEditorView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public AndroidCalculatorEditorView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCheckIsTextEditor() {
|
||||
// NOTE: code below can be used carefully and should not be copied without special intention
|
||||
// The main purpose of code is to disable soft input (virtual keyboard) but leave all the TextEdit functionality, like cursor, scrolling, copy/paste menu etc
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
// fix for missing cursor in android 3 and higher
|
||||
try {
|
||||
// IDEA: return false always except if method was called from TextView.isCursorVisible() method
|
||||
for (StackTraceElement stackTraceElement : Collections.asList(Thread.currentThread().getStackTrace())) {
|
||||
if ("isCursorVisible".equals(stackTraceElement.getMethodName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
// just in case...
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateContextMenu(ContextMenu menu) {
|
||||
super.onCreateContextMenu(menu);
|
||||
|
||||
menu.removeItem(android.R.id.selectAll);
|
||||
}
|
||||
|
||||
public void setHighlightText(boolean highlightText) {
|
||||
//this.highlightText = highlightText;
|
||||
Locator.getInstance().getEditor().updateViewState();
|
||||
}
|
||||
|
||||
public synchronized void init() {
|
||||
if (!initialized) {
|
||||
this.addTextChangedListener(new TextWatcherImpl());
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(@Nonnull final CalculatorEditorViewState viewState) {
|
||||
synchronized (this) {
|
||||
|
||||
uiHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final AndroidCalculatorEditorView editorView = AndroidCalculatorEditorView.this;
|
||||
synchronized (AndroidCalculatorEditorView.this) {
|
||||
try {
|
||||
editorView.viewStateChange = true;
|
||||
editorView.viewState = viewState;
|
||||
if (App.getTheme().isLight() && getContext() instanceof CalculatorOnscreenService) {
|
||||
// don't need formatting
|
||||
editorView.setText(viewState.getText());
|
||||
} else {
|
||||
editorView.setText(viewState.getTextAsCharSequence(), BufferType.EDITABLE);
|
||||
}
|
||||
final int selection = CalculatorEditorImpl.correctSelection(viewState.getSelection(), editorView.getText());
|
||||
editorView.setSelection(selection);
|
||||
} finally {
|
||||
editorView.viewStateChange = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSelectionChanged(int selStart, int selEnd) {
|
||||
synchronized (this) {
|
||||
if (initialized && !viewStateChange) {
|
||||
// external text change => need to notify editor
|
||||
super.onSelectionChanged(selStart, selEnd);
|
||||
|
||||
if (selStart == selEnd) {
|
||||
// only if cursor moving, if selection do nothing
|
||||
Locator.getInstance().getEditor().setSelection(selStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleTextChange(Editable s) {
|
||||
synchronized (this) {
|
||||
if (initialized && !viewStateChange) {
|
||||
// external text change => need to notify editor
|
||||
Locator.getInstance().getEditor().setText(String.valueOf(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class TextWatcherImpl implements TextWatcher {
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
handleTextChange(s);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 11/18/12
|
||||
* Time: 6:05 PM
|
||||
*/
|
||||
public class AndroidCalculatorKeyboard implements CalculatorKeyboard {
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorKeyboard calculatorKeyboard;
|
||||
|
||||
@Nonnull
|
||||
private final Context context;
|
||||
|
||||
@android.support.annotation.Nullable
|
||||
private org.solovyev.android.calculator.Vibrator vibrator;
|
||||
|
||||
public AndroidCalculatorKeyboard(@Nonnull Application application,
|
||||
@Nonnull CalculatorKeyboard calculatorKeyboard) {
|
||||
this.context = application;
|
||||
this.calculatorKeyboard = calculatorKeyboard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean buttonPressed(@Nullable String text) {
|
||||
App.getGa().onButtonPressed(text);
|
||||
final boolean processed = calculatorKeyboard.buttonPressed(text);
|
||||
if (processed) {
|
||||
vibrate();
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
private void vibrate() {
|
||||
if (vibrator == null) {
|
||||
vibrator = App.getVibrator();
|
||||
}
|
||||
vibrator.vibrate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void roundBracketsButtonPressed() {
|
||||
vibrate();
|
||||
calculatorKeyboard.roundBracketsButtonPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pasteButtonPressed() {
|
||||
vibrate();
|
||||
calculatorKeyboard.pasteButtonPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearButtonPressed() {
|
||||
vibrate();
|
||||
calculatorKeyboard.clearButtonPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyButtonPressed() {
|
||||
vibrate();
|
||||
calculatorKeyboard.copyButtonPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorLeft() {
|
||||
vibrate();
|
||||
calculatorKeyboard.moveCursorLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorRight() {
|
||||
vibrate();
|
||||
calculatorKeyboard.moveCursorRight();
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.util.Log;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/11/12
|
||||
* Time: 12:15 AM
|
||||
*/
|
||||
public class AndroidCalculatorLogger implements CalculatorLogger {
|
||||
|
||||
@Nonnull
|
||||
private static final String TAG = "Calculatorpp";
|
||||
|
||||
@Override
|
||||
public void debug(@Nullable String tag, @Nonnull String message) {
|
||||
Log.d(getTag(tag), message);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private String getTag(@Nullable String tag) {
|
||||
return tag != null ? TAG + "/" + tag : TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) {
|
||||
Log.d(getTag(tag), message, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) {
|
||||
Log.e(getTag(tag), message, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(@Nullable String tag, @Nullable String message) {
|
||||
Log.e(getTag(tag), message);
|
||||
}
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.Application;
|
||||
import android.os.Handler;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.solovyev.android.Threads;
|
||||
import org.solovyev.android.msg.AndroidMessage;
|
||||
import org.solovyev.common.msg.Message;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/22/12
|
||||
* Time: 2:00 PM
|
||||
*/
|
||||
public class AndroidCalculatorNotifier implements CalculatorNotifier {
|
||||
|
||||
@Nonnull
|
||||
private final Application application;
|
||||
|
||||
@Nonnull
|
||||
private final Handler uiHandler = new Handler();
|
||||
|
||||
private final boolean showDebugMessages;
|
||||
|
||||
public AndroidCalculatorNotifier(@Nonnull Application application) {
|
||||
this(application, false);
|
||||
}
|
||||
|
||||
public AndroidCalculatorNotifier(@Nonnull Application application, boolean showDebugMessages) {
|
||||
if (!Threads.isUiThread()) throw new AssertionError();
|
||||
|
||||
this.application = application;
|
||||
this.showDebugMessages = showDebugMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage(@Nonnull Message message) {
|
||||
showMessageInUiThread(message.getLocalizedMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nonnull List<Object> parameters) {
|
||||
showMessage(new AndroidMessage(messageCode, messageType, application, parameters));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters) {
|
||||
showMessage(new AndroidMessage(messageCode, messageType, application, parameters));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDebugMessage(@Nullable final String tag, @Nonnull final String message) {
|
||||
if (showDebugMessages) {
|
||||
showMessageInUiThread(tag == null ? message : tag + ": " + message);
|
||||
}
|
||||
}
|
||||
|
||||
private void showMessageInUiThread(@Nonnull final String message) {
|
||||
if (Threads.isUiThread()) {
|
||||
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
uiHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.Application;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
|
||||
import org.solovyev.android.msg.AndroidMessage;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import jscl.AngleUnit;
|
||||
import jscl.NumeralBase;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 11/17/12
|
||||
* Time: 7:46 PM
|
||||
*/
|
||||
public class AndroidCalculatorPreferenceService implements CalculatorPreferenceService {
|
||||
|
||||
// one hour
|
||||
private static final Long PREFERRED_PREFS_INTERVAL_TIME = 1000L * 60L * 60L;
|
||||
|
||||
@Nonnull
|
||||
private final Application application;
|
||||
|
||||
public AndroidCalculatorPreferenceService(@Nonnull Application application) {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkPreferredPreferences(boolean force) {
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(application);
|
||||
|
||||
final Long currentTime = System.currentTimeMillis();
|
||||
|
||||
if (force || (Preferences.Calculations.showCalculationMessagesDialog.getPreference(prefs) && isTimeForCheck(currentTime, prefs))) {
|
||||
final NumeralBase preferredNumeralBase = Preferences.Calculations.preferredNumeralBase.getPreference(prefs);
|
||||
final NumeralBase numeralBase = AndroidCalculatorEngine.Preferences.numeralBase.getPreference(prefs);
|
||||
|
||||
final AngleUnit preferredAngleUnits = Preferences.Calculations.preferredAngleUnits.getPreference(prefs);
|
||||
final AngleUnit angleUnits = AndroidCalculatorEngine.Preferences.angleUnit.getPreference(prefs);
|
||||
|
||||
final List<FixableMessage> messages = new ArrayList<FixableMessage>(2);
|
||||
if (numeralBase != preferredNumeralBase) {
|
||||
messages.add(new FixableMessage(application.getString(R.string.preferred_numeral_base_message, preferredNumeralBase.name(), numeralBase.name()), MessageType.warning, CalculatorFixableError.preferred_numeral_base));
|
||||
}
|
||||
|
||||
if (angleUnits != preferredAngleUnits) {
|
||||
messages.add(new FixableMessage(application.getString(R.string.preferred_angle_units_message, preferredAngleUnits.name(), angleUnits.name()), MessageType.warning, CalculatorFixableError.preferred_angle_units));
|
||||
}
|
||||
|
||||
FixableMessagesDialog.showDialog(messages, application, true);
|
||||
|
||||
Preferences.Calculations.lastPreferredPreferencesCheck.putPreference(prefs, currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTimeForCheck(@Nonnull Long currentTime, @Nonnull SharedPreferences preferences) {
|
||||
final Long lastPreferredPreferencesCheckTime = Preferences.Calculations.lastPreferredPreferencesCheck.getPreference(preferences);
|
||||
|
||||
return currentTime - lastPreferredPreferencesCheckTime > PREFERRED_PREFS_INTERVAL_TIME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreferredAngleUnits() {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);
|
||||
setAngleUnits(Preferences.Calculations.preferredAngleUnits.getPreference(preferences));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAngleUnits(@Nonnull AngleUnit angleUnit) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);
|
||||
AndroidCalculatorEngine.Preferences.angleUnit.putPreference(preferences, angleUnit);
|
||||
|
||||
Locator.getInstance().getNotifier().showMessage(new AndroidMessage(R.string.c_angle_units_changed_to, MessageType.info, application, angleUnit.name()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreferredNumeralBase() {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);
|
||||
setNumeralBase(Preferences.Calculations.preferredNumeralBase.getPreference(preferences));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNumeralBase(@Nonnull NumeralBase numeralBase) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);
|
||||
AndroidCalculatorEngine.Preferences.numeralBase.putPreference(preferences, numeralBase);
|
||||
|
||||
Locator.getInstance().getNotifier().showMessage(new AndroidMessage(R.string.c_numeral_base_changed_to, MessageType.info, application, numeralBase.name()));
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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: 10/7/12
|
||||
* Time: 7:17 PM
|
||||
*/
|
||||
public enum AndroidFunctionCategory {
|
||||
|
||||
trigonometric(R.string.c_fun_category_trig),
|
||||
hyperbolic_trigonometric(R.string.c_fun_category_hyper_trig),
|
||||
comparison(R.string.c_fun_category_comparison),
|
||||
my(R.string.c_fun_category_my),
|
||||
common(R.string.c_fun_category_common);
|
||||
|
||||
private final int captionId;
|
||||
|
||||
AndroidFunctionCategory(int captionId) {
|
||||
this.captionId = captionId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AndroidFunctionCategory valueOf(@Nonnull FunctionCategory functionCategory) {
|
||||
for (AndroidFunctionCategory androidFunctionCategory : values()) {
|
||||
if (androidFunctionCategory.name().equals(functionCategory.name())) {
|
||||
return androidFunctionCategory;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCaptionId() {
|
||||
return captionId;
|
||||
}
|
||||
}
|
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
|
||||
import org.solovyev.android.views.dragbutton.DirectionDragButton;
|
||||
import org.solovyev.android.views.dragbutton.DragDirection;
|
||||
import org.solovyev.android.calculator.units.CalculatorNumeralBase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import jscl.NumeralBase;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 4/21/12
|
||||
* Time: 8:00 PM
|
||||
*/
|
||||
public enum AndroidNumeralBase {
|
||||
|
||||
bin(CalculatorNumeralBase.bin) {
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Integer> getButtonIds() {
|
||||
return Arrays.asList(R.id.cpp_button_0, R.id.cpp_button_1);
|
||||
}
|
||||
},
|
||||
|
||||
oct(CalculatorNumeralBase.oct) {
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Integer> getButtonIds() {
|
||||
final List<Integer> result = new ArrayList<Integer>(bin.getButtonIds());
|
||||
result.addAll(Arrays.asList(R.id.cpp_button_2, R.id.cpp_button_3, R.id.cpp_button_4, R.id.cpp_button_5, R.id.cpp_button_6, R.id.cpp_button_7));
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
dec(CalculatorNumeralBase.dec) {
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Integer> getButtonIds() {
|
||||
final List<Integer> result = new ArrayList<Integer>(oct.getButtonIds());
|
||||
result.addAll(Arrays.asList(R.id.cpp_button_8, R.id.cpp_button_9));
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
hex(CalculatorNumeralBase.hex) {
|
||||
|
||||
@Nonnull
|
||||
private List<Integer> specialHexButtonIds = Arrays.asList(R.id.cpp_button_1, R.id.cpp_button_2, R.id.cpp_button_3, R.id.cpp_button_4, R.id.cpp_button_5, R.id.cpp_button_6);
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Integer> getButtonIds() {
|
||||
return dec.getButtonIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toggleButton(boolean show, @Nonnull DirectionDragButton button) {
|
||||
super.toggleButton(show, button);
|
||||
if (specialHexButtonIds.contains(button.getId())) {
|
||||
button.showDirectionText(show, DragDirection.left);
|
||||
button.invalidate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorNumeralBase calculatorNumeralBase;
|
||||
|
||||
private AndroidNumeralBase(@Nonnull CalculatorNumeralBase calculatorNumeralBase) {
|
||||
this.calculatorNumeralBase = calculatorNumeralBase;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static AndroidNumeralBase valueOf(@Nonnull NumeralBase nb) {
|
||||
for (AndroidNumeralBase androidNumeralBase : values()) {
|
||||
if (androidNumeralBase.calculatorNumeralBase.getNumeralBase() == nb) {
|
||||
return androidNumeralBase;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(nb + " is not supported numeral base!");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public abstract List<Integer> getButtonIds();
|
||||
|
||||
public void toggleButtons(boolean show, @Nonnull Activity activity) {
|
||||
for (Integer buttonId : getButtonIds()) {
|
||||
final DirectionDragButton button = (DirectionDragButton) activity.findViewById(buttonId);
|
||||
if (button != null) {
|
||||
toggleButton(show, button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void toggleButton(boolean show, @Nonnull DirectionDragButton button) {
|
||||
button.setShowText(show);
|
||||
button.invalidate();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public NumeralBase getNumeralBase() {
|
||||
return calculatorNumeralBase.getNumeralBase();
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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: 10/7/12
|
||||
* Time: 7:41 PM
|
||||
*/
|
||||
public enum AndroidOperatorCategory {
|
||||
|
||||
derivatives(R.string.derivatives),
|
||||
other(R.string.other),
|
||||
my(R.string.c_fun_category_my),
|
||||
common(R.string.c_fun_category_common);
|
||||
|
||||
private final int captionId;
|
||||
|
||||
AndroidOperatorCategory(int captionId) {
|
||||
this.captionId = captionId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AndroidOperatorCategory valueOf(@Nonnull OperatorCategory operatorCategory) {
|
||||
for (AndroidOperatorCategory androidOperatorCategory : values()) {
|
||||
if (androidOperatorCategory.name().equals(operatorCategory.name())) {
|
||||
return androidOperatorCategory;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCaptionId() {
|
||||
return captionId;
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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: 10/7/12
|
||||
* Time: 7:56 PM
|
||||
*/
|
||||
public enum AndroidVarCategory {
|
||||
|
||||
system(R.string.c_var_system),
|
||||
my(R.string.c_var_my);
|
||||
|
||||
private final int captionId;
|
||||
|
||||
AndroidVarCategory(int captionId) {
|
||||
this.captionId = captionId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AndroidVarCategory valueOf(@Nonnull VarCategory varCategory) {
|
||||
for (AndroidVarCategory androidVarCategory : values()) {
|
||||
if (androidVarCategory.name().equals(varCategory.name())) {
|
||||
return androidVarCategory;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCaptionId() {
|
||||
return captionId;
|
||||
}
|
||||
}
|
342
app/src/main/java/org/solovyev/android/calculator/App.java
Normal file
342
app/src/main/java/org/solovyev/android/calculator/App.java
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* 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.Application;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
|
||||
import org.solovyev.android.Android;
|
||||
import org.solovyev.android.UiThreadExecutor;
|
||||
import org.solovyev.android.Views;
|
||||
import org.solovyev.android.calculator.ga.Ga;
|
||||
import org.solovyev.android.calculator.language.Languages;
|
||||
import org.solovyev.android.calculator.onscreen.CalculatorOnscreenService;
|
||||
import org.solovyev.android.calculator.view.ScreenMetrics;
|
||||
import org.solovyev.android.calculator.widget.BaseCalculatorWidgetProvider;
|
||||
import org.solovyev.android.calculator.widget.CalculatorWidgetProvider;
|
||||
import org.solovyev.android.calculator.widget.CalculatorWidgetProvider3x4;
|
||||
import org.solovyev.android.calculator.widget.CalculatorWidgetProvider4x4;
|
||||
import org.solovyev.android.calculator.widget.CalculatorWidgetProvider4x5;
|
||||
import org.solovyev.android.checkout.Billing;
|
||||
import org.solovyev.android.checkout.Checkout;
|
||||
import org.solovyev.android.checkout.Inventory;
|
||||
import org.solovyev.android.checkout.ProductTypes;
|
||||
import org.solovyev.android.checkout.Products;
|
||||
import org.solovyev.android.checkout.RobotmediaDatabase;
|
||||
import org.solovyev.android.checkout.RobotmediaInventory;
|
||||
import org.solovyev.android.plotter.Plot;
|
||||
import org.solovyev.android.plotter.Plotter;
|
||||
import org.solovyev.common.listeners.JEvent;
|
||||
import org.solovyev.common.listeners.JEventListener;
|
||||
import org.solovyev.common.listeners.JEventListeners;
|
||||
import org.solovyev.common.listeners.Listeners;
|
||||
import org.solovyev.common.threads.DelayedExecutor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 12/1/12
|
||||
* Time: 3:58 PM
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class aggregates several useful in any Android application interfaces and provides access to {@link android.app.Application} object from a static context.
|
||||
* NOTE: use this class only if you don't use and dependency injection library (if you use any you can directly set interfaces through it). <br/>
|
||||
* <p/>
|
||||
* Before first usage this class must be initialized by calling {@link App#init(android.app.Application)} method (for example, from {@link android.app.Application#onCreate()})
|
||||
*/
|
||||
public final class App {
|
||||
@Nonnull
|
||||
private static final List<Class<? extends BaseCalculatorWidgetProvider>> OLD_WIDGETS = Arrays.asList(CalculatorWidgetProvider.class, CalculatorWidgetProvider3x4.class, CalculatorWidgetProvider4x4.class, CalculatorWidgetProvider4x5.class);
|
||||
@Nonnull
|
||||
private static final Products products = Products.create().add(ProductTypes.IN_APP, Arrays.asList("ad_free"));
|
||||
@Nonnull
|
||||
private static final Languages languages = new Languages();
|
||||
@Nonnull
|
||||
private static volatile Application application;
|
||||
@Nonnull
|
||||
private static volatile DelayedExecutor uiThreadExecutor;
|
||||
@Nonnull
|
||||
private static volatile JEventListeners<JEventListener<? extends JEvent>, JEvent> eventBus;
|
||||
private static volatile boolean initialized;
|
||||
@Nonnull
|
||||
private static CalculatorBroadcaster broadcaster;
|
||||
@Nonnull
|
||||
private static SharedPreferences preferences;
|
||||
@Nonnull
|
||||
private static volatile Ga ga;
|
||||
@Nonnull
|
||||
private static volatile Billing billing;
|
||||
@Nullable
|
||||
private static Boolean lg = null;
|
||||
@Nonnull
|
||||
private static volatile Vibrator vibrator;
|
||||
@Nonnull
|
||||
private static volatile ScreenMetrics screenMetrics;
|
||||
@Nonnull
|
||||
private static volatile Plotter plotter;
|
||||
|
||||
private App() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* METHODS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
public static void init(@Nonnull Application application) {
|
||||
init(application, new UiThreadExecutor(), Listeners.newEventBus());
|
||||
}
|
||||
|
||||
public static void init(@Nonnull Application application,
|
||||
@Nonnull UiThreadExecutor uiThreadExecutor,
|
||||
@Nonnull JEventListeners<JEventListener<? extends JEvent>, JEvent> eventBus) {
|
||||
if (!initialized) {
|
||||
App.application = application;
|
||||
App.preferences = PreferenceManager.getDefaultSharedPreferences(application);
|
||||
App.uiThreadExecutor = uiThreadExecutor;
|
||||
App.eventBus = eventBus;
|
||||
App.ga = new Ga(application, preferences, eventBus);
|
||||
App.billing = new Billing(application, new Billing.DefaultConfiguration() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getPublicKey() {
|
||||
return CalculatorSecurity.getPK();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Inventory getFallbackInventory(@Nonnull Checkout checkout, @Nonnull Executor onLoadExecutor) {
|
||||
if (RobotmediaDatabase.exists(billing.getContext())) {
|
||||
return new RobotmediaInventory(checkout, onLoadExecutor);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
App.broadcaster = new CalculatorBroadcaster(application, preferences);
|
||||
App.vibrator = new Vibrator(application, preferences);
|
||||
App.screenMetrics = new ScreenMetrics(application);
|
||||
|
||||
final List<Class<? extends AppWidgetProvider>> oldNotUsedWidgetClasses = findNotUsedWidgets(application);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
|
||||
for (Class<? extends AppWidgetProvider> oldNotUsedWidgetClass : oldNotUsedWidgetClasses) {
|
||||
Android.enableComponent(application, oldNotUsedWidgetClass, false);
|
||||
}
|
||||
} else {
|
||||
// smaller widgets should be still used for smaller screens
|
||||
if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x5.class)) {
|
||||
Android.enableComponent(application, CalculatorWidgetProvider4x5.class, false);
|
||||
}
|
||||
if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x4.class)) {
|
||||
Android.enableComponent(application, CalculatorWidgetProvider4x4.class, false);
|
||||
}
|
||||
}
|
||||
App.languages.init(App.preferences);
|
||||
App.plotter = Plot.newPlotter(application);
|
||||
|
||||
App.initialized = true;
|
||||
} else {
|
||||
throw new IllegalStateException("Already initialized!");
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static List<Class<? extends AppWidgetProvider>> findNotUsedWidgets(@Nonnull Application application) {
|
||||
final List<Class<? extends AppWidgetProvider>> result = new ArrayList<>();
|
||||
|
||||
final AppWidgetManager widgetManager = AppWidgetManager.getInstance(application);
|
||||
for (Class<? extends AppWidgetProvider> widgetClass : OLD_WIDGETS) {
|
||||
final int ids[] = widgetManager.getAppWidgetIds(new ComponentName(application, widgetClass));
|
||||
if (ids == null || ids.length == 0) {
|
||||
result.add(widgetClass);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void checkInit() {
|
||||
if (!initialized) {
|
||||
throw new IllegalStateException("App should be initialized!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if App has already been initialized, false otherwise
|
||||
*/
|
||||
public static boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <A> real type of application
|
||||
* @return application instance which was provided in {@link App#init(android.app.Application)} method
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nonnull
|
||||
public static <A extends Application> A getApplication() {
|
||||
checkInit();
|
||||
return (A) application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method returns executor which runs on Main Application's thread. It's safe to do all UI work on this executor
|
||||
*
|
||||
* @return UI thread executor
|
||||
*/
|
||||
@Nonnull
|
||||
public static DelayedExecutor getUiThreadExecutor() {
|
||||
checkInit();
|
||||
return uiThreadExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return application's event bus
|
||||
*/
|
||||
@Nonnull
|
||||
public static JEventListeners<JEventListener<? extends JEvent>, JEvent> getEventBus() {
|
||||
checkInit();
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorBroadcaster getBroadcaster() {
|
||||
return broadcaster;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Ga getGa() {
|
||||
return ga;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Billing getBilling() {
|
||||
return billing;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Products getProducts() {
|
||||
return products;
|
||||
}
|
||||
|
||||
public static boolean isLargeScreen() {
|
||||
return Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE, App.getApplication().getResources().getConfiguration());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static SharedPreferences getPreferences() {
|
||||
return preferences;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Preferences.Gui.Theme getTheme() {
|
||||
return Preferences.Gui.getTheme(getPreferences());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Preferences.SimpleTheme getWidgetTheme() {
|
||||
return Preferences.Widget.getTheme(getPreferences());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Preferences.Gui.Theme getThemeIn(@Nonnull Context context) {
|
||||
if (context instanceof CalculatorOnscreenService) {
|
||||
final SharedPreferences p = getPreferences();
|
||||
final Preferences.SimpleTheme onscreenTheme = Preferences.Onscreen.getTheme(p);
|
||||
final Preferences.Gui.Theme appTheme = Preferences.Gui.getTheme(p);
|
||||
return onscreenTheme.resolveThemeFor(appTheme).getAppTheme();
|
||||
} else {
|
||||
return App.getTheme();
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Languages getLanguages() {
|
||||
return languages;
|
||||
}
|
||||
|
||||
public static boolean isLg() {
|
||||
if (lg == null) {
|
||||
lg = "lge".equalsIgnoreCase(Build.BRAND) || "lge".equalsIgnoreCase(Build.MANUFACTURER);
|
||||
}
|
||||
return lg;
|
||||
}
|
||||
|
||||
// see https://code.google.com/p/android/issues/detail?id=78154
|
||||
// and http://developer.lge.com/community/forums/RetrieveForumContent.dev?detailContsId=FC29190703
|
||||
public static boolean shouldOpenMenuManually() {
|
||||
return isLg() && Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Vibrator getVibrator() {
|
||||
return vibrator;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ScreenMetrics getScreenMetrics() {
|
||||
return screenMetrics;
|
||||
}
|
||||
|
||||
public static void showDialog(@Nonnull DialogFragment dialogFragment,
|
||||
@Nonnull String fragmentTag,
|
||||
@Nonnull FragmentManager fm) {
|
||||
final FragmentTransaction ft = fm.beginTransaction();
|
||||
|
||||
Fragment prev = fm.findFragmentByTag(fragmentTag);
|
||||
if (prev != null) {
|
||||
ft.remove(prev);
|
||||
}
|
||||
|
||||
// Create and show the dialog.
|
||||
dialogFragment.show(ft, fragmentTag);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Plotter getPlotter() {
|
||||
return plotter;
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class BaseActivity extends ActionBarActivity {
|
||||
|
||||
@Nonnull
|
||||
protected final ActivityUi ui;
|
||||
|
||||
public BaseActivity(@Nonnull ActivityUi ui) {
|
||||
this.ui = ui;
|
||||
}
|
||||
|
||||
public BaseActivity(@LayoutRes int layout) {
|
||||
this(layout, "Activity");
|
||||
}
|
||||
|
||||
public BaseActivity(@LayoutRes int layout, @Nonnull String logTag) {
|
||||
this.ui = new ActivityUi(layout, logTag);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public ActivityUi getUi() {
|
||||
return ui;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
ui.onPreCreate(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
ui.onCreate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
ui.onSaveInstanceState(this, outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
ui.onStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
ui.onStop(this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (App.shouldOpenMenuManually() && keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
openOptionsMenu();
|
||||
return true;
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
ui.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
this.ui.onPause(this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
ui.onDestroy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
323
app/src/main/java/org/solovyev/android/calculator/BaseUi.java
Normal file
323
app/src/main/java/org/solovyev/android/calculator/BaseUi.java
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Typeface;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.solovyev.android.Views;
|
||||
import org.solovyev.android.views.dragbutton.DirectionDragButton;
|
||||
import org.solovyev.android.views.dragbutton.DragButton;
|
||||
import org.solovyev.android.views.dragbutton.DragDirection;
|
||||
import org.solovyev.android.views.dragbutton.DragListener;
|
||||
import org.solovyev.android.views.dragbutton.SimpleDragListener;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistoryState;
|
||||
import org.solovyev.android.calculator.history.HistoryDragProcessor;
|
||||
import org.solovyev.android.calculator.view.AngleUnitsButton;
|
||||
import org.solovyev.android.calculator.view.LongClickEraser;
|
||||
import org.solovyev.android.calculator.view.NumeralBasesButton;
|
||||
import org.solovyev.android.calculator.view.ViewsCache;
|
||||
import org.solovyev.common.math.Point2d;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple;
|
||||
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile;
|
||||
import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.angleUnit;
|
||||
import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.numeralBase;
|
||||
|
||||
public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
@Nonnull
|
||||
private static final List<Integer> viewIds = new ArrayList<>(200);
|
||||
|
||||
@Nonnull
|
||||
protected Preferences.Gui.Layout layout;
|
||||
|
||||
@Nonnull
|
||||
protected Preferences.Gui.Theme theme;
|
||||
|
||||
@Nonnull
|
||||
private String logTag = "CalculatorActivity";
|
||||
|
||||
@Nullable
|
||||
private AngleUnitsButton angleUnitsButton;
|
||||
|
||||
@Nullable
|
||||
private NumeralBasesButton clearButton;
|
||||
|
||||
protected BaseUi() {
|
||||
}
|
||||
|
||||
protected BaseUi(@Nonnull String logTag) {
|
||||
this.logTag = logTag;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static List<Integer> getViewIds() {
|
||||
if (viewIds.isEmpty()) {
|
||||
viewIds.add(R.id.wizard_dragbutton);
|
||||
viewIds.add(R.id.cpp_button_vars);
|
||||
viewIds.add(R.id.cpp_button_round_brackets);
|
||||
viewIds.add(R.id.cpp_button_right);
|
||||
viewIds.add(R.id.cpp_button_plus);
|
||||
viewIds.add(R.id.cpp_button_operators);
|
||||
viewIds.add(R.id.cpp_button_multiplication);
|
||||
viewIds.add(R.id.cpp_button_subtraction);
|
||||
viewIds.add(R.id.cpp_button_left);
|
||||
viewIds.add(R.id.cpp_button_history);
|
||||
viewIds.add(R.id.cpp_button_functions);
|
||||
viewIds.add(R.id.cpp_button_equals);
|
||||
viewIds.add(R.id.cpp_button_period);
|
||||
viewIds.add(R.id.cpp_button_division);
|
||||
viewIds.add(R.id.cpp_button_9);
|
||||
viewIds.add(R.id.cpp_button_8);
|
||||
viewIds.add(R.id.cpp_button_7);
|
||||
viewIds.add(R.id.cpp_button_6);
|
||||
viewIds.add(R.id.cpp_button_5);
|
||||
viewIds.add(R.id.cpp_button_4);
|
||||
viewIds.add(R.id.cpp_button_3);
|
||||
viewIds.add(R.id.cpp_button_2);
|
||||
viewIds.add(R.id.cpp_button_1);
|
||||
viewIds.add(R.id.cpp_button_0);
|
||||
viewIds.add(R.id.cpp_button_clear);
|
||||
}
|
||||
return viewIds;
|
||||
}
|
||||
|
||||
protected void onCreate(@Nonnull Activity activity) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
|
||||
layout = Preferences.Gui.layout.getPreferenceNoError(preferences);
|
||||
theme = Preferences.Gui.theme.getPreferenceNoError(preferences);
|
||||
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
// let's disable locking of screen for monkeyrunner
|
||||
if (CalculatorApplication.isMonkeyRunner(activity)) {
|
||||
final KeyguardManager km = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
|
||||
//noinspection deprecation
|
||||
km.newKeyguardLock(activity.getClass().getName()).disableKeyguard();
|
||||
}
|
||||
}
|
||||
|
||||
public void logError(@Nonnull String message) {
|
||||
Log.e(logTag, message);
|
||||
}
|
||||
|
||||
public void onDestroy(@Nonnull Activity activity) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
|
||||
preferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
protected void fixFonts(@Nonnull View root) {
|
||||
// some devices ship own fonts which causes issues with rendering. Let's use our own font for all text views
|
||||
final Typeface typeFace = CalculatorApplication.getInstance().getTypeFace();
|
||||
Views.processViewsOfType(root, TextView.class, new Views.ViewProcessor<TextView>() {
|
||||
@Override
|
||||
public void process(@Nonnull TextView view) {
|
||||
int style = Typeface.NORMAL;
|
||||
final Typeface oldTypeface = view.getTypeface();
|
||||
if (oldTypeface != null) {
|
||||
style = oldTypeface.getStyle();
|
||||
}
|
||||
view.setTypeface(typeFace, style);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void processButtons(@Nonnull final Activity activity, @Nonnull View root) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
|
||||
final ViewsCache views = ViewsCache.forView(root);
|
||||
setOnDragListeners(views, activity);
|
||||
|
||||
HistoryDragProcessor<CalculatorHistoryState> historyDragProcessor = new HistoryDragProcessor<>(getCalculator());
|
||||
final DragListener historyDragListener = newDragListener(historyDragProcessor, activity);
|
||||
final DragButton historyButton = getButton(views, R.id.cpp_button_history);
|
||||
if (historyButton != null) {
|
||||
historyButton.setOnDragListener(historyDragListener);
|
||||
}
|
||||
|
||||
final DragButton minusButton = getButton(views, R.id.cpp_button_subtraction);
|
||||
if (minusButton != null) {
|
||||
minusButton.setOnDragListener(newDragListener(new OperatorsDragProcessor(), activity));
|
||||
}
|
||||
|
||||
final DragListener toPositionDragListener = new SimpleDragListener(new CursorDragProcessor(), activity);
|
||||
|
||||
final DragButton rightButton = getButton(views, R.id.cpp_button_right);
|
||||
if (rightButton != null) {
|
||||
rightButton.setOnDragListener(toPositionDragListener);
|
||||
}
|
||||
|
||||
final DragButton leftButton = getButton(views, R.id.cpp_button_left);
|
||||
if (leftButton != null) {
|
||||
leftButton.setOnDragListener(toPositionDragListener);
|
||||
}
|
||||
|
||||
final DragButton equalsButton = getButton(views, R.id.cpp_button_equals);
|
||||
if (equalsButton != null) {
|
||||
equalsButton.setOnDragListener(newDragListener(new EqualsDragProcessor(), activity));
|
||||
}
|
||||
|
||||
angleUnitsButton = getButton(views, R.id.cpp_button_6);
|
||||
if (angleUnitsButton != null) {
|
||||
angleUnitsButton.setOnDragListener(newDragListener(new CalculatorButtons.AngleUnitsChanger(activity), activity));
|
||||
}
|
||||
|
||||
final View eraseButton = getButton(views, R.id.cpp_button_erase);
|
||||
if (eraseButton != null) {
|
||||
LongClickEraser.createAndAttach(eraseButton);
|
||||
}
|
||||
|
||||
clearButton = getButton(views, R.id.cpp_button_clear);
|
||||
if (clearButton != null) {
|
||||
clearButton.setOnDragListener(newDragListener(new CalculatorButtons.NumeralBasesChanger(activity), activity));
|
||||
}
|
||||
|
||||
final DragButton varsButton = getButton(views, R.id.cpp_button_vars);
|
||||
if (varsButton != null) {
|
||||
varsButton.setOnDragListener(newDragListener(new CalculatorButtons.VarsDragProcessor(activity), activity));
|
||||
}
|
||||
|
||||
final DragButton functionsButton = getButton(views, R.id.cpp_button_functions);
|
||||
if (functionsButton != null) {
|
||||
functionsButton.setOnDragListener(newDragListener(new CalculatorButtons.FunctionsDragProcessor(activity), activity));
|
||||
}
|
||||
|
||||
final DragButton roundBracketsButton = getButton(views, R.id.cpp_button_round_brackets);
|
||||
if (roundBracketsButton != null) {
|
||||
roundBracketsButton.setOnDragListener(newDragListener(new CalculatorButtons.RoundBracketsDragProcessor(), activity));
|
||||
}
|
||||
|
||||
if (layout == simple || layout == simple_mobile) {
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_1, false, DragDirection.up, DragDirection.down);
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_2, false, DragDirection.up, DragDirection.down);
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_3, false, DragDirection.up, DragDirection.down);
|
||||
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_6, false, DragDirection.up, DragDirection.down);
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_7, false, DragDirection.left, DragDirection.up, DragDirection.down);
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_8, false, DragDirection.left, DragDirection.up, DragDirection.down);
|
||||
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_clear, false, DragDirection.left, DragDirection.up, DragDirection.down);
|
||||
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_4, false, DragDirection.down);
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_5, false, DragDirection.down);
|
||||
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_9, false, DragDirection.left);
|
||||
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_multiplication, false, DragDirection.left);
|
||||
toggleButtonDirectionText(views, R.id.cpp_button_plus, false, DragDirection.down, DragDirection.up);
|
||||
}
|
||||
|
||||
CalculatorButtons.fixButtonsTextSize(theme, layout, root);
|
||||
CalculatorButtons.toggleEqualsButton(preferences, activity);
|
||||
CalculatorButtons.initMultiplicationButton(root);
|
||||
NumeralBaseButtons.toggleNumericDigits(activity, preferences);
|
||||
|
||||
new ButtonOnClickListener().attachToViews(views);
|
||||
}
|
||||
|
||||
private void setOnDragListeners(@Nonnull ViewsCache views, @Nonnull Context context) {
|
||||
final DragListener dragListener = newDragListener(new DigitButtonDragProcessor(getKeyboard()), context);
|
||||
|
||||
final List<Integer> viewIds = getViewIds();
|
||||
for (Integer viewId : viewIds) {
|
||||
final View view = views.findViewById(viewId);
|
||||
if (view instanceof DragButton) {
|
||||
((DragButton) view).setOnDragListener(dragListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private SimpleDragListener newDragListener(@Nonnull SimpleDragListener.DragProcessor dragProcessor, @Nonnull Context context) {
|
||||
return new SimpleDragListener(dragProcessor, context);
|
||||
}
|
||||
|
||||
private void toggleButtonDirectionText(@Nonnull ViewsCache views, int id, boolean showDirectionText, @Nonnull DragDirection... dragDirections) {
|
||||
final View v = getButton(views, id);
|
||||
if (v instanceof DirectionDragButton) {
|
||||
final DirectionDragButton button = (DirectionDragButton) v;
|
||||
for (DragDirection dragDirection : dragDirections) {
|
||||
button.showDirectionText(showDirectionText, dragDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Calculator getCalculator() {
|
||||
return Locator.getInstance().getCalculator();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private CalculatorKeyboard getKeyboard() {
|
||||
return Locator.getInstance().getKeyboard();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <V extends View> V getButton(@Nonnull ViewsCache views, int buttonId) {
|
||||
//noinspection unchecked
|
||||
return (V) views.findViewById(buttonId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||
if (angleUnit.isSameKey(key) || numeralBase.isSameKey(key)) {
|
||||
if (angleUnitsButton != null) {
|
||||
angleUnitsButton.setAngleUnit(angleUnit.getPreference(preferences));
|
||||
}
|
||||
|
||||
if (clearButton != null) {
|
||||
clearButton.setNumeralBase(numeralBase.getPreference(preferences));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class OperatorsDragProcessor implements SimpleDragListener.DragProcessor {
|
||||
@Override
|
||||
public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull PointF startPoint, @Nonnull MotionEvent motionEvent) {
|
||||
if (dragDirection == DragDirection.down) {
|
||||
App.getVibrator().vibrate();
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_operators, null);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,114 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.support.annotation.IdRes;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.solovyev.android.calculator.view.ViewsCache;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
final class ButtonOnClickListener implements View.OnClickListener {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.cpp_button_0:
|
||||
case R.id.cpp_button_1:
|
||||
case R.id.cpp_button_2:
|
||||
case R.id.cpp_button_3:
|
||||
case R.id.cpp_button_4:
|
||||
case R.id.cpp_button_5:
|
||||
case R.id.cpp_button_6:
|
||||
case R.id.cpp_button_7:
|
||||
case R.id.cpp_button_8:
|
||||
case R.id.cpp_button_9:
|
||||
case R.id.cpp_button_division:
|
||||
case R.id.cpp_button_period:
|
||||
case R.id.cpp_button_left:
|
||||
case R.id.cpp_button_subtraction:
|
||||
case R.id.cpp_button_multiplication:
|
||||
case R.id.cpp_button_plus:
|
||||
case R.id.cpp_button_right:
|
||||
case R.id.cpp_button_round_brackets:
|
||||
onClick(((Button) v).getText().toString());
|
||||
break;
|
||||
case R.id.cpp_button_clear:
|
||||
onClick(CalculatorSpecialButton.clear);
|
||||
break;
|
||||
case R.id.cpp_button_functions:
|
||||
onClick(CalculatorSpecialButton.functions);
|
||||
break;
|
||||
case R.id.cpp_button_history:
|
||||
onClick(CalculatorSpecialButton.history);
|
||||
break;
|
||||
case R.id.cpp_button_erase:
|
||||
onClick(CalculatorSpecialButton.erase);
|
||||
break;
|
||||
case R.id.cpp_button_paste:
|
||||
onClick(CalculatorSpecialButton.paste);
|
||||
break;
|
||||
case R.id.cpp_button_copy:
|
||||
onClick(CalculatorSpecialButton.copy);
|
||||
break;
|
||||
case R.id.cpp_button_like:
|
||||
onClick(CalculatorSpecialButton.like);
|
||||
break;
|
||||
case R.id.cpp_button_operators:
|
||||
onClick(CalculatorSpecialButton.operators);
|
||||
break;
|
||||
case R.id.cpp_button_vars:
|
||||
onClick(CalculatorSpecialButton.vars);
|
||||
break;
|
||||
case R.id.cpp_button_equals:
|
||||
onClick(CalculatorSpecialButton.equals);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onClick(@Nonnull CalculatorSpecialButton b) {
|
||||
onClick(b.getActionCode());
|
||||
}
|
||||
|
||||
private void onClick(@Nonnull String s) {
|
||||
Locator.getInstance().getKeyboard().buttonPressed(s);
|
||||
}
|
||||
|
||||
public void attachToViews(@Nonnull ViewsCache views) {
|
||||
attachToView(views, R.id.cpp_button_0);
|
||||
attachToView(views, R.id.cpp_button_1);
|
||||
attachToView(views, R.id.cpp_button_2);
|
||||
attachToView(views, R.id.cpp_button_3);
|
||||
attachToView(views, R.id.cpp_button_4);
|
||||
attachToView(views, R.id.cpp_button_5);
|
||||
attachToView(views, R.id.cpp_button_6);
|
||||
attachToView(views, R.id.cpp_button_7);
|
||||
attachToView(views, R.id.cpp_button_8);
|
||||
attachToView(views, R.id.cpp_button_9);
|
||||
attachToView(views, R.id.cpp_button_division);
|
||||
attachToView(views, R.id.cpp_button_period);
|
||||
attachToView(views, R.id.cpp_button_left);
|
||||
attachToView(views, R.id.cpp_button_subtraction);
|
||||
attachToView(views, R.id.cpp_button_multiplication);
|
||||
attachToView(views, R.id.cpp_button_plus);
|
||||
attachToView(views, R.id.cpp_button_right);
|
||||
attachToView(views, R.id.cpp_button_round_brackets);
|
||||
attachToView(views, R.id.cpp_button_clear);
|
||||
attachToView(views, R.id.cpp_button_functions);
|
||||
attachToView(views, R.id.cpp_button_history);
|
||||
attachToView(views, R.id.cpp_button_erase);
|
||||
attachToView(views, R.id.cpp_button_paste);
|
||||
attachToView(views, R.id.cpp_button_copy);
|
||||
attachToView(views, R.id.cpp_button_like);
|
||||
attachToView(views, R.id.cpp_button_operators);
|
||||
attachToView(views, R.id.cpp_button_vars);
|
||||
attachToView(views, R.id.cpp_button_equals);
|
||||
}
|
||||
|
||||
private void attachToView(@Nonnull ViewsCache views, @IdRes int viewId) {
|
||||
final View view = views.findViewById(viewId);
|
||||
if (view != null) {
|
||||
view.setOnClickListener(this);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.history.CalculatorHistoryState;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
import org.solovyev.common.history.HistoryControl;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.NumeralBase;
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 16:38
|
||||
*/
|
||||
public interface Calculator extends CalculatorEventContainer, HistoryControl<CalculatorHistoryState> {
|
||||
|
||||
void init();
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CALCULATIONS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
void evaluate();
|
||||
|
||||
void evaluate(@Nonnull Long sequenceId);
|
||||
|
||||
void simplify();
|
||||
|
||||
@Nonnull
|
||||
CalculatorEventData evaluate(@Nonnull JsclOperation operation,
|
||||
@Nonnull String expression);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEventData evaluate(@Nonnull JsclOperation operation,
|
||||
@Nonnull String expression,
|
||||
@Nonnull Long sequenceId);
|
||||
|
||||
boolean isCalculateOnFly();
|
||||
|
||||
void setCalculateOnFly(boolean calculateOnFly);
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONVERSION
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
boolean isConversionPossible(@Nonnull Generic generic, @Nonnull NumeralBase from, @Nonnull NumeralBase to);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEventData convert(@Nonnull Generic generic, @Nonnull NumeralBase to);
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* EVENTS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
@Nonnull
|
||||
CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data, @Nonnull Object source);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data, @Nonnull Long sequenceId);
|
||||
|
||||
@Nonnull
|
||||
PreparedExpression prepareExpression(@Nonnull String expression) throws CalculatorParseException;
|
||||
}
|
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* 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.annotation.TargetApi;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.solovyev.android.Activities;
|
||||
import org.solovyev.android.Android;
|
||||
import org.solovyev.android.Threads;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotActivity;
|
||||
import org.solovyev.android.calculator.wizard.CalculatorWizards;
|
||||
import org.solovyev.android.fragments.FragmentUtils;
|
||||
import org.solovyev.android.prefs.Preference;
|
||||
import org.solovyev.android.wizard.Wizard;
|
||||
import org.solovyev.android.wizard.Wizards;
|
||||
import org.solovyev.common.Objects;
|
||||
import org.solovyev.common.history.HistoryAction;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static android.os.Build.VERSION_CODES.GINGERBREAD_MR1;
|
||||
import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
|
||||
import static org.solovyev.android.calculator.Preferences.Gui.preventScreenFromFading;
|
||||
import static org.solovyev.android.calculator.release.ReleaseNotes.hasReleaseNotes;
|
||||
import static org.solovyev.android.wizard.WizardUi.continueWizard;
|
||||
import static org.solovyev.android.wizard.WizardUi.createLaunchIntent;
|
||||
import static org.solovyev.android.wizard.WizardUi.startWizard;
|
||||
|
||||
public class CalculatorActivity extends BaseActivity implements SharedPreferences.OnSharedPreferenceChangeListener, CalculatorEventListener {
|
||||
|
||||
@Nonnull
|
||||
public static final String TAG = CalculatorActivity.class.getSimpleName();
|
||||
|
||||
private boolean useBackAsPrev;
|
||||
|
||||
public CalculatorActivity() {
|
||||
super(0, TAG);
|
||||
}
|
||||
|
||||
private static void firstTimeInit(@Nonnull SharedPreferences preferences, @Nonnull Context context) {
|
||||
final Integer appOpenedCounter = Preferences.appOpenedCounter.getPreference(preferences);
|
||||
if (appOpenedCounter != null) {
|
||||
Preferences.appOpenedCounter.putPreference(preferences, appOpenedCounter + 1);
|
||||
}
|
||||
|
||||
final Integer savedVersion = Preferences.appVersion.getPreference(preferences);
|
||||
|
||||
final int appVersion = Android.getAppVersionCode(context);
|
||||
|
||||
Preferences.appVersion.putPreference(preferences, appVersion);
|
||||
|
||||
if (!CalculatorApplication.isMonkeyRunner(context)) {
|
||||
|
||||
boolean dialogShown = false;
|
||||
final Wizards wizards = CalculatorApplication.getInstance().getWizards();
|
||||
final Wizard wizard = wizards.getWizard(CalculatorWizards.FIRST_TIME_WIZARD);
|
||||
if (wizard.isStarted() && !wizard.isFinished()) {
|
||||
continueWizard(wizards, wizard.getName(), context);
|
||||
dialogShown = true;
|
||||
} else {
|
||||
if (Objects.areEqual(savedVersion, Preferences.appVersion.getDefaultValue())) {
|
||||
// new start
|
||||
startWizard(wizards, context);
|
||||
dialogShown = true;
|
||||
} else {
|
||||
if (savedVersion < appVersion) {
|
||||
final boolean showReleaseNotes = Preferences.Gui.showReleaseNotes.getPreference(preferences);
|
||||
if (showReleaseNotes && hasReleaseNotes(context, savedVersion + 1)) {
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putInt(CalculatorWizards.RELEASE_NOTES_VERSION, savedVersion);
|
||||
context.startActivity(createLaunchIntent(wizards, CalculatorWizards.RELEASE_NOTES, context, bundle));
|
||||
dialogShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Log.d(this.getClass().getName(), "Application was opened " + appOpenedCounter + " time!");
|
||||
if (!dialogShown) {
|
||||
if (appOpenedCounter != null && appOpenedCounter > 30) {
|
||||
dialogShown = showSpecialWindow(preferences, Preferences.Gui.feedbackWindowShown, R.layout.feedback, R.id.feedbackText, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean showSpecialWindow(@Nonnull SharedPreferences preferences, @Nonnull Preference<Boolean> specialWindowShownPref, int layoutId, int textViewId, @Nonnull Context context) {
|
||||
boolean result = false;
|
||||
|
||||
final Boolean specialWindowShown = specialWindowShownPref.getPreference(preferences);
|
||||
if (specialWindowShown != null && !specialWindowShown) {
|
||||
final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
|
||||
final View view = layoutInflater.inflate(layoutId, null);
|
||||
|
||||
final TextView feedbackTextView = (TextView) view.findViewById(textViewId);
|
||||
feedbackTextView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context).setView(view);
|
||||
builder.setPositiveButton(android.R.string.ok, null);
|
||||
builder.create().show();
|
||||
|
||||
result = true;
|
||||
specialWindowShownPref.putPreference(preferences, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
final Preferences.Gui.Layout layout = Preferences.Gui.layout.getPreferenceNoError(preferences);
|
||||
ui.setLayoutId(layout.getLayoutId());
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (isMultiPane()) {
|
||||
ui.addTab(this, CalculatorFragmentType.history, null, R.id.main_second_pane);
|
||||
ui.addTab(this, CalculatorFragmentType.saved_history, null, R.id.main_second_pane);
|
||||
ui.addTab(this, CalculatorFragmentType.variables, null, R.id.main_second_pane);
|
||||
ui.addTab(this, CalculatorFragmentType.functions, null, R.id.main_second_pane);
|
||||
ui.addTab(this, CalculatorFragmentType.operators, null, R.id.main_second_pane);
|
||||
ui.addTab(this, CalculatorPlotActivity.getPlotterFragmentType(), null, R.id.main_second_pane);
|
||||
} else {
|
||||
final ActionBar actionBar = getSupportActionBar();
|
||||
if (Build.VERSION.SDK_INT <= GINGERBREAD_MR1 || (Build.VERSION.SDK_INT >= ICE_CREAM_SANDWICH && hasPermanentMenuKey())) {
|
||||
actionBar.hide();
|
||||
} else {
|
||||
actionBar.setDisplayShowTitleEnabled(false);
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
|
||||
}
|
||||
}
|
||||
|
||||
FragmentUtils.createFragment(this, CalculatorEditorFragment.class, R.id.editorContainer, "editor");
|
||||
FragmentUtils.createFragment(this, CalculatorDisplayFragment.class, R.id.displayContainer, "display");
|
||||
FragmentUtils.createFragment(this, CalculatorKeyboardFragment.class, R.id.keyboardContainer, "keyboard");
|
||||
|
||||
this.useBackAsPrev = Preferences.Gui.usePrevAsBack.getPreference(preferences);
|
||||
if (savedInstanceState == null) {
|
||||
firstTimeInit(preferences, this);
|
||||
}
|
||||
|
||||
toggleOrientationChange(preferences);
|
||||
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
Locator.getInstance().getPreferenceService().checkPreferredPreferences(false);
|
||||
|
||||
if (CalculatorApplication.isMonkeyRunner(this)) {
|
||||
Locator.getInstance().getKeyboard().buttonPressed("123");
|
||||
Locator.getInstance().getKeyboard().buttonPressed("+");
|
||||
Locator.getInstance().getKeyboard().buttonPressed("321");
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
private boolean hasPermanentMenuKey() {
|
||||
return ViewConfiguration.get(this).hasPermanentMenuKey();
|
||||
}
|
||||
|
||||
private boolean isMultiPane() {
|
||||
return findViewById(R.id.main_second_pane) != null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private AndroidCalculator getCalculator() {
|
||||
return ((AndroidCalculator) Locator.getInstance().getCalculator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (useBackAsPrev) {
|
||||
getCalculator().doHistoryAction(HistoryAction.undo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
final Preferences.Gui.Layout newLayout = Preferences.Gui.layout.getPreference(preferences);
|
||||
if (newLayout != ui.getLayout()) {
|
||||
Activities.restartActivity(this);
|
||||
}
|
||||
|
||||
final Window window = getWindow();
|
||||
if (preventScreenFromFading.getPreference(preferences)) {
|
||||
window.addFlags(FLAG_KEEP_SCREEN_ON);
|
||||
} else {
|
||||
window.clearFlags(FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences preferences, @Nullable String key) {
|
||||
if (Preferences.Gui.usePrevAsBack.getKey().equals(key)) {
|
||||
useBackAsPrev = Preferences.Gui.usePrevAsBack.getPreference(preferences);
|
||||
}
|
||||
|
||||
if (Preferences.Gui.autoOrientation.getKey().equals(key)) {
|
||||
toggleOrientationChange(preferences);
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleOrientationChange(@Nullable SharedPreferences preferences) {
|
||||
preferences = preferences == null ? PreferenceManager.getDefaultSharedPreferences(this) : preferences;
|
||||
if (Preferences.Gui.autoOrientation.getPreference(preferences)) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
} else {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||
switch (calculatorEventType) {
|
||||
case plot_graph:
|
||||
Threads.tryRunOnUiThread(this, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isMultiPane()) {
|
||||
final ActionBar.Tab selectedTab = getSupportActionBar().getSelectedTab();
|
||||
if (selectedTab != null && CalculatorFragmentType.plotter.getFragmentTag().equals(selectedTab.getTag())) {
|
||||
// do nothing - fragment shown and already registered for plot updates
|
||||
} else {
|
||||
// otherwise - open fragment
|
||||
ui.selectTab(CalculatorActivity.this, CalculatorFragmentType.plotter);
|
||||
}
|
||||
} else {
|
||||
// start new activity
|
||||
CalculatorActivityLauncher.plotGraph(CalculatorActivity.this);
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.solovyev.android.Android;
|
||||
import org.solovyev.android.calculator.about.CalculatorAboutActivity;
|
||||
import org.solovyev.android.calculator.function.FunctionEditDialogFragment;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistoryActivity;
|
||||
import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity;
|
||||
import org.solovyev.android.calculator.math.edit.CalculatorOperatorsActivity;
|
||||
import org.solovyev.android.calculator.math.edit.CalculatorVarsActivity;
|
||||
import org.solovyev.android.calculator.math.edit.CalculatorVarsFragment;
|
||||
import org.solovyev.android.calculator.math.edit.VarEditDialogFragment;
|
||||
import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotActivity;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotter;
|
||||
import org.solovyev.android.calculator.preferences.PreferencesActivity;
|
||||
import org.solovyev.common.msg.Message;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
import org.solovyev.common.text.Strings;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 11/2/11
|
||||
* Time: 2:18 PM
|
||||
*/
|
||||
public final class CalculatorActivityLauncher implements CalculatorEventListener {
|
||||
|
||||
public CalculatorActivityLauncher() {
|
||||
}
|
||||
|
||||
public static void showHistory(@Nonnull final Context context) {
|
||||
showHistory(context, false);
|
||||
}
|
||||
|
||||
public static void showHistory(@Nonnull final Context context, boolean detached) {
|
||||
final Intent intent = new Intent(context, CalculatorHistoryActivity.class);
|
||||
Android.addIntentFlags(intent, detached, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void showSettings(@Nonnull final Context context) {
|
||||
showSettings(context, false);
|
||||
}
|
||||
|
||||
public static void showSettings(@Nonnull final Context context, boolean detached) {
|
||||
final Intent intent = new Intent(context, PreferencesActivity.class);
|
||||
Android.addIntentFlags(intent, detached, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void showAbout(@Nonnull final Context context) {
|
||||
context.startActivity(new Intent(context, CalculatorAboutActivity.class));
|
||||
}
|
||||
|
||||
public static void showFunctions(@Nonnull final Context context) {
|
||||
showFunctions(context, false);
|
||||
}
|
||||
|
||||
public static void showFunctions(@Nonnull final Context context, boolean detached) {
|
||||
final Intent intent = new Intent(context, CalculatorFunctionsActivity.class);
|
||||
Android.addIntentFlags(intent, detached, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void showOperators(@Nonnull final Context context) {
|
||||
showOperators(context, false);
|
||||
}
|
||||
|
||||
public static void showOperators(@Nonnull final Context context, boolean detached) {
|
||||
final Intent intent = new Intent(context, CalculatorOperatorsActivity.class);
|
||||
Android.addIntentFlags(intent, detached, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void showVars(@Nonnull final Context context) {
|
||||
showVars(context, false);
|
||||
}
|
||||
|
||||
public static void showVars(@Nonnull final Context context, boolean detached) {
|
||||
final Intent intent = new Intent(context, CalculatorVarsActivity.class);
|
||||
Android.addIntentFlags(intent, detached, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void plotGraph(@Nonnull final Context context) {
|
||||
final Intent intent = new Intent();
|
||||
intent.setClass(context, CalculatorPlotActivity.class);
|
||||
Android.addIntentFlags(intent, false, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void tryCreateVar(@Nonnull final Context context) {
|
||||
final CalculatorDisplay display = Locator.getInstance().getDisplay();
|
||||
final CalculatorDisplayViewState viewState = display.getViewState();
|
||||
if (viewState.isValid()) {
|
||||
final String varValue = viewState.getText();
|
||||
if (!Strings.isEmpty(varValue)) {
|
||||
if (CalculatorVarsFragment.isValidValue(varValue)) {
|
||||
if (context instanceof ActionBarActivity) {
|
||||
VarEditDialogFragment.showDialog(VarEditDialogFragment.Input.newFromValue(varValue), ((ActionBarActivity) context).getSupportFragmentManager());
|
||||
} else {
|
||||
final Intent intent = new Intent(context, CalculatorVarsActivity.class);
|
||||
intent.putExtra(CalculatorVarsFragment.CREATE_VAR_EXTRA_STRING, varValue);
|
||||
Android.addIntentFlags(intent, false, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
} else {
|
||||
getNotifier().showMessage(R.string.c_value_is_not_a_number, MessageType.error);
|
||||
}
|
||||
} else {
|
||||
getNotifier().showMessage(R.string.empty_var_error, MessageType.error);
|
||||
}
|
||||
} else {
|
||||
getNotifier().showMessage(R.string.not_valid_result, MessageType.error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void tryCreateFunction(@Nonnull final Context context) {
|
||||
final CalculatorDisplay display = Locator.getInstance().getDisplay();
|
||||
final CalculatorDisplayViewState viewState = display.getViewState();
|
||||
|
||||
if (viewState.isValid()) {
|
||||
final String functionValue = viewState.getText();
|
||||
if (!Strings.isEmpty(functionValue)) {
|
||||
|
||||
FunctionEditDialogFragment.showDialog(FunctionEditDialogFragment.Input.newFromDisplay(viewState), context);
|
||||
|
||||
} else {
|
||||
getNotifier().showMessage(R.string.empty_function_error, MessageType.error);
|
||||
}
|
||||
} else {
|
||||
getNotifier().showMessage(R.string.not_valid_result, MessageType.error);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static CalculatorNotifier getNotifier() {
|
||||
return Locator.getInstance().getNotifier();
|
||||
}
|
||||
|
||||
public static void tryPlot() {
|
||||
final CalculatorPlotter plotter = Locator.getInstance().getPlotter();
|
||||
final CalculatorDisplay display = Locator.getInstance().getDisplay();
|
||||
final CalculatorDisplayViewState viewState = display.getViewState();
|
||||
|
||||
if (viewState.isValid()) {
|
||||
final String functionValue = viewState.getText();
|
||||
final Generic expression = viewState.getResult();
|
||||
if (!Strings.isEmpty(functionValue) && expression != null) {
|
||||
if (plotter.isPlotPossibleFor(expression)) {
|
||||
plotter.plot(expression);
|
||||
} else {
|
||||
getNotifier().showMessage(R.string.cpp_plot_too_many_variables, MessageType.error);
|
||||
}
|
||||
} else {
|
||||
getNotifier().showMessage(R.string.cpp_plot_empty_function_error, MessageType.error);
|
||||
}
|
||||
} else {
|
||||
getNotifier().showMessage(R.string.not_valid_result, MessageType.error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void openApp(@Nonnull Context context) {
|
||||
final Intent intent = new Intent(context, CalculatorActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void likeButtonPressed(@Nonnull final Context context) {
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.cpp_share_link)));
|
||||
Android.addIntentFlags(intent, false, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void showCalculationMessagesDialog(@Nonnull Context context, @Nonnull List<Message> messages) {
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
if (Preferences.Calculations.showCalculationMessagesDialog.getPreference(prefs)) {
|
||||
FixableMessagesDialog.showDialogForMessages(messages, context, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void showEvaluationError(@Nonnull Context context, @Nonnull final String errorMessage) {
|
||||
final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
final View errorMessageView = layoutInflater.inflate(R.layout.display_error_message, null);
|
||||
((TextView) errorMessageView.findViewById(R.id.error_message_text_view)).setText(errorMessage);
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context)
|
||||
.setPositiveButton(R.string.c_cancel, null)
|
||||
.setView(errorMessageView);
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||
final Context context;
|
||||
|
||||
final Object source = calculatorEventData.getSource();
|
||||
if (source instanceof Context) {
|
||||
context = ((Context) source);
|
||||
} else {
|
||||
context = App.getApplication();
|
||||
}
|
||||
|
||||
switch (calculatorEventType) {
|
||||
case show_create_matrix_dialog:
|
||||
App.getUiThreadExecutor().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Intent intent = new Intent(context, CalculatorMatrixActivity.class);
|
||||
Android.addIntentFlags(intent, false, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case show_create_var_dialog:
|
||||
App.getUiThreadExecutor().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CalculatorActivityLauncher.tryCreateVar(context);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case show_create_function_dialog:
|
||||
App.getUiThreadExecutor().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CalculatorActivityLauncher.tryCreateFunction(context);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case show_evaluation_error:
|
||||
final String errorMessage = (String) data;
|
||||
if (errorMessage != null) {
|
||||
App.getUiThreadExecutor().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showEvaluationError(context, errorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case show_message_dialog:
|
||||
final DialogData dialogData = (DialogData) data;
|
||||
if (dialogData != null) {
|
||||
App.getUiThreadExecutor().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CalculatorDialogActivity.showDialog(context, dialogData);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 11/25/12
|
||||
* Time: 2:34 PM
|
||||
*/
|
||||
public class CalculatorActivityMobile extends CalculatorActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
Preferences.Gui.layout.putPreference(prefs, Preferences.Gui.Layout.main_calculator_mobile);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (!CalculatorApplication.isMonkeyRunner(this)) {
|
||||
this.finish();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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.content.pm.PackageManager;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
|
||||
import org.acra.ACRA;
|
||||
import org.acra.ReportingInteractionMode;
|
||||
import org.acra.annotation.ReportsCrashes;
|
||||
import org.solovyev.android.Android;
|
||||
import org.solovyev.android.calculator.history.AndroidCalculatorHistory;
|
||||
import org.solovyev.android.calculator.language.Language;
|
||||
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
|
||||
import org.solovyev.android.calculator.onscreen.CalculatorOnscreenStartActivity;
|
||||
import org.solovyev.android.calculator.plot.AndroidCalculatorPlotter;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotterImpl;
|
||||
import org.solovyev.android.calculator.view.EditorTextProcessor;
|
||||
import org.solovyev.android.calculator.wizard.CalculatorWizards;
|
||||
import org.solovyev.android.wizard.Wizards;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@ReportsCrashes(formKey = "",
|
||||
formUri = "https://serso.cloudant.com/acra-cpp/_design/acra-storage/_update/report",
|
||||
reportType = org.acra.sender.HttpSender.Type.JSON,
|
||||
httpMethod = org.acra.sender.HttpSender.Method.PUT,
|
||||
formUriBasicAuthLogin = "timbeenterumisideffecird",
|
||||
formUriBasicAuthPassword = "ECL65PO2TH5quIFNAK4hQ5Ng",
|
||||
mode = ReportingInteractionMode.TOAST,
|
||||
resToastText = R.string.crashed)
|
||||
public class CalculatorApplication extends android.app.Application implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTANTS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
public static final String AD_FREE_PRODUCT_ID = "ad_free";
|
||||
public static final String AD_FREE_P_KEY = "org.solovyev.android.calculator_ad_free";
|
||||
public static final String ADMOB = "ca-app-pub-2228934497384784/2916398892";
|
||||
@Nonnull
|
||||
static final String MAIL = "se.solovyev@gmail.com";
|
||||
private static final String TAG = "C++";
|
||||
@Nonnull
|
||||
private static CalculatorApplication instance;
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* FIELDS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
@Nonnull
|
||||
protected final Handler uiHandler = new Handler();
|
||||
@Nonnull
|
||||
private final List<CalculatorEventListener> listeners = new ArrayList<CalculatorEventListener>();
|
||||
@Nonnull
|
||||
private final Wizards wizards = new CalculatorWizards(this);
|
||||
|
||||
private Typeface typeFace;
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTRUCTORS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
public CalculatorApplication() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* METHODS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorApplication getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static SharedPreferences getPreferences() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(getInstance());
|
||||
}
|
||||
|
||||
public static boolean isMonkeyRunner(@Nonnull Context context) {
|
||||
// NOTE: this code is only for monkeyrunner
|
||||
return context.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
ACRA.init(this);
|
||||
} else {
|
||||
LeakCanary.install(this);
|
||||
}
|
||||
|
||||
if (!App.isInitialized()) {
|
||||
App.init(this);
|
||||
}
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
Preferences.setDefaultValues(preferences);
|
||||
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
setTheme(preferences);
|
||||
setLanguageInitially();
|
||||
|
||||
super.onCreate();
|
||||
App.getLanguages().updateLanguage(this, true);
|
||||
|
||||
if (!Preferences.Ga.initialReportDone.getPreference(preferences)) {
|
||||
App.getGa().reportInitially(preferences);
|
||||
Preferences.Ga.initialReportDone.putPreference(preferences, true);
|
||||
}
|
||||
|
||||
final AndroidCalculator calculator = new AndroidCalculator(this);
|
||||
|
||||
final EditorTextProcessor editorTextProcessor = new EditorTextProcessor();
|
||||
|
||||
Locator.getInstance().init(calculator,
|
||||
new AndroidCalculatorEngine(this),
|
||||
new AndroidCalculatorClipboard(this),
|
||||
new AndroidCalculatorNotifier(this),
|
||||
new AndroidCalculatorHistory(this, calculator),
|
||||
new AndroidCalculatorLogger(),
|
||||
new AndroidCalculatorPreferenceService(this),
|
||||
new AndroidCalculatorKeyboard(this, new CalculatorKeyboardImpl(calculator)),
|
||||
new AndroidCalculatorPlotter(this, new CalculatorPlotterImpl(calculator)),
|
||||
editorTextProcessor);
|
||||
|
||||
editorTextProcessor.init(this);
|
||||
|
||||
listeners.add(new CalculatorActivityLauncher());
|
||||
for (CalculatorEventListener listener : listeners) {
|
||||
calculator.addCalculatorEventListener(listener);
|
||||
}
|
||||
|
||||
calculator.addCalculatorEventListener(App.getBroadcaster());
|
||||
|
||||
Locator.getInstance().getCalculator().init();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// prepare engine
|
||||
Locator.getInstance().getEngine().getMathEngine0().evaluate("1+1");
|
||||
Locator.getInstance().getEngine().getMathEngine0().evaluate("1*1");
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
Locator.getInstance().getLogger().debug(TAG, "Application started!");
|
||||
Locator.getInstance().getNotifier().showDebugMessage(TAG, "Application started!");
|
||||
|
||||
App.getUiThreadExecutor().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// we must update the widget when app starts
|
||||
App.getBroadcaster().sendEditorStateChangedIntent();
|
||||
}
|
||||
}, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void setLanguageInitially() {
|
||||
// should be called before onCreate()
|
||||
final Language language = App.getLanguages().getCurrent();
|
||||
if (!language.isSystem() && !language.locale.equals(Locale.getDefault())) {
|
||||
Locale.setDefault(language.locale);
|
||||
}
|
||||
}
|
||||
|
||||
private void setTheme(@Nonnull SharedPreferences preferences) {
|
||||
final Preferences.Gui.Theme theme = Preferences.Gui.getTheme(preferences);
|
||||
setTheme(theme.getThemeId());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public FragmentUi createFragmentHelper(int layoutId) {
|
||||
return new FragmentUi(layoutId);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public FragmentUi createFragmentHelper(int layoutId, int titleResId) {
|
||||
return new FragmentUi(layoutId, titleResId);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public FragmentUi createFragmentHelper(int layoutId, int titleResId, boolean listenersOnCreate) {
|
||||
return new FragmentUi(layoutId, titleResId, listenersOnCreate);
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* STATIC
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
public Handler getUiHandler() {
|
||||
return uiHandler;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Wizards getWizards() {
|
||||
return wizards;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Typeface getTypeFace() {
|
||||
if (typeFace == null) {
|
||||
typeFace = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Regular.ttf");
|
||||
}
|
||||
return typeFace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
||||
if (Preferences.Onscreen.showAppIcon.getKey().equals(key)) {
|
||||
boolean showAppIcon = Preferences.Onscreen.showAppIcon.getPreference(prefs);
|
||||
Android.toggleComponent(this, CalculatorOnscreenStartActivity.class, showAppIcon);
|
||||
Locator.getInstance().getNotifier().showMessage(R.string.cpp_this_change_may_require_reboot, MessageType.info);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class CalculatorBroadcaster implements CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
public static final String ACTION_INIT = "org.solovyev.android.calculator.INIT";
|
||||
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_THEME_CHANGED = "org.solovyev.android.calculator.THEME_CHANGED";
|
||||
|
||||
@Nonnull
|
||||
private final Context context;
|
||||
|
||||
public CalculatorBroadcaster(@Nonnull Context context, @Nonnull SharedPreferences preferences) {
|
||||
this.context = context;
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||
switch (calculatorEventType) {
|
||||
case editor_state_changed:
|
||||
case editor_state_changed_light:
|
||||
sendEditorStateChangedIntent();
|
||||
break;
|
||||
case display_state_changed:
|
||||
sendDisplayStateChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void sendDisplayStateChanged() {
|
||||
sendBroadcastIntent(ACTION_DISPLAY_STATE_CHANGED);
|
||||
}
|
||||
|
||||
public void sendEditorStateChangedIntent() {
|
||||
sendBroadcastIntent(ACTION_EDITOR_STATE_CHANGED);
|
||||
}
|
||||
|
||||
public void sendBroadcastIntent(@Nonnull String action) {
|
||||
context.sendBroadcast(new Intent(action));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (Preferences.Gui.theme.isSameKey(key) || Preferences.Widget.theme.isSameKey(key)) {
|
||||
sendBroadcastIntent(ACTION_THEME_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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.util.SparseArray;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.solovyev.android.calculator.CalculatorSpecialButton.cursor_left;
|
||||
import static org.solovyev.android.calculator.CalculatorSpecialButton.cursor_right;
|
||||
import static org.solovyev.android.calculator.CalculatorSpecialButton.functions_detached;
|
||||
import static org.solovyev.android.calculator.CalculatorSpecialButton.history_detached;
|
||||
import static org.solovyev.android.calculator.CalculatorSpecialButton.open_app;
|
||||
import static org.solovyev.android.calculator.CalculatorSpecialButton.operators_detached;
|
||||
import static org.solovyev.android.calculator.CalculatorSpecialButton.settings_detached;
|
||||
import static org.solovyev.android.calculator.CalculatorSpecialButton.vars_detached;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/20/12
|
||||
* Time: 12:05 AM
|
||||
*/
|
||||
public enum CalculatorButton {
|
||||
|
||||
/*digits*/
|
||||
one(R.id.cpp_button_1, "1"),
|
||||
two(R.id.cpp_button_2, "2"),
|
||||
three(R.id.cpp_button_3, "3"),
|
||||
four(R.id.cpp_button_4, "4"),
|
||||
five(R.id.cpp_button_5, "5"),
|
||||
six(R.id.cpp_button_6, "6"),
|
||||
seven(R.id.cpp_button_7, "7"),
|
||||
eight(R.id.cpp_button_8, "8"),
|
||||
nine(R.id.cpp_button_9, "9"),
|
||||
zero(R.id.cpp_button_0, "0"),
|
||||
|
||||
period(R.id.cpp_button_period, "."),
|
||||
brackets(R.id.cpp_button_round_brackets, "()"),
|
||||
|
||||
settings(R.id.cpp_button_settings, settings_detached),
|
||||
like(R.id.cpp_button_like, CalculatorSpecialButton.like),
|
||||
|
||||
/*last row*/
|
||||
left(R.id.cpp_button_left, cursor_left),
|
||||
right(R.id.cpp_button_right, cursor_right),
|
||||
vars(R.id.cpp_button_vars, vars_detached),
|
||||
functions(R.id.cpp_button_functions, functions_detached),
|
||||
operators(R.id.cpp_button_operators, operators_detached),
|
||||
app(R.id.cpp_button_app, open_app),
|
||||
history(R.id.cpp_button_history, history_detached),
|
||||
|
||||
/*operations*/
|
||||
multiplication(R.id.cpp_button_multiplication, "*"),
|
||||
division(R.id.cpp_button_division, "/"),
|
||||
plus(R.id.cpp_button_plus, "+"),
|
||||
subtraction(R.id.cpp_button_subtraction, "−"),
|
||||
percent(R.id.cpp_button_percent, "%"),
|
||||
power(R.id.cpp_button_power, "^"),
|
||||
|
||||
/*last column*/
|
||||
clear(R.id.cpp_button_clear, CalculatorSpecialButton.clear),
|
||||
erase(R.id.cpp_button_erase, CalculatorSpecialButton.erase, CalculatorSpecialButton.clear),
|
||||
copy(R.id.cpp_button_copy, CalculatorSpecialButton.copy),
|
||||
paste(R.id.cpp_button_paste, CalculatorSpecialButton.paste),
|
||||
|
||||
/*equals*/
|
||||
equals(R.id.cpp_button_equals, CalculatorSpecialButton.equals);
|
||||
|
||||
|
||||
@Nonnull
|
||||
private static SparseArray<CalculatorButton> buttonsByIds = new SparseArray<>();
|
||||
private final int buttonId;
|
||||
@Nonnull
|
||||
private final String onClickText;
|
||||
@Nullable
|
||||
private final String onLongClickText;
|
||||
|
||||
CalculatorButton(int buttonId, @Nonnull CalculatorSpecialButton onClickButton, @Nullable CalculatorSpecialButton onLongClickButton) {
|
||||
this(buttonId, onClickButton.getActionCode(), onLongClickButton == null ? null : onLongClickButton.getActionCode());
|
||||
}
|
||||
|
||||
CalculatorButton(int buttonId, @Nonnull CalculatorSpecialButton onClickButton) {
|
||||
this(buttonId, onClickButton, null);
|
||||
}
|
||||
|
||||
CalculatorButton(int buttonId, @Nonnull String onClickText, @Nullable String onLongClickText) {
|
||||
this.buttonId = buttonId;
|
||||
this.onClickText = onClickText;
|
||||
this.onLongClickText = onLongClickText;
|
||||
|
||||
}
|
||||
|
||||
CalculatorButton(int buttonId, @Nonnull String onClickText) {
|
||||
this(buttonId, onClickText, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CalculatorButton getById(int buttonId) {
|
||||
initButtonsByIdsMap();
|
||||
|
||||
return buttonsByIds.get(buttonId);
|
||||
}
|
||||
|
||||
private static void initButtonsByIdsMap() {
|
||||
if (buttonsByIds.size() == 0) {
|
||||
// if not initialized
|
||||
|
||||
final CalculatorButton[] calculatorButtons = values();
|
||||
|
||||
final SparseArray<CalculatorButton> localButtonsByIds = new SparseArray<>();
|
||||
for (CalculatorButton calculatorButton : calculatorButtons) {
|
||||
localButtonsByIds.append(calculatorButton.getButtonId(), calculatorButton);
|
||||
}
|
||||
|
||||
buttonsByIds = localButtonsByIds;
|
||||
}
|
||||
}
|
||||
|
||||
public void onLongClick() {
|
||||
if (onLongClickText != null) {
|
||||
Locator.getInstance().getKeyboard().buttonPressed(onLongClickText);
|
||||
}
|
||||
}
|
||||
|
||||
public void onClick() {
|
||||
Locator.getInstance().getKeyboard().buttonPressed(onClickText);
|
||||
}
|
||||
|
||||
public int getButtonId() {
|
||||
return buttonId;
|
||||
}
|
||||
}
|
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.PointF;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.RemoteViews;
|
||||
import jscl.AngleUnit;
|
||||
import jscl.NumeralBase;
|
||||
import org.solovyev.android.Views;
|
||||
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
|
||||
import org.solovyev.android.calculator.view.AngleUnitsButton;
|
||||
import org.solovyev.android.calculator.view.NumeralBasesButton;
|
||||
import org.solovyev.android.calculator.view.ScreenMetrics;
|
||||
import org.solovyev.android.views.dragbutton.DragButton;
|
||||
import org.solovyev.android.views.dragbutton.DragDirection;
|
||||
import org.solovyev.android.views.dragbutton.SimpleDragListener;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/28/12
|
||||
* Time: 12:06 AM
|
||||
*/
|
||||
public final class CalculatorButtons {
|
||||
|
||||
private CalculatorButtons() {
|
||||
}
|
||||
|
||||
|
||||
public static void fixButtonsTextSize(@Nonnull Preferences.Gui.Theme theme,
|
||||
@Nonnull Preferences.Gui.Layout layout,
|
||||
@Nonnull View root) {
|
||||
if (!layout.isOptimized()) {
|
||||
|
||||
final ScreenMetrics metrics = App.getScreenMetrics();
|
||||
final boolean portrait = metrics.isInPortraitMode();
|
||||
final int buttonsCount = portrait ? 5 : 4;
|
||||
final int buttonsWeight = portrait ? (2 + 1 + buttonsCount) : (2 + buttonsCount);
|
||||
final int buttonSize = metrics.getHeightPxs() / buttonsWeight;
|
||||
final int textSize = 5 * buttonSize / 12;
|
||||
|
||||
Views.processViewsOfType(root, DragButton.class, new Views.ViewProcessor<DragButton>() {
|
||||
@Override
|
||||
public void process(@Nonnull DragButton button) {
|
||||
button.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void initMultiplicationButton(@Nonnull View root) {
|
||||
final View multiplicationButton = root.findViewById(R.id.cpp_button_multiplication);
|
||||
if (multiplicationButton instanceof Button) {
|
||||
((Button) multiplicationButton).setText(Locator.getInstance().getEngine().getMultiplicationSign());
|
||||
}
|
||||
}
|
||||
|
||||
public static void initMultiplicationButton(@Nonnull RemoteViews views) {
|
||||
views.setTextViewText(R.id.cpp_button_multiplication, Locator.getInstance().getEngine().getMultiplicationSign());
|
||||
}
|
||||
|
||||
|
||||
public static void toggleEqualsButton(@Nullable SharedPreferences preferences,
|
||||
@Nonnull Activity activity) {
|
||||
preferences = preferences == null ? PreferenceManager.getDefaultSharedPreferences(activity) : preferences;
|
||||
|
||||
final boolean large = App.isLargeScreen() && Preferences.Gui.getLayout(preferences).isOptimized();
|
||||
|
||||
if (!large) {
|
||||
if (Views.getScreenOrientation(activity) == Configuration.ORIENTATION_PORTRAIT
|
||||
|| !Preferences.Gui.autoOrientation.getPreference(preferences)) {
|
||||
|
||||
final DragButton equalsButton = (DragButton) activity.findViewById(R.id.cpp_button_equals);
|
||||
if (equalsButton != null) {
|
||||
if (Preferences.Gui.showEqualsButton.getPreference(preferences)) {
|
||||
equalsButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
equalsButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* STATIC CLASSES
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
private static CalculatorKeyboard getKeyboard() {
|
||||
return Locator.getInstance().getKeyboard();
|
||||
}
|
||||
|
||||
static class RoundBracketsDragProcessor implements SimpleDragListener.DragProcessor {
|
||||
|
||||
@Nonnull
|
||||
private final DigitButtonDragProcessor upDownProcessor = new DigitButtonDragProcessor(getKeyboard());
|
||||
|
||||
@Override
|
||||
public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull PointF startPoint, @Nonnull MotionEvent motionEvent) {
|
||||
final boolean result;
|
||||
|
||||
if (dragDirection == DragDirection.left) {
|
||||
App.getVibrator().vibrate();
|
||||
getKeyboard().roundBracketsButtonPressed();
|
||||
result = true;
|
||||
} else {
|
||||
result = upDownProcessor.processDragEvent(dragDirection, dragButton, startPoint, motionEvent);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static class VarsDragProcessor implements SimpleDragListener.DragProcessor {
|
||||
|
||||
@Nonnull
|
||||
private Context context;
|
||||
|
||||
VarsDragProcessor(@Nonnull Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDragEvent(@Nonnull DragDirection dragDirection,
|
||||
@Nonnull DragButton dragButton,
|
||||
@Nonnull PointF startPoint,
|
||||
@Nonnull MotionEvent motionEvent) {
|
||||
boolean result = false;
|
||||
|
||||
if (dragDirection == DragDirection.up) {
|
||||
App.getVibrator().vibrate();
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_create_var_dialog, null, context);
|
||||
result = true;
|
||||
}/* else if (dragDirection == DragDirection.down) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_create_matrix_dialog, null, context);
|
||||
result = true;
|
||||
}*/
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static class AngleUnitsChanger implements SimpleDragListener.DragProcessor {
|
||||
|
||||
@Nonnull
|
||||
private final DigitButtonDragProcessor processor;
|
||||
|
||||
@Nonnull
|
||||
private final Context context;
|
||||
|
||||
AngleUnitsChanger(@Nonnull Context context) {
|
||||
this.context = context;
|
||||
this.processor = new DigitButtonDragProcessor(Locator.getInstance().getKeyboard());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDragEvent(@Nonnull DragDirection dragDirection,
|
||||
@Nonnull DragButton dragButton,
|
||||
@Nonnull PointF startPoint,
|
||||
@Nonnull MotionEvent motionEvent) {
|
||||
boolean result = false;
|
||||
|
||||
if (dragButton instanceof AngleUnitsButton) {
|
||||
if (dragDirection != DragDirection.left) {
|
||||
final String directionText = ((AngleUnitsButton) dragButton).getText(dragDirection);
|
||||
if (directionText != null) {
|
||||
try {
|
||||
|
||||
final AngleUnit angleUnits = AngleUnit.valueOf(directionText);
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
final AngleUnit oldAngleUnits = AndroidCalculatorEngine.Preferences.angleUnit.getPreference(preferences);
|
||||
if (oldAngleUnits != angleUnits) {
|
||||
App.getVibrator().vibrate();
|
||||
Locator.getInstance().getPreferenceService().setAngleUnits(angleUnits);
|
||||
}
|
||||
|
||||
result = true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.d(this.getClass().getName(), "Unsupported angle units: " + directionText);
|
||||
}
|
||||
}
|
||||
} else if (dragDirection == DragDirection.left) {
|
||||
result = processor.processDragEvent(dragDirection, dragButton, startPoint, motionEvent);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static class NumeralBasesChanger implements SimpleDragListener.DragProcessor {
|
||||
|
||||
@Nonnull
|
||||
private final Context context;
|
||||
|
||||
NumeralBasesChanger(@Nonnull Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDragEvent(@Nonnull DragDirection dragDirection,
|
||||
@Nonnull DragButton dragButton,
|
||||
@Nonnull PointF startPoint,
|
||||
@Nonnull MotionEvent motionEvent) {
|
||||
boolean result = false;
|
||||
|
||||
if (dragButton instanceof NumeralBasesButton) {
|
||||
final String directionText = ((NumeralBasesButton) dragButton).getText(dragDirection);
|
||||
if (directionText != null) {
|
||||
try {
|
||||
|
||||
final NumeralBase numeralBase = NumeralBase.valueOf(directionText);
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
final NumeralBase oldNumeralBase = AndroidCalculatorEngine.Preferences.numeralBase.getPreference(preferences);
|
||||
if (oldNumeralBase != numeralBase) {
|
||||
App.getVibrator().vibrate();
|
||||
Locator.getInstance().getPreferenceService().setNumeralBase(numeralBase);
|
||||
}
|
||||
|
||||
result = true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.d(this.getClass().getName(), "Unsupported numeral base: " + directionText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static class FunctionsDragProcessor implements SimpleDragListener.DragProcessor {
|
||||
|
||||
@Nonnull
|
||||
private Context context;
|
||||
|
||||
FunctionsDragProcessor(@Nonnull Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDragEvent(@Nonnull DragDirection dragDirection,
|
||||
@Nonnull DragButton dragButton,
|
||||
@Nonnull PointF startPoint,
|
||||
@Nonnull MotionEvent motionEvent) {
|
||||
boolean result = false;
|
||||
|
||||
if (dragDirection == DragDirection.up) {
|
||||
App.getVibrator().vibrate();
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_create_function_dialog, null, context);
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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: 9/22/12
|
||||
* Time: 1:34 PM
|
||||
*/
|
||||
public interface CalculatorClipboard {
|
||||
|
||||
@Nullable
|
||||
String getText();
|
||||
|
||||
void setText(@Nonnull CharSequence text);
|
||||
|
||||
void setText(@Nonnull String text);
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 jscl.NumeralBase;
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 24.09.12
|
||||
* Time: 16:45
|
||||
*/
|
||||
public interface CalculatorConversionEventData extends CalculatorEventData {
|
||||
|
||||
// display state on the moment of conversion
|
||||
@Nonnull
|
||||
CalculatorDisplayViewState getDisplayState();
|
||||
|
||||
@Nonnull
|
||||
NumeralBase getFromNumeralBase();
|
||||
|
||||
@Nonnull
|
||||
NumeralBase getToNumeralBase();
|
||||
|
||||
@Nonnull
|
||||
Generic getValue();
|
||||
}
|
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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 jscl.NumeralBase;
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 24.09.12
|
||||
* Time: 16:48
|
||||
*/
|
||||
public class CalculatorConversionEventDataImpl implements CalculatorConversionEventData {
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEventData calculatorEventData;
|
||||
|
||||
@Nonnull
|
||||
private NumeralBase fromNumeralBase;
|
||||
|
||||
@Nonnull
|
||||
private NumeralBase toNumeralBase;
|
||||
|
||||
@Nonnull
|
||||
private Generic value;
|
||||
|
||||
@Nonnull
|
||||
private CalculatorDisplayViewState displayState;
|
||||
|
||||
private CalculatorConversionEventDataImpl() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorConversionEventData newInstance(@Nonnull CalculatorEventData calculatorEventData,
|
||||
@Nonnull Generic value,
|
||||
@Nonnull NumeralBase from,
|
||||
@Nonnull NumeralBase to,
|
||||
@Nonnull CalculatorDisplayViewState displayViewState) {
|
||||
final CalculatorConversionEventDataImpl result = new CalculatorConversionEventDataImpl();
|
||||
|
||||
result.calculatorEventData = calculatorEventData;
|
||||
result.value = value;
|
||||
result.displayState = displayViewState;
|
||||
result.fromNumeralBase = from;
|
||||
result.toNumeralBase = to;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEventId() {
|
||||
return calculatorEventData.getEventId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public Long getSequenceId() {
|
||||
return calculatorEventData.getSequenceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSource() {
|
||||
return calculatorEventData.getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfter(@Nonnull CalculatorEventData that) {
|
||||
return calculatorEventData.isAfter(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameSequence(@Nonnull CalculatorEventData that) {
|
||||
return calculatorEventData.isSameSequence(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfterSequence(@Nonnull CalculatorEventData that) {
|
||||
return calculatorEventData.isAfterSequence(that);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorDisplayViewState getDisplayState() {
|
||||
return this.displayState;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public NumeralBase getFromNumeralBase() {
|
||||
return fromNumeralBase;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public NumeralBase getToNumeralBase() {
|
||||
return toNumeralBase;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public Generic getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.solovyev.android.Android;
|
||||
import org.solovyev.android.fragments.FragmentUtils;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
import org.solovyev.common.text.Strings;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 1/20/13
|
||||
* Time: 12:50 PM
|
||||
*/
|
||||
public class CalculatorDialogActivity extends ActionBarActivity {
|
||||
|
||||
@Nonnull
|
||||
private static final String TAG = CalculatorDialogActivity.class.getSimpleName();
|
||||
|
||||
@Nonnull
|
||||
private static final String DIALOG_DATA_EXTRA = "dialog_data";
|
||||
|
||||
public static void showDialog(@Nonnull Context context, @Nonnull DialogData dialogData) {
|
||||
final Intent intent = new Intent();
|
||||
intent.setClass(context, CalculatorDialogActivity.class);
|
||||
intent.putExtra(DIALOG_DATA_EXTRA, ParcelableDialogData.wrap(dialogData));
|
||||
Android.addIntentFlags(intent, false, context);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static DialogData readDialogData(@Nullable Intent in) {
|
||||
if (in != null) {
|
||||
final Parcelable parcelable = in.getParcelableExtra(DIALOG_DATA_EXTRA);
|
||||
if (parcelable instanceof DialogData) {
|
||||
return (DialogData) parcelable;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static DialogData readDialogData(@Nullable Bundle in) {
|
||||
if (in != null) {
|
||||
final Parcelable parcelable = in.getParcelable(DIALOG_DATA_EXTRA);
|
||||
if (parcelable instanceof DialogData) {
|
||||
return (DialogData) parcelable;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle in) {
|
||||
super.onCreate(in);
|
||||
|
||||
final DialogData dialogData = readDialogData(getIntent());
|
||||
if (dialogData == null) {
|
||||
Locator.getInstance().getLogger().error(TAG, "Dialog data is null!");
|
||||
this.finish();
|
||||
} else {
|
||||
setContentView(R.layout.cpp_dialog);
|
||||
|
||||
final String title = dialogData.getTitle();
|
||||
if (!Strings.isEmpty(title)) {
|
||||
setTitle(title);
|
||||
}
|
||||
|
||||
|
||||
final Bundle args = new Bundle();
|
||||
args.putParcelable(DIALOG_DATA_EXTRA, ParcelableDialogData.wrap(dialogData));
|
||||
FragmentUtils.createFragment(this, CalculatorDialogFragment.class, R.id.dialog_layout, "dialog", args);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CalculatorDialogFragment extends CalculatorFragment {
|
||||
|
||||
public CalculatorDialogFragment() {
|
||||
super(CalculatorFragmentType.dialog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@Nonnull View root, Bundle savedInstanceState) {
|
||||
super.onViewCreated(root, savedInstanceState);
|
||||
|
||||
final DialogData dialogData = readDialogData(getArguments());
|
||||
|
||||
if (dialogData != null) {
|
||||
final TextView messageTextView = (TextView) root.findViewById(R.id.cpp_dialog_message_textview);
|
||||
messageTextView.setMovementMethod(ScrollingMovementMethod.getInstance());
|
||||
messageTextView.setText(dialogData.getMessage());
|
||||
|
||||
if (dialogData.getMessageLevel() == MessageType.error || dialogData.getMessageLevel() == MessageType.warning) {
|
||||
final Button copyButton = (Button) root.findViewById(R.id.cpp_copy_button);
|
||||
copyButton.setVisibility(View.VISIBLE);
|
||||
copyButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Locator.getInstance().getClipboard().setText(dialogData.getMessage());
|
||||
Locator.getInstance().getNotifier().showMessage(CalculatorMessage.newInfoMessage(CalculatorMessages.text_copied));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
root.findViewById(R.id.cpp_ok_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
getActivity().finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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
|
||||
CalculatorDisplayViewState getViewState();
|
||||
|
||||
void setViewState(@Nonnull CalculatorDisplayViewState viewState);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEventData getLastEventData();
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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<CalculatorDisplayViewState> {
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 CalculatorDisplayViewState oldState;
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorDisplayViewState newState;
|
||||
|
||||
public CalculatorDisplayChangeEventDataImpl(@Nonnull CalculatorDisplayViewState oldState, @Nonnull CalculatorDisplayViewState newState) {
|
||||
this.oldState = oldState;
|
||||
this.newState = newState;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorDisplayViewState getOldValue() {
|
||||
return this.oldState;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorDisplayViewState getNewValue() {
|
||||
return this.newState;
|
||||
}
|
||||
}
|
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 25.09.12
|
||||
* Time: 12:03
|
||||
*/
|
||||
public class CalculatorDisplayFragment extends Fragment {
|
||||
|
||||
@Nonnull
|
||||
private FragmentUi fragmentUi;
|
||||
@Nonnull
|
||||
private AndroidCalculatorDisplayView displayView;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
|
||||
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(prefs);
|
||||
if (!layout.isOptimized()) {
|
||||
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_display_mobile, R.string.result);
|
||||
} else {
|
||||
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_display, R.string.result);
|
||||
}
|
||||
|
||||
fragmentUi.onCreate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return fragmentUi.onCreateView(this, inflater, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View root, Bundle savedInstanceState) {
|
||||
super.onViewCreated(root, savedInstanceState);
|
||||
|
||||
displayView = (AndroidCalculatorDisplayView) root.findViewById(R.id.calculator_display);
|
||||
displayView.init(getActivity());
|
||||
Locator.getInstance().getDisplay().setView(displayView);
|
||||
|
||||
fragmentUi.onViewCreated(this, root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
fragmentUi.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
fragmentUi.onPause(this);
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
Locator.getInstance().getDisplay().clearView(displayView);
|
||||
fragmentUi.onDestroyView(this);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
fragmentUi.onDestroy(this);
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static org.solovyev.android.calculator.CalculatorEventType.calculation_cancelled;
|
||||
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;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 8:24 PM
|
||||
*/
|
||||
public class CalculatorDisplayImpl implements CalculatorDisplay {
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorEventHolder lastEvent;
|
||||
@Nonnull
|
||||
private final Object viewLock = new Object();
|
||||
@Nonnull
|
||||
private final Calculator calculator;
|
||||
@Nullable
|
||||
private CalculatorDisplayView view;
|
||||
@Nonnull
|
||||
private CalculatorDisplayViewState viewState = CalculatorDisplayViewStateImpl.newDefaultInstance();
|
||||
|
||||
public CalculatorDisplayImpl(@Nonnull Calculator calculator) {
|
||||
this.calculator = calculator;
|
||||
this.lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
|
||||
this.calculator.addCalculatorEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(@Nonnull CalculatorDisplayView view) {
|
||||
synchronized (viewLock) {
|
||||
if (this.view == view) {
|
||||
this.view = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CalculatorDisplayView getView() {
|
||||
return this.view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setView(@Nonnull CalculatorDisplayView view) {
|
||||
synchronized (viewLock) {
|
||||
this.view = view;
|
||||
this.view.setState(viewState);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorDisplayViewState getViewState() {
|
||||
return this.viewState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setViewState(@Nonnull CalculatorDisplayViewState newViewState) {
|
||||
synchronized (viewLock) {
|
||||
final CalculatorDisplayViewState oldViewState = setViewState0(newViewState);
|
||||
|
||||
this.calculator.fireCalculatorEvent(display_state_changed, new CalculatorDisplayChangeEventDataImpl(oldViewState, newViewState));
|
||||
}
|
||||
}
|
||||
|
||||
private void setViewStateForSequence(@Nonnull CalculatorDisplayViewState newViewState, @Nonnull Long sequenceId) {
|
||||
synchronized (viewLock) {
|
||||
final CalculatorDisplayViewState oldViewState = setViewState0(newViewState);
|
||||
|
||||
this.calculator.fireCalculatorEvent(display_state_changed, new CalculatorDisplayChangeEventDataImpl(oldViewState, newViewState), sequenceId);
|
||||
}
|
||||
}
|
||||
|
||||
// must be synchronized with viewLock
|
||||
@Nonnull
|
||||
private CalculatorDisplayViewState setViewState0(@Nonnull CalculatorDisplayViewState newViewState) {
|
||||
final CalculatorDisplayViewState 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
|
||||
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData,
|
||||
@Nonnull CalculatorEventType calculatorEventType,
|
||||
@Nullable Object data) {
|
||||
if (calculatorEventType.isOfType(calculation_result, calculation_failed, calculation_cancelled, conversion_result, conversion_failed)) {
|
||||
|
||||
final CalculatorEventHolder.Result result = lastEvent.apply(calculatorEventData);
|
||||
|
||||
if (result.isNewAfter()) {
|
||||
switch (calculatorEventType) {
|
||||
case conversion_failed:
|
||||
processConversationFailed((CalculatorConversionEventData) calculatorEventData, (ConversionFailure) data);
|
||||
break;
|
||||
case conversion_result:
|
||||
processConversationResult((CalculatorConversionEventData) calculatorEventData, (String) data);
|
||||
break;
|
||||
case calculation_result:
|
||||
processCalculationResult((CalculatorEvaluationEventData) calculatorEventData, (CalculatorOutput) data);
|
||||
break;
|
||||
case calculation_cancelled:
|
||||
processCalculationCancelled((CalculatorEvaluationEventData) calculatorEventData);
|
||||
break;
|
||||
case calculation_failed:
|
||||
processCalculationFailed((CalculatorEvaluationEventData) calculatorEventData, (CalculatorFailure) data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processConversationFailed(@Nonnull CalculatorConversionEventData calculatorEventData,
|
||||
@Nonnull ConversionFailure data) {
|
||||
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getDisplayState().getOperation(), CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error)), calculatorEventData.getSequenceId());
|
||||
|
||||
}
|
||||
|
||||
private void processCalculationFailed(@Nonnull CalculatorEvaluationEventData calculatorEventData, @Nonnull CalculatorFailure data) {
|
||||
|
||||
final CalculatorEvalException calculatorEvalException = data.getCalculationEvalException();
|
||||
|
||||
final String errorMessage;
|
||||
if (calculatorEvalException != null) {
|
||||
errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
|
||||
} else {
|
||||
final CalculatorParseException calculationParseException = data.getCalculationParseException();
|
||||
if (calculationParseException != null) {
|
||||
errorMessage = calculationParseException.getLocalizedMessage();
|
||||
} else {
|
||||
errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
|
||||
}
|
||||
}
|
||||
|
||||
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage), calculatorEventData.getSequenceId());
|
||||
}
|
||||
|
||||
private void processCalculationCancelled(@Nonnull CalculatorEvaluationEventData calculatorEventData) {
|
||||
final String errorMessage = CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error);
|
||||
|
||||
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newErrorState(calculatorEventData.getOperation(), errorMessage), calculatorEventData.getSequenceId());
|
||||
}
|
||||
|
||||
private void processCalculationResult(@Nonnull CalculatorEvaluationEventData calculatorEventData, @Nonnull CalculatorOutput data) {
|
||||
final String stringResult = data.getStringResult();
|
||||
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newValidState(calculatorEventData.getOperation(), data.getResult(), stringResult, 0), calculatorEventData.getSequenceId());
|
||||
}
|
||||
|
||||
private void processConversationResult(@Nonnull CalculatorConversionEventData calculatorEventData, @Nonnull String result) {
|
||||
// add prefix
|
||||
if (calculatorEventData.getFromNumeralBase() != calculatorEventData.getToNumeralBase()) {
|
||||
result = calculatorEventData.getToNumeralBase().getJsclPrefix() + result;
|
||||
}
|
||||
|
||||
final CalculatorDisplayViewState displayState = calculatorEventData.getDisplayState();
|
||||
this.setViewStateForSequence(CalculatorDisplayViewStateImpl.newValidState(displayState.getOperation(), displayState.getResult(), result, 0), calculatorEventData.getSequenceId());
|
||||
}
|
||||
}
|
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotter;
|
||||
import org.solovyev.android.calculator.view.NumeralBaseConverterDialog;
|
||||
import org.solovyev.android.menu.LabeledMenuItem;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 21.09.12
|
||||
* Time: 10:55
|
||||
*/
|
||||
public enum CalculatorDisplayMenuItem implements LabeledMenuItem<CalculatorDisplayViewState> {
|
||||
|
||||
copy(R.string.c_copy) {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
|
||||
Locator.getInstance().getKeyboard().copyButtonPressed();
|
||||
}
|
||||
},
|
||||
|
||||
convert_to_bin(R.string.convert_to_bin) {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
|
||||
ConversionMenuItem.convert_to_bin.onClick(data, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
|
||||
return ConversionMenuItem.convert_to_bin.isItemVisibleFor(generic, operation);
|
||||
}
|
||||
},
|
||||
|
||||
convert_to_dec(R.string.convert_to_dec) {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
|
||||
ConversionMenuItem.convert_to_dec.onClick(data, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
|
||||
return ConversionMenuItem.convert_to_dec.isItemVisibleFor(generic, operation);
|
||||
}
|
||||
},
|
||||
|
||||
convert_to_hex(R.string.convert_to_hex) {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
|
||||
ConversionMenuItem.convert_to_hex.onClick(data, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
|
||||
return ConversionMenuItem.convert_to_hex.isItemVisibleFor(generic, operation);
|
||||
}
|
||||
},
|
||||
|
||||
convert(R.string.c_convert) {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
|
||||
final Generic result = data.getResult();
|
||||
if (result != null) {
|
||||
new NumeralBaseConverterDialog(result.toString()).show(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
|
||||
return operation == JsclOperation.numeric && generic.getConstants().isEmpty();
|
||||
}
|
||||
},
|
||||
|
||||
plot(R.string.c_plot) {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
|
||||
final Generic expression = data.getResult();
|
||||
if (expression == null) throw new AssertionError();
|
||||
|
||||
final CalculatorPlotter plotter = Locator.getInstance().getPlotter();
|
||||
plotter.plot(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
|
||||
return Locator.getInstance().getPlotter().isPlotPossibleFor(generic);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final int captionId;
|
||||
|
||||
CalculatorDisplayMenuItem(int captionId) {
|
||||
this.captionId = captionId;
|
||||
}
|
||||
|
||||
public final boolean isItemVisible(@Nonnull CalculatorDisplayViewState displayViewState) {
|
||||
//noinspection ConstantConditions
|
||||
return displayViewState.isValid() && displayViewState.getResult() != null && isItemVisibleFor(displayViewState.getResult(), displayViewState.getOperation());
|
||||
}
|
||||
|
||||
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCaption(@Nonnull Context context) {
|
||||
return context.getString(captionId);
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.support.v4.app.FragmentActivity;
|
||||
import android.view.View;
|
||||
|
||||
import org.solovyev.android.menu.ContextMenuBuilder;
|
||||
import org.solovyev.android.menu.ListContextMenu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 21.09.12
|
||||
* Time: 10:58
|
||||
*/
|
||||
public class CalculatorDisplayOnClickListener implements View.OnClickListener {
|
||||
|
||||
@Nonnull
|
||||
private final FragmentActivity activity;
|
||||
|
||||
public CalculatorDisplayOnClickListener(@Nonnull FragmentActivity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v instanceof CalculatorDisplayView) {
|
||||
final CalculatorDisplay cd = Locator.getInstance().getDisplay();
|
||||
|
||||
final CalculatorDisplayViewState displayViewState = cd.getViewState();
|
||||
|
||||
if (displayViewState.isValid()) {
|
||||
final List<CalculatorDisplayMenuItem> filteredMenuItems = new ArrayList<CalculatorDisplayMenuItem>(CalculatorDisplayMenuItem.values().length);
|
||||
for (CalculatorDisplayMenuItem menuItem : CalculatorDisplayMenuItem.values()) {
|
||||
if (menuItem.isItemVisible(displayViewState)) {
|
||||
filteredMenuItems.add(menuItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (!filteredMenuItems.isEmpty()) {
|
||||
ContextMenuBuilder.newInstance(activity, "display-menu", ListContextMenu.newInstance(filteredMenuItems)).build(displayViewState).show();
|
||||
}
|
||||
|
||||
} else {
|
||||
final String errorMessage = displayViewState.getErrorMessage();
|
||||
if (errorMessage != null) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_evaluation_error, errorMessage, activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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
|
||||
CalculatorDisplayViewState getState();
|
||||
|
||||
void setState(@Nonnull CalculatorDisplayViewState state);
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 9:50 PM
|
||||
*/
|
||||
public interface CalculatorDisplayViewState extends Serializable {
|
||||
|
||||
@Nonnull
|
||||
String getText();
|
||||
|
||||
int getSelection();
|
||||
|
||||
@Nullable
|
||||
Generic getResult();
|
||||
|
||||
boolean isValid();
|
||||
|
||||
@Nullable
|
||||
String getErrorMessage();
|
||||
|
||||
@Nonnull
|
||||
JsclOperation getOperation();
|
||||
|
||||
@Nullable
|
||||
String getStringResult();
|
||||
}
|
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.jscl.JsclOperation;
|
||||
import org.solovyev.common.text.Strings;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 9:50 PM
|
||||
*/
|
||||
public class CalculatorDisplayViewStateImpl implements CalculatorDisplayViewState {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* FIELDS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
private JsclOperation operation = JsclOperation.numeric;
|
||||
|
||||
@Nullable
|
||||
private transient Generic result;
|
||||
|
||||
@Nullable
|
||||
private String stringResult = "";
|
||||
|
||||
private boolean valid = true;
|
||||
|
||||
@Nullable
|
||||
private String errorMessage;
|
||||
|
||||
private int selection = 0;
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTRUCTORS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private CalculatorDisplayViewStateImpl() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorDisplayViewState newDefaultInstance() {
|
||||
return new CalculatorDisplayViewStateImpl();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorDisplayViewState newErrorState(@Nonnull JsclOperation operation,
|
||||
@Nonnull String errorMessage) {
|
||||
final CalculatorDisplayViewStateImpl calculatorDisplayState = new CalculatorDisplayViewStateImpl();
|
||||
calculatorDisplayState.valid = false;
|
||||
calculatorDisplayState.errorMessage = errorMessage;
|
||||
calculatorDisplayState.operation = operation;
|
||||
return calculatorDisplayState;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorDisplayViewState newValidState(@Nonnull JsclOperation operation,
|
||||
@Nullable Generic result,
|
||||
@Nonnull String stringResult,
|
||||
int selection) {
|
||||
final CalculatorDisplayViewStateImpl calculatorDisplayState = new CalculatorDisplayViewStateImpl();
|
||||
calculatorDisplayState.valid = true;
|
||||
calculatorDisplayState.result = result;
|
||||
calculatorDisplayState.stringResult = stringResult;
|
||||
calculatorDisplayState.operation = operation;
|
||||
calculatorDisplayState.selection = selection;
|
||||
|
||||
return calculatorDisplayState;
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* METHODS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getText() {
|
||||
return Strings.getNotEmpty(isValid() ? stringResult : errorMessage, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelection() {
|
||||
return selection;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Generic getResult() {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return this.valid;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getErrorMessage() {
|
||||
return this.errorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getStringResult() {
|
||||
return stringResult;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public JsclOperation getOperation() {
|
||||
return this.operation;
|
||||
}
|
||||
}
|
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.solovyev.common.gui.CursorControl;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 21.09.12
|
||||
* Time: 11:47
|
||||
*/
|
||||
public interface CalculatorEditor extends CalculatorEventListener {
|
||||
|
||||
@Nonnull
|
||||
String TAG = CalculatorEditor.class.getSimpleName();
|
||||
|
||||
void setView(@Nonnull CalculatorEditorView view);
|
||||
|
||||
void clearView(@Nonnull CalculatorEditorView view);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEditorViewState getViewState();
|
||||
|
||||
void setViewState(@Nonnull CalculatorEditorViewState viewState);
|
||||
|
||||
// updates state of view (view.setState())
|
||||
void updateViewState();
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CURSOR CONTROL
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Method sets the cursor to the beginning
|
||||
*/
|
||||
@Nonnull
|
||||
public CalculatorEditorViewState setCursorOnStart();
|
||||
|
||||
/**
|
||||
* Method sets the cursor to the end
|
||||
*/
|
||||
@Nonnull
|
||||
public CalculatorEditorViewState setCursorOnEnd();
|
||||
|
||||
/**
|
||||
* Method moves cursor to the left of current position
|
||||
*/
|
||||
@Nonnull
|
||||
public CalculatorEditorViewState moveCursorLeft();
|
||||
|
||||
/**
|
||||
* Method moves cursor to the right of current position
|
||||
*/
|
||||
@Nonnull
|
||||
public CalculatorEditorViewState moveCursorRight();
|
||||
|
||||
@Nonnull
|
||||
CursorControl asCursorControl();
|
||||
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* EDITOR OPERATIONS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
@Nonnull
|
||||
CalculatorEditorViewState erase();
|
||||
|
||||
@Nonnull
|
||||
CalculatorEditorViewState clear();
|
||||
|
||||
@Nonnull
|
||||
CalculatorEditorViewState setText(@Nonnull String text);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEditorViewState setText(@Nonnull String text, int selection);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEditorViewState insert(@Nonnull String text);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEditorViewState insert(@Nonnull String text, int selectionOffset);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEditorViewState moveSelection(int offset);
|
||||
|
||||
@Nonnull
|
||||
CalculatorEditorViewState setSelection(int selection);
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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: Solovyev_S
|
||||
* Date: 21.09.12
|
||||
* Time: 13:46
|
||||
*/
|
||||
public final class CalculatorEditorChangeEventData implements Change<CalculatorEditorViewState> {
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEditorViewState oldState;
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEditorViewState newState;
|
||||
|
||||
private CalculatorEditorChangeEventData(@Nonnull CalculatorEditorViewState oldState,
|
||||
@Nonnull CalculatorEditorViewState newState) {
|
||||
this.oldState = oldState;
|
||||
this.newState = newState;
|
||||
}
|
||||
|
||||
public static CalculatorEditorChangeEventData newChangeEventData(@Nonnull CalculatorEditorViewState oldState,
|
||||
@Nonnull CalculatorEditorViewState newState) {
|
||||
return new CalculatorEditorChangeEventData(oldState, newState);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState getOldValue() {
|
||||
return this.oldState;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState getNewValue() {
|
||||
return this.newState;
|
||||
}
|
||||
}
|
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.solovyev.android.menu.ActivityMenu;
|
||||
import org.solovyev.android.menu.AndroidMenuHelper;
|
||||
import org.solovyev.android.menu.ListActivityMenu;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 25.09.12
|
||||
* Time: 10:49
|
||||
*/
|
||||
public class CalculatorEditorFragment extends Fragment {
|
||||
|
||||
@Nonnull
|
||||
private FragmentUi fragmentUi;
|
||||
|
||||
@Nonnull
|
||||
private ActivityMenu<Menu, MenuItem> menu = ListActivityMenu.fromEnum(CalculatorMenu.class, AndroidMenuHelper.getInstance());
|
||||
|
||||
@Nonnull
|
||||
private AndroidCalculatorEditorView editorView;
|
||||
|
||||
public CalculatorEditorFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
fragmentUi.onViewCreated(this, view);
|
||||
|
||||
editorView = (AndroidCalculatorEditorView) view.findViewById(R.id.calculator_editor);
|
||||
editorView.init();
|
||||
Locator.getInstance().getEditor().setView(editorView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
|
||||
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(prefs);
|
||||
if (!layout.isOptimized()) {
|
||||
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_editor_mobile, R.string.editor);
|
||||
} else {
|
||||
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_editor, R.string.editor);
|
||||
}
|
||||
|
||||
fragmentUi.onCreate(this);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return fragmentUi.onCreateView(this, inflater, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
this.fragmentUi.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
this.fragmentUi.onPause(this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
Locator.getInstance().getEditor().clearView(editorView);
|
||||
fragmentUi.onDestroyView(this);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
fragmentUi.onDestroy(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* MENU
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
this.menu.onCreateOptionsMenu(this.getActivity(), menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
this.menu.onPrepareOptionsMenu(this.getActivity(), menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return this.menu.onOptionsItemSelected(this.getActivity(), item);
|
||||
}
|
||||
}
|
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.history.CalculatorHistoryState;
|
||||
import org.solovyev.android.calculator.history.EditorHistoryState;
|
||||
import org.solovyev.android.calculator.text.TextProcessor;
|
||||
import org.solovyev.android.calculator.text.TextProcessorEditorResult;
|
||||
import org.solovyev.common.gui.CursorControl;
|
||||
import org.solovyev.common.text.Strings;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.lang.Math.min;
|
||||
import static org.solovyev.android.calculator.CalculatorEditorChangeEventData.newChangeEventData;
|
||||
import static org.solovyev.android.calculator.CalculatorEventType.editor_state_changed;
|
||||
import static org.solovyev.android.calculator.CalculatorEventType.editor_state_changed_light;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 21.09.12
|
||||
* Time: 11:53
|
||||
*/
|
||||
public class CalculatorEditorImpl implements CalculatorEditor {
|
||||
|
||||
@Nonnull
|
||||
private final Object viewLock = new Object();
|
||||
@Nonnull
|
||||
private final Calculator calculator;
|
||||
@Nonnull
|
||||
private final CalculatorEventHolder lastEventHolder;
|
||||
@Nonnull
|
||||
private final CursorControlAdapter cursorControlAdapter = new CursorControlAdapter(this);
|
||||
@Nullable
|
||||
private final TextProcessor<TextProcessorEditorResult, String> textProcessor;
|
||||
@Nullable
|
||||
private CalculatorEditorView view;
|
||||
@Nonnull
|
||||
private CalculatorEditorViewState lastViewState = CalculatorEditorViewStateImpl.newDefaultInstance();
|
||||
|
||||
public CalculatorEditorImpl(@Nonnull Calculator calculator, @Nullable TextProcessor<TextProcessorEditorResult, String> textProcessor) {
|
||||
this.calculator = calculator;
|
||||
this.textProcessor = textProcessor;
|
||||
this.calculator.addCalculatorEventListener(this);
|
||||
this.lastEventHolder = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
|
||||
}
|
||||
|
||||
public static int correctSelection(int selection, @Nonnull CharSequence text) {
|
||||
return correctSelection(selection, text.length());
|
||||
}
|
||||
|
||||
public static int correctSelection(int selection, int textLength) {
|
||||
int result = Math.max(selection, 0);
|
||||
result = min(result, textLength);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setView(@Nonnull CalculatorEditorView view) {
|
||||
synchronized (viewLock) {
|
||||
this.view = view;
|
||||
this.view.setState(lastViewState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(@Nonnull CalculatorEditorView view) {
|
||||
synchronized (viewLock) {
|
||||
if (this.view == view) {
|
||||
this.view = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState getViewState() {
|
||||
return lastViewState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setViewState(@Nonnull CalculatorEditorViewState newViewState) {
|
||||
setViewState(newViewState, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateViewState() {
|
||||
setViewState(this.lastViewState, false);
|
||||
}
|
||||
|
||||
private void setViewState(@Nonnull CalculatorEditorViewState newViewState, boolean majorChanges) {
|
||||
if (textProcessor != null) {
|
||||
try {
|
||||
final TextProcessorEditorResult result = textProcessor.process(newViewState.getText());
|
||||
newViewState = CalculatorEditorViewStateImpl.newInstance(result.getCharSequence(), newViewState.getSelection() + result.getOffset());
|
||||
} catch (CalculatorParseException e) {
|
||||
Locator.getInstance().getLogger().error(TAG, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
synchronized (viewLock) {
|
||||
final CalculatorEditorViewState oldViewState = this.lastViewState;
|
||||
|
||||
this.lastViewState = newViewState;
|
||||
if (this.view != null) {
|
||||
this.view.setState(newViewState);
|
||||
}
|
||||
|
||||
fireStateChangedEvent(majorChanges, oldViewState, newViewState);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* SELECTION
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private void fireStateChangedEvent(boolean majorChanges, @Nonnull CalculatorEditorViewState oldViewState, @Nonnull CalculatorEditorViewState newViewState) {
|
||||
if (!Thread.holdsLock(viewLock)) throw new AssertionError();
|
||||
|
||||
if (majorChanges) {
|
||||
calculator.fireCalculatorEvent(editor_state_changed, newChangeEventData(oldViewState, newViewState));
|
||||
} else {
|
||||
calculator.fireCalculatorEvent(editor_state_changed_light, newChangeEventData(oldViewState, newViewState));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData,
|
||||
@Nonnull CalculatorEventType calculatorEventType,
|
||||
@Nullable Object data) {
|
||||
final CalculatorEventHolder.Result result = lastEventHolder.apply(calculatorEventData);
|
||||
|
||||
if (result.isNewAfter()) {
|
||||
switch (calculatorEventType) {
|
||||
case use_history_state:
|
||||
final CalculatorHistoryState calculatorHistoryState = (CalculatorHistoryState) data;
|
||||
final EditorHistoryState editorState = calculatorHistoryState.getEditorState();
|
||||
this.setText(Strings.getNotEmpty(editorState.getText(), ""), editorState.getCursorPosition());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEditorViewState newSelectionViewState(int newSelection) {
|
||||
if (this.lastViewState.getSelection() != newSelection) {
|
||||
final CalculatorEditorViewState result = CalculatorEditorViewStateImpl.newSelection(this.lastViewState, newSelection);
|
||||
setViewState(result, false);
|
||||
return result;
|
||||
} else {
|
||||
return this.lastViewState;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CalculatorEditorViewState setCursorOnStart() {
|
||||
synchronized (viewLock) {
|
||||
return newSelectionViewState(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CalculatorEditorViewState setCursorOnEnd() {
|
||||
synchronized (viewLock) {
|
||||
return newSelectionViewState(this.lastViewState.getText().length());
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CalculatorEditorViewState moveCursorLeft() {
|
||||
synchronized (viewLock) {
|
||||
if (this.lastViewState.getSelection() > 0) {
|
||||
return newSelectionViewState(this.lastViewState.getSelection() - 1);
|
||||
} else {
|
||||
return this.lastViewState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* EDITOR ACTIONS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
public CalculatorEditorViewState moveCursorRight() {
|
||||
synchronized (viewLock) {
|
||||
if (this.lastViewState.getSelection() < this.lastViewState.getText().length()) {
|
||||
return newSelectionViewState(this.lastViewState.getSelection() + 1);
|
||||
} else {
|
||||
return this.lastViewState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CursorControl asCursorControl() {
|
||||
return cursorControlAdapter;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState erase() {
|
||||
synchronized (viewLock) {
|
||||
int selection = this.lastViewState.getSelection();
|
||||
final String text = this.lastViewState.getText();
|
||||
if (selection > 0 && text.length() > 0 && selection <= text.length()) {
|
||||
final StringBuilder newText = new StringBuilder(text.length() - 1);
|
||||
newText.append(text.substring(0, selection - 1)).append(text.substring(selection, text.length()));
|
||||
|
||||
final CalculatorEditorViewState result = CalculatorEditorViewStateImpl.newInstance(newText.toString(), selection - 1);
|
||||
setViewState(result);
|
||||
return result;
|
||||
} else {
|
||||
return this.lastViewState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState clear() {
|
||||
synchronized (viewLock) {
|
||||
return setText("");
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState setText(@Nonnull String text) {
|
||||
synchronized (viewLock) {
|
||||
final CalculatorEditorViewState result = CalculatorEditorViewStateImpl.newInstance(text, text.length());
|
||||
setViewState(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState setText(@Nonnull String text, int selection) {
|
||||
synchronized (viewLock) {
|
||||
selection = correctSelection(selection, text);
|
||||
|
||||
final CalculatorEditorViewState result = CalculatorEditorViewStateImpl.newInstance(text, selection);
|
||||
setViewState(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState insert(@Nonnull String text) {
|
||||
synchronized (viewLock) {
|
||||
return insert(text, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState insert(@Nonnull String text, int selectionOffset) {
|
||||
synchronized (viewLock) {
|
||||
final String oldText = lastViewState.getText();
|
||||
final int selection = correctSelection(lastViewState.getSelection(), oldText);
|
||||
|
||||
int newTextLength = text.length() + oldText.length();
|
||||
final StringBuilder newText = new StringBuilder(newTextLength);
|
||||
|
||||
newText.append(oldText.substring(0, selection));
|
||||
newText.append(text);
|
||||
newText.append(oldText.substring(selection));
|
||||
|
||||
int newSelection = correctSelection(text.length() + selection + selectionOffset, newTextLength);
|
||||
final CalculatorEditorViewState result = CalculatorEditorViewStateImpl.newInstance(newText.toString(), newSelection);
|
||||
setViewState(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState moveSelection(int offset) {
|
||||
synchronized (viewLock) {
|
||||
int selection = this.lastViewState.getSelection() + offset;
|
||||
|
||||
return setSelection(selection);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEditorViewState setSelection(int selection) {
|
||||
synchronized (viewLock) {
|
||||
selection = correctSelection(selection, this.lastViewState.getText());
|
||||
|
||||
final CalculatorEditorViewState result = CalculatorEditorViewStateImpl.newSelection(this.lastViewState, selection);
|
||||
setViewState(result, false);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CursorControlAdapter implements CursorControl {
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorEditor calculatorEditor;
|
||||
|
||||
private CursorControlAdapter(@Nonnull CalculatorEditor calculatorEditor) {
|
||||
this.calculatorEditor = calculatorEditor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorOnStart() {
|
||||
this.calculatorEditor.setCursorOnStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorOnEnd() {
|
||||
this.calculatorEditor.setCursorOnEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorLeft() {
|
||||
this.calculatorEditor.moveCursorLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorRight() {
|
||||
this.calculatorEditor.moveCursorRight();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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: Solovyev_S
|
||||
* Date: 21.09.12
|
||||
* Time: 11:48
|
||||
*/
|
||||
public interface CalculatorEditorView {
|
||||
|
||||
void setState(@Nonnull CalculatorEditorViewState viewState);
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 java.io.Serializable;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 21.09.12
|
||||
* Time: 11:48
|
||||
*/
|
||||
public interface CalculatorEditorViewState extends Serializable {
|
||||
|
||||
@Nonnull
|
||||
String getText();
|
||||
|
||||
@Nonnull
|
||||
CharSequence getTextAsCharSequence();
|
||||
|
||||
int getSelection();
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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: Solovyev_S
|
||||
* Date: 21.09.12
|
||||
* Time: 12:02
|
||||
*/
|
||||
public class CalculatorEditorViewStateImpl implements CalculatorEditorViewState {
|
||||
|
||||
@Nonnull
|
||||
private CharSequence text = "";
|
||||
|
||||
private int selection = 0;
|
||||
|
||||
private CalculatorEditorViewStateImpl() {
|
||||
}
|
||||
|
||||
public CalculatorEditorViewStateImpl(@Nonnull CalculatorEditorViewState viewState) {
|
||||
this.text = viewState.getText();
|
||||
this.selection = viewState.getSelection();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorEditorViewState newDefaultInstance() {
|
||||
return new CalculatorEditorViewStateImpl();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorEditorViewState newSelection(@Nonnull CalculatorEditorViewState viewState, int newSelection) {
|
||||
final CalculatorEditorViewStateImpl result = new CalculatorEditorViewStateImpl(viewState);
|
||||
|
||||
result.selection = newSelection;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorEditorViewState newInstance(@Nonnull CharSequence text, int selection) {
|
||||
final CalculatorEditorViewStateImpl result = new CalculatorEditorViewStateImpl();
|
||||
result.text = text;
|
||||
result.selection = selection;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getText() {
|
||||
return this.text.toString();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CharSequence getTextAsCharSequence() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelection() {
|
||||
return this.selection;
|
||||
}
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 java.text.DecimalFormatSymbols;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import jscl.AngleUnit;
|
||||
import jscl.MathEngine;
|
||||
import jscl.NumeralBase;
|
||||
import jscl.math.function.Function;
|
||||
import jscl.math.function.IConstant;
|
||||
import jscl.math.operator.Operator;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 12:43
|
||||
*/
|
||||
public interface CalculatorEngine {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* INIT
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
void init();
|
||||
|
||||
void reset();
|
||||
|
||||
void softReset();
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* REGISTRIES
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
CalculatorMathRegistry<IConstant> getVarsRegistry();
|
||||
|
||||
@Nonnull
|
||||
CalculatorMathRegistry<Function> getFunctionsRegistry();
|
||||
|
||||
@Nonnull
|
||||
CalculatorMathRegistry<Operator> getOperatorsRegistry();
|
||||
|
||||
@Nonnull
|
||||
CalculatorMathRegistry<Operator> getPostfixFunctionsRegistry();
|
||||
|
||||
@Nonnull
|
||||
CalculatorMathEngine getMathEngine();
|
||||
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
MathEngine getMathEngine0();
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* PREFERENCES
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
String getMultiplicationSign();
|
||||
|
||||
void setMultiplicationSign(@Nonnull String multiplicationSign);
|
||||
|
||||
void setUseGroupingSeparator(boolean useGroupingSeparator);
|
||||
|
||||
void setGroupingSeparator(char groupingSeparator);
|
||||
|
||||
void setPrecision(@Nonnull Integer precision);
|
||||
|
||||
void setRoundResult(@Nonnull Boolean round);
|
||||
|
||||
@Nonnull
|
||||
AngleUnit getAngleUnits();
|
||||
|
||||
void setAngleUnits(@Nonnull AngleUnit angleUnits);
|
||||
|
||||
@Nonnull
|
||||
NumeralBase getNumeralBase();
|
||||
|
||||
void setNumeralBase(@Nonnull NumeralBase numeralBase);
|
||||
|
||||
void setScienceNotation(@Nonnull Boolean scienceNotation);
|
||||
|
||||
void setTimeout(@Nonnull Integer timeout);
|
||||
|
||||
void setDecimalGroupSymbols(@Nonnull DecimalFormatSymbols decimalGroupSymbols);
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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: 10/24/11
|
||||
* Time: 9:55 PM
|
||||
*/
|
||||
public interface CalculatorEngineControl {
|
||||
|
||||
void evaluate();
|
||||
|
||||
void simplify();
|
||||
}
|
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* 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 java.text.DecimalFormatSymbols;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.AngleUnit;
|
||||
import jscl.JsclMathEngine;
|
||||
import jscl.MathEngine;
|
||||
import jscl.NumeralBase;
|
||||
import jscl.math.Generic;
|
||||
import jscl.math.function.Function;
|
||||
import jscl.math.function.IConstant;
|
||||
import jscl.math.operator.Operator;
|
||||
import jscl.text.ParseException;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/23/12
|
||||
* Time: 5:34 PM
|
||||
*/
|
||||
public class CalculatorEngineImpl implements CalculatorEngine {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTANTS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private static final String MULTIPLICATION_SIGN_DEFAULT = "×";
|
||||
|
||||
private static final String MAX_CALCULATION_TIME_DEFAULT = "5";
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* ENGINE/REGISTRIES
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
@Nonnull
|
||||
private final MathEngine engine;
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorMathEngine mathEngine;
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorMathRegistry<IConstant> varsRegistry;
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorMathRegistry<Function> functionsRegistry;
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorMathRegistry<Operator> operatorsRegistry;
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorMathRegistry<Operator> postfixFunctionsRegistry;
|
||||
|
||||
@Nonnull
|
||||
private final Object lock;
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* PREFERENCES
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
|
||||
private int timeout = Integer.valueOf(MAX_CALCULATION_TIME_DEFAULT);
|
||||
|
||||
@Nonnull
|
||||
private String multiplicationSign = MULTIPLICATION_SIGN_DEFAULT;
|
||||
|
||||
public CalculatorEngineImpl(@Nonnull JsclMathEngine engine,
|
||||
@Nonnull CalculatorMathRegistry<IConstant> varsRegistry,
|
||||
@Nonnull CalculatorMathRegistry<Function> functionsRegistry,
|
||||
@Nonnull CalculatorMathRegistry<Operator> operatorsRegistry,
|
||||
@Nonnull CalculatorMathRegistry<Operator> postfixFunctionsRegistry,
|
||||
@Nullable Object lock) {
|
||||
|
||||
this.engine = engine;
|
||||
this.mathEngine = new JsclCalculatorMathEngine(engine);
|
||||
|
||||
this.engine.setRoundResult(true);
|
||||
this.engine.setUseGroupingSeparator(true);
|
||||
|
||||
this.varsRegistry = varsRegistry;
|
||||
this.functionsRegistry = functionsRegistry;
|
||||
this.operatorsRegistry = operatorsRegistry;
|
||||
this.postfixFunctionsRegistry = postfixFunctionsRegistry;
|
||||
this.lock = lock == null ? new Object() : lock;
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* REGISTRIES
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorMathRegistry<IConstant> getVarsRegistry() {
|
||||
return this.varsRegistry;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorMathRegistry<Function> getFunctionsRegistry() {
|
||||
return this.functionsRegistry;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorMathRegistry<Operator> getOperatorsRegistry() {
|
||||
return this.operatorsRegistry;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorMathRegistry<Operator> getPostfixFunctionsRegistry() {
|
||||
return this.postfixFunctionsRegistry;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorMathEngine getMathEngine() {
|
||||
return this.mathEngine;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public MathEngine getMathEngine0() {
|
||||
return this.engine;
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* INIT
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
synchronized (lock) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
synchronized (lock) {
|
||||
safeLoadRegistry(varsRegistry);
|
||||
safeLoadRegistry(functionsRegistry);
|
||||
safeLoadRegistry(operatorsRegistry);
|
||||
safeLoadRegistry(postfixFunctionsRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
private void safeLoadRegistry(@Nonnull CalculatorMathRegistry<?> registry) {
|
||||
try {
|
||||
registry.load();
|
||||
} catch (Exception e) {
|
||||
logException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void logException(@Nonnull Exception e) {
|
||||
final CalculatorLogger logger = Locator.getInstance().getLogger();
|
||||
logger.error("Engine", e.getMessage(), e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void softReset() {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.engine_preferences_changed, null);
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* PREFERENCES
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getMultiplicationSign() {
|
||||
return this.multiplicationSign;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMultiplicationSign(@Nonnull String multiplicationSign) {
|
||||
this.multiplicationSign = multiplicationSign;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUseGroupingSeparator(boolean useGroupingSeparator) {
|
||||
synchronized (lock) {
|
||||
this.engine.setUseGroupingSeparator(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupingSeparator(char groupingSeparator) {
|
||||
synchronized (lock) {
|
||||
this.engine.setGroupingSeparator(groupingSeparator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrecision(@Nonnull Integer precision) {
|
||||
synchronized (lock) {
|
||||
this.engine.setPrecision(precision);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRoundResult(@Nonnull Boolean round) {
|
||||
synchronized (lock) {
|
||||
this.engine.setRoundResult(round);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public AngleUnit getAngleUnits() {
|
||||
synchronized (lock) {
|
||||
return this.engine.getAngleUnits();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAngleUnits(@Nonnull AngleUnit angleUnits) {
|
||||
synchronized (lock) {
|
||||
this.engine.setAngleUnits(angleUnits);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public NumeralBase getNumeralBase() {
|
||||
synchronized (lock) {
|
||||
return this.engine.getNumeralBase();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNumeralBase(@Nonnull NumeralBase numeralBase) {
|
||||
synchronized (lock) {
|
||||
this.engine.setNumeralBase(numeralBase);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScienceNotation(@Nonnull Boolean scienceNotation) {
|
||||
synchronized (lock) {
|
||||
this.engine.setScienceNotation(scienceNotation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimeout(@Nonnull Integer timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDecimalGroupSymbols(@Nonnull DecimalFormatSymbols decimalGroupSymbols) {
|
||||
synchronized (lock) {
|
||||
this.engine.setDecimalGroupSymbols(decimalGroupSymbols);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* STATIC CLASSES
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private static final class JsclCalculatorMathEngine implements CalculatorMathEngine {
|
||||
|
||||
@Nonnull
|
||||
private final MathEngine mathEngine;
|
||||
|
||||
private JsclCalculatorMathEngine(@Nonnull MathEngine mathEngine) {
|
||||
this.mathEngine = mathEngine;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String evaluate(@Nonnull String expression) throws ParseException {
|
||||
return this.mathEngine.evaluate(expression);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String simplify(@Nonnull String expression) throws ParseException {
|
||||
return this.mathEngine.simplify(expression);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String elementary(@Nonnull String expression) throws ParseException {
|
||||
return this.mathEngine.elementary(expression);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Generic evaluateGeneric(@Nonnull String expression) throws ParseException {
|
||||
return this.mathEngine.evaluateGeneric(expression);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Generic simplifyGeneric(@Nonnull String expression) throws ParseException {
|
||||
return this.mathEngine.simplifyGeneric(expression);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Generic elementaryGeneric(@Nonnull String expression) throws ParseException {
|
||||
return this.mathEngine.elementaryGeneric(expression);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.solovyev.common.msg.Message;
|
||||
import org.solovyev.common.msg.MessageLevel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 12/8/11
|
||||
* Time: 1:27 AM
|
||||
*/
|
||||
public class CalculatorEvalException extends Exception implements Message {
|
||||
|
||||
@Nonnull
|
||||
private final Message message;
|
||||
|
||||
@Nonnull
|
||||
private final String expression;
|
||||
|
||||
public CalculatorEvalException(@Nonnull Message message, @Nonnull Throwable cause, String expression) {
|
||||
super(cause);
|
||||
this.message = message;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getMessageCode() {
|
||||
return this.message.getMessageCode();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Object> getParameters() {
|
||||
return this.message.getParameters();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public MessageLevel getMessageLevel() {
|
||||
return this.message.getMessageLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public String getLocalizedMessage() {
|
||||
return this.message.getLocalizedMessage(Locale.getDefault());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getLocalizedMessage(@Nonnull Locale locale) {
|
||||
return this.message.getLocalizedMessage(locale);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 10:00 PM
|
||||
*/
|
||||
public interface CalculatorEvaluationEventData extends CalculatorEventData {
|
||||
|
||||
@Nonnull
|
||||
JsclOperation getOperation();
|
||||
|
||||
@Nonnull
|
||||
String getExpression();
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 10:01 PM
|
||||
*/
|
||||
public class CalculatorEvaluationEventDataImpl implements CalculatorEvaluationEventData {
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorEventData calculatorEventData;
|
||||
|
||||
@Nonnull
|
||||
private final JsclOperation operation;
|
||||
|
||||
@Nonnull
|
||||
private final String expression;
|
||||
|
||||
public CalculatorEvaluationEventDataImpl(@Nonnull CalculatorEventData calculatorEventData,
|
||||
@Nonnull JsclOperation operation,
|
||||
@Nonnull String expression) {
|
||||
this.calculatorEventData = calculatorEventData;
|
||||
this.operation = operation;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public JsclOperation getOperation() {
|
||||
return this.operation;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getExpression() {
|
||||
return this.expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEventId() {
|
||||
return calculatorEventData.getEventId();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Long getSequenceId() {
|
||||
return calculatorEventData.getSequenceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSource() {
|
||||
return calculatorEventData.getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfter(@Nonnull CalculatorEventData that) {
|
||||
return calculatorEventData.isAfter(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameSequence(@Nonnull CalculatorEventData that) {
|
||||
return this.calculatorEventData.isSameSequence(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfterSequence(@Nonnull CalculatorEventData that) {
|
||||
return this.calculatorEventData.isAfterSequence(that);
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 16:39
|
||||
*/
|
||||
public interface CalculatorEventContainer {
|
||||
|
||||
void addCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener);
|
||||
|
||||
void removeCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener);
|
||||
|
||||
void fireCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data);
|
||||
|
||||
void fireCalculatorEvents(@Nonnull List<CalculatorEvent> calculatorEvents);
|
||||
|
||||
public static class CalculatorEvent {
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEventData calculatorEventData;
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEventType calculatorEventType;
|
||||
|
||||
@Nullable
|
||||
private Object data;
|
||||
|
||||
public CalculatorEvent(@Nonnull CalculatorEventData calculatorEventData,
|
||||
@Nonnull CalculatorEventType calculatorEventType,
|
||||
@Nullable Object data) {
|
||||
this.calculatorEventData = calculatorEventData;
|
||||
this.calculatorEventType = calculatorEventType;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CalculatorEventData getCalculatorEventData() {
|
||||
return calculatorEventData;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CalculatorEventType getCalculatorEventType() {
|
||||
return calculatorEventType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 18:18
|
||||
*/
|
||||
public interface CalculatorEventData {
|
||||
|
||||
// the higher id => the later event
|
||||
long getEventId();
|
||||
|
||||
// the higher id => the later event
|
||||
@Nonnull
|
||||
Long getSequenceId();
|
||||
|
||||
@Nullable
|
||||
Object getSource();
|
||||
|
||||
boolean isAfter(@Nonnull CalculatorEventData that);
|
||||
|
||||
boolean isSameSequence(@Nonnull CalculatorEventData that);
|
||||
|
||||
boolean isAfterSequence(@Nonnull CalculatorEventData that);
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 18:18
|
||||
*/
|
||||
class CalculatorEventDataImpl implements CalculatorEventData {
|
||||
|
||||
private static final long NO_SEQUENCE = -1L;
|
||||
|
||||
private final long eventId;
|
||||
private final Object source;
|
||||
@Nonnull
|
||||
private Long sequenceId = NO_SEQUENCE;
|
||||
|
||||
private CalculatorEventDataImpl(long id, @Nonnull Long sequenceId, @Nullable Object source) {
|
||||
this.eventId = id;
|
||||
this.sequenceId = sequenceId;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
static CalculatorEventData newInstance(long id, @Nonnull Long sequenceId) {
|
||||
return new CalculatorEventDataImpl(id, sequenceId, null);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
static CalculatorEventData newInstance(long id, @Nonnull Long sequenceId, @Nonnull Object source) {
|
||||
return new CalculatorEventDataImpl(id, sequenceId, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEventId() {
|
||||
return this.eventId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Long getSequenceId() {
|
||||
return this.sequenceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfter(@Nonnull CalculatorEventData that) {
|
||||
return this.eventId > that.getEventId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameSequence(@Nonnull CalculatorEventData that) {
|
||||
return !this.sequenceId.equals(NO_SEQUENCE) && this.sequenceId.equals(that.getSequenceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAfterSequence(@Nonnull CalculatorEventData that) {
|
||||
return !this.sequenceId.equals(NO_SEQUENCE) && this.sequenceId > that.getSequenceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof CalculatorEventDataImpl)) return false;
|
||||
|
||||
CalculatorEventDataImpl that = (CalculatorEventDataImpl) o;
|
||||
|
||||
if (eventId != that.eventId) return false;
|
||||
if (!sequenceId.equals(that.sequenceId))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (int) (eventId ^ (eventId >>> 32));
|
||||
result = 31 * result + (sequenceId.hashCode());
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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: 10/9/12
|
||||
* Time: 9:59 PM
|
||||
*/
|
||||
public class CalculatorEventHolder {
|
||||
|
||||
@Nonnull
|
||||
private volatile CalculatorEventData lastEventData;
|
||||
|
||||
public CalculatorEventHolder(@Nonnull CalculatorEventData lastEventData) {
|
||||
this.lastEventData = lastEventData;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public synchronized CalculatorEventData getLastEventData() {
|
||||
return lastEventData;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public synchronized Result apply(@Nonnull CalculatorEventData newEventData) {
|
||||
final Result result = new Result(lastEventData, newEventData);
|
||||
|
||||
if (result.isNewAfter()) {
|
||||
this.lastEventData = newEventData;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorEventData lastEventData;
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorEventData newEventData;
|
||||
|
||||
@Nullable
|
||||
private Boolean after = null;
|
||||
|
||||
@Nullable
|
||||
private Boolean sameSequence = null;
|
||||
|
||||
public Result(@Nonnull CalculatorEventData lastEventData,
|
||||
@Nonnull CalculatorEventData newEventData) {
|
||||
this.lastEventData = lastEventData;
|
||||
this.newEventData = newEventData;
|
||||
}
|
||||
|
||||
public boolean isNewAfter() {
|
||||
if (after == null) {
|
||||
after = newEventData.isAfter(lastEventData);
|
||||
}
|
||||
return after;
|
||||
}
|
||||
|
||||
public boolean isSameSequence() {
|
||||
if (sameSequence == null) {
|
||||
sameSequence = newEventData.isSameSequence(lastEventData);
|
||||
}
|
||||
return sameSequence;
|
||||
}
|
||||
|
||||
public boolean isNewAfterSequence() {
|
||||
return newEventData.isAfterSequence(lastEventData);
|
||||
}
|
||||
|
||||
public boolean isNewSameOrAfterSequence() {
|
||||
return isSameSequence() || isNewAfterSequence();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 java.util.EventListener;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 16:39
|
||||
*/
|
||||
public interface CalculatorEventListener extends EventListener {
|
||||
|
||||
void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data);
|
||||
|
||||
}
|
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 16:40
|
||||
*/
|
||||
public enum CalculatorEventType {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CALCULATION
|
||||
* org.solovyev.android.calculator.CalculatorEvaluationEventData
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
|
||||
// @Nonnull CalculatorEditorViewState
|
||||
manual_calculation_requested,
|
||||
|
||||
// @Nonnull org.solovyev.android.calculator.CalculatorOutput
|
||||
calculation_result,
|
||||
|
||||
calculation_cancelled,
|
||||
|
||||
// @Nonnull org.solovyev.android.calculator.CalculatorFailure
|
||||
calculation_failed,
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONVERSION
|
||||
* CalculatorConversionEventData
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
conversion_started,
|
||||
|
||||
// @Nonnull String conversion result
|
||||
conversion_result,
|
||||
|
||||
// @Nonnull ConversionFailure
|
||||
conversion_failed,
|
||||
|
||||
conversion_finished,
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* EDITOR
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
// @Nonnull org.solovyev.android.calculator.CalculatorEditorChangeEventData
|
||||
editor_state_changed,
|
||||
editor_state_changed_light,
|
||||
|
||||
// @Nonnull CalculatorDisplayChangeEventData
|
||||
display_state_changed,
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* ENGINE
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
engine_preferences_changed,
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
// @Nonnull CalculatorHistoryState
|
||||
history_state_added,
|
||||
|
||||
// @Nonnull CalculatorHistoryState
|
||||
use_history_state,
|
||||
|
||||
clear_history_requested,
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* MATH ENTITIES
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
// @Nonnull IConstant
|
||||
use_constant,
|
||||
|
||||
// @Nonnull Function
|
||||
use_function,
|
||||
|
||||
// @Nonnull Operator
|
||||
use_operator,
|
||||
|
||||
// @Nonnull IConstant
|
||||
constant_added,
|
||||
|
||||
// @Nonnull Change<IConstant>
|
||||
constant_changed,
|
||||
|
||||
// @Nonnull IConstant
|
||||
constant_removed,
|
||||
|
||||
|
||||
// @Nonnull Function
|
||||
function_removed,
|
||||
|
||||
// @Nonnull Function
|
||||
function_added,
|
||||
|
||||
// @Nonnull Change<IFunction>
|
||||
function_changed,
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* OTHER
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
// List<Message>
|
||||
calculation_messages,
|
||||
|
||||
show_history,
|
||||
show_history_detached,
|
||||
|
||||
show_functions,
|
||||
show_functions_detached,
|
||||
|
||||
show_vars,
|
||||
show_vars_detached,
|
||||
|
||||
open_app,
|
||||
|
||||
show_operators,
|
||||
show_operators_detached,
|
||||
|
||||
show_settings,
|
||||
show_settings_detached,
|
||||
|
||||
show_like_dialog,
|
||||
|
||||
show_create_var_dialog,
|
||||
show_create_matrix_dialog,
|
||||
show_create_function_dialog,
|
||||
|
||||
/**
|
||||
* {@link DialogData}
|
||||
*/
|
||||
show_message_dialog,
|
||||
|
||||
plot_graph,
|
||||
|
||||
/**
|
||||
* {@link org.solovyev.android.calculator.plot.PlotData}
|
||||
*/
|
||||
plot_data_changed,
|
||||
|
||||
//String
|
||||
show_evaluation_error;
|
||||
|
||||
public boolean isOfType(@Nonnull CalculatorEventType... types) {
|
||||
for (CalculatorEventType type : types) {
|
||||
if (this == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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: 9/20/12
|
||||
* Time: 7:33 PM
|
||||
*/
|
||||
public interface CalculatorFailure {
|
||||
|
||||
@Nonnull
|
||||
Exception getException();
|
||||
|
||||
@Nullable
|
||||
CalculatorParseException getCalculationParseException();
|
||||
|
||||
@Nullable
|
||||
CalculatorEvalException getCalculationEvalException();
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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: 7:34 PM
|
||||
*/
|
||||
public class CalculatorFailureImpl implements CalculatorFailure {
|
||||
|
||||
@Nonnull
|
||||
private Exception exception;
|
||||
|
||||
public CalculatorFailureImpl(@Nonnull Exception exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Exception getException() {
|
||||
return this.exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalculatorParseException getCalculationParseException() {
|
||||
return exception instanceof CalculatorParseException ? (CalculatorParseException) exception : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalculatorEvalException getCalculationEvalException() {
|
||||
return exception instanceof CalculatorEvalException ? (CalculatorEvalException) exception : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CalculatorFailureImpl{" +
|
||||
"exception=" + exception +
|
||||
'}';
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.solovyev.common.collections.Collections;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.AngleUnit;
|
||||
import jscl.text.msg.Messages;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 11/17/12
|
||||
* Time: 7:30 PM
|
||||
*/
|
||||
public enum CalculatorFixableError implements FixableError {
|
||||
|
||||
must_be_rad(Messages.msg_23, Messages.msg_24, Messages.msg_25) {
|
||||
@Override
|
||||
public void fix() {
|
||||
Locator.getInstance().getPreferenceService().setAngleUnits(AngleUnit.rad);
|
||||
}
|
||||
},
|
||||
|
||||
preferred_numeral_base() {
|
||||
@Override
|
||||
public void fix() {
|
||||
Locator.getInstance().getPreferenceService().setPreferredNumeralBase();
|
||||
}
|
||||
},
|
||||
|
||||
preferred_angle_units() {
|
||||
@Override
|
||||
public void fix() {
|
||||
Locator.getInstance().getPreferenceService().setPreferredAngleUnits();
|
||||
}
|
||||
};
|
||||
|
||||
@Nonnull
|
||||
private final List<String> messageCodes;
|
||||
|
||||
CalculatorFixableError(@Nullable String... messageCodes) {
|
||||
this.messageCodes = Collections.asList(messageCodes);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CalculatorFixableError getErrorByMessageCode(@Nonnull String messageCode) {
|
||||
for (CalculatorFixableError fixableError : values()) {
|
||||
if (fixableError.messageCodes.contains(messageCode)) {
|
||||
return fixableError;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CharSequence getFixCaption() {
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 03.10.12
|
||||
* Time: 14:18
|
||||
*/
|
||||
public abstract class CalculatorFragment extends Fragment {
|
||||
|
||||
@Nonnull
|
||||
private final FragmentUi fragmentUi;
|
||||
|
||||
protected CalculatorFragment(int layoutResId, int titleResId) {
|
||||
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(layoutResId, titleResId);
|
||||
}
|
||||
|
||||
protected CalculatorFragment(@Nonnull CalculatorFragmentType fragmentType) {
|
||||
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId());
|
||||
}
|
||||
|
||||
protected CalculatorFragment(@Nonnull FragmentUi fragmentUi) {
|
||||
this.fragmentUi = fragmentUi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
fragmentUi.onCreate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return fragmentUi.onCreateView(this, inflater, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
fragmentUi.onViewCreated(this, view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
this.fragmentUi.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
this.fragmentUi.onPause(this);
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
fragmentUi.onDestroyView(this);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
fragmentUi.onDestroy(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
public boolean isPaneFragment() {
|
||||
return fragmentUi.isPane(this);
|
||||
}
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.support.v4.app.Fragment;
|
||||
|
||||
import org.solovyev.android.calculator.about.CalculatorAboutFragment;
|
||||
import org.solovyev.android.calculator.about.CalculatorReleaseNotesFragment;
|
||||
import org.solovyev.android.calculator.history.HistoryFragment;
|
||||
import org.solovyev.android.calculator.history.SavedHistoryFragment;
|
||||
import org.solovyev.android.calculator.math.edit.CalculatorFunctionsFragment;
|
||||
import org.solovyev.android.calculator.math.edit.CalculatorOperatorsFragment;
|
||||
import org.solovyev.android.calculator.math.edit.CalculatorVarsFragment;
|
||||
import org.solovyev.android.calculator.matrix.CalculatorMatrixEditFragment;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotFragment;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotFunctionSettingsActivity;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotFunctionsActivity;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotRangeActivity;
|
||||
import org.solovyev.android.calculator.preferences.PurchaseDialogActivity;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 03.10.12
|
||||
* Time: 11:30
|
||||
*/
|
||||
public enum CalculatorFragmentType {
|
||||
|
||||
editor(CalculatorEditorFragment.class, R.layout.cpp_app_editor, R.string.editor),
|
||||
//display(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history),
|
||||
//keyboard(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history),
|
||||
history(HistoryFragment.class, R.layout.history_fragment, R.string.c_history),
|
||||
saved_history(SavedHistoryFragment.class, R.layout.history_fragment, R.string.c_saved_history),
|
||||
variables(CalculatorVarsFragment.class, R.layout.vars_fragment, R.string.c_vars),
|
||||
functions(CalculatorFunctionsFragment.class, R.layout.math_entities_fragment, R.string.c_functions),
|
||||
operators(CalculatorOperatorsFragment.class, R.layout.math_entities_fragment, R.string.c_operators),
|
||||
plotter(CalculatorPlotFragment.class, R.layout.cpp_plotter_fragment, R.string.c_graph),
|
||||
plotter_functions(CalculatorPlotFunctionsActivity.CalculatorPlotFunctionsFragment.class, R.layout.cpp_plot_functions_fragment, R.string.cpp_plot_functions),
|
||||
plotter_function_settings(CalculatorPlotFunctionSettingsActivity.CalculatorPlotFunctionSettingsFragment.class, R.layout.cpp_plot_function_settings_fragment, R.string.cpp_plot_function_settings),
|
||||
plotter_range(CalculatorPlotRangeActivity.CalculatorPlotRangeFragment.class, R.layout.cpp_plot_range_fragment, R.string.cpp_plot_range),
|
||||
|
||||
purchase_dialog(PurchaseDialogActivity.PurchaseDialogFragment.class, R.layout.cpp_purchase_dialog_fragment, R.string.cpp_purchase_title),
|
||||
|
||||
dialog(CalculatorDialogActivity.CalculatorDialogFragment.class, R.layout.cpp_dialog_fragment, R.string.cpp_message),
|
||||
|
||||
about(CalculatorAboutFragment.class, R.layout.about_fragment, R.string.c_about),
|
||||
|
||||
// todo serso: strings
|
||||
matrix_edit(CalculatorMatrixEditFragment.class, R.layout.matrix_edit_fragment, R.string.c_release_notes),
|
||||
release_notes(CalculatorReleaseNotesFragment.class, R.layout.release_notes_fragment, R.string.c_release_notes);
|
||||
|
||||
private final int defaultLayoutId;
|
||||
@Nonnull
|
||||
private Class<? extends Fragment> fragmentClass;
|
||||
private int defaultTitleResId;
|
||||
|
||||
private CalculatorFragmentType(@Nonnull Class<? extends Fragment> fragmentClass,
|
||||
int defaultLayoutId,
|
||||
int defaultTitleResId) {
|
||||
this.fragmentClass = fragmentClass;
|
||||
this.defaultLayoutId = defaultLayoutId;
|
||||
this.defaultTitleResId = defaultTitleResId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getFragmentTag() {
|
||||
return this.name();
|
||||
}
|
||||
|
||||
public int getDefaultTitleResId() {
|
||||
return defaultTitleResId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Class<? extends Fragment> getFragmentClass() {
|
||||
return fragmentClass;
|
||||
}
|
||||
|
||||
public int getDefaultLayoutId() {
|
||||
return defaultLayoutId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String createSubFragmentTag(@Nonnull String subFragmentTag) {
|
||||
return this.getFragmentTag() + "_" + subFragmentTag;
|
||||
}
|
||||
}
|
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.function.FunctionBuilderAdapter;
|
||||
import org.solovyev.android.calculator.model.AFunction;
|
||||
import org.solovyev.android.calculator.model.Functions;
|
||||
import org.solovyev.android.calculator.model.MathEntityBuilder;
|
||||
import org.solovyev.common.JBuilder;
|
||||
import org.solovyev.common.math.MathRegistry;
|
||||
import org.solovyev.common.text.Strings;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.CustomFunctionCalculationException;
|
||||
import jscl.math.function.CustomFunction;
|
||||
import jscl.math.function.Function;
|
||||
import jscl.math.function.IFunction;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 11/17/11
|
||||
* Time: 11:28 PM
|
||||
*/
|
||||
public class CalculatorFunctionsMathRegistry extends AbstractCalculatorMathRegistry<Function, AFunction> {
|
||||
|
||||
@Nonnull
|
||||
private static final Map<String, String> substitutes = new HashMap<String, String>();
|
||||
@Nonnull
|
||||
private static final String FUNCTION_DESCRIPTION_PREFIX = "c_fun_description_";
|
||||
|
||||
static {
|
||||
substitutes.put("√", "sqrt");
|
||||
}
|
||||
|
||||
public CalculatorFunctionsMathRegistry(@Nonnull MathRegistry<Function> functionsRegistry,
|
||||
@Nonnull MathEntityDao<AFunction> mathEntityDao) {
|
||||
super(functionsRegistry, FUNCTION_DESCRIPTION_PREFIX, mathEntityDao);
|
||||
}
|
||||
|
||||
public static void saveFunction(@Nonnull CalculatorMathRegistry<Function> registry,
|
||||
@Nonnull MathEntityBuilder<? extends Function> builder,
|
||||
@Nullable IFunction editedInstance,
|
||||
@Nonnull Object source, boolean save) throws CustomFunctionCalculationException, AFunction.Builder.CreationException {
|
||||
final Function addedFunction = registry.add(builder);
|
||||
|
||||
if (save) {
|
||||
registry.save();
|
||||
}
|
||||
|
||||
if (editedInstance == null) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.function_added, addedFunction, source);
|
||||
} else {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.function_changed, ChangeImpl.newInstance(editedInstance, addedFunction), source);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
add(new CustomFunction.Builder(true, "log", Arrays.asList("base", "x"), "ln(x)/ln(base)"));
|
||||
add(new CustomFunction.Builder(true, "√3", Arrays.asList("x"), "x^(1/3)"));
|
||||
add(new CustomFunction.Builder(true, "√4", Arrays.asList("x"), "x^(1/4)"));
|
||||
add(new CustomFunction.Builder(true, "√n", Arrays.asList("x", "n"), "x^(1/n)"));
|
||||
add(new CustomFunction.Builder(true, "re", Arrays.asList("x"), "(x+conjugate(x))/2"));
|
||||
add(new CustomFunction.Builder(true, "im", Arrays.asList("x"), "(x-conjugate(x))/(2*i)"));
|
||||
|
||||
super.load();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected Map<String, String> getSubstitutes() {
|
||||
return substitutes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory(@Nonnull Function function) {
|
||||
for (FunctionCategory category : FunctionCategory.values()) {
|
||||
if (category.isInCategory(function)) {
|
||||
return category.name();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getDescription(@Nonnull String functionName) {
|
||||
final Function function = get(functionName);
|
||||
|
||||
String result = null;
|
||||
if (function instanceof CustomFunction) {
|
||||
result = ((CustomFunction) function).getDescription();
|
||||
}
|
||||
|
||||
if (Strings.isEmpty(result)) {
|
||||
result = super.getDescription(functionName);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected JBuilder<? extends Function> createBuilder(@Nonnull AFunction function) {
|
||||
return new FunctionBuilderAdapter(new AFunction.Builder(function));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AFunction transform(@Nonnull Function function) {
|
||||
if (function instanceof CustomFunction) {
|
||||
return AFunction.fromIFunction((CustomFunction) function);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected MathEntityPersistenceContainer<AFunction> createPersistenceContainer() {
|
||||
return new Functions();
|
||||
}
|
||||
}
|
@@ -0,0 +1,637 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.history.CalculatorHistory;
|
||||
import org.solovyev.android.calculator.history.CalculatorHistoryState;
|
||||
import org.solovyev.android.calculator.jscl.JsclOperation;
|
||||
import org.solovyev.android.calculator.model.Var;
|
||||
import org.solovyev.android.calculator.text.TextProcessor;
|
||||
import org.solovyev.android.calculator.units.CalculatorNumeralBase;
|
||||
import org.solovyev.common.history.HistoryAction;
|
||||
import org.solovyev.common.msg.ListMessageRegistry;
|
||||
import org.solovyev.common.msg.Message;
|
||||
import org.solovyev.common.msg.MessageRegistry;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
import org.solovyev.common.text.Strings;
|
||||
import org.solovyev.common.units.ConversionException;
|
||||
import org.solovyev.common.units.Conversions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.AbstractJsclArithmeticException;
|
||||
import jscl.NumeralBase;
|
||||
import jscl.NumeralBaseException;
|
||||
import jscl.math.Generic;
|
||||
import jscl.math.function.Function;
|
||||
import jscl.math.function.IConstant;
|
||||
import jscl.math.operator.Operator;
|
||||
import jscl.text.ParseInterruptedException;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 16:42
|
||||
*/
|
||||
public class CalculatorImpl implements Calculator, CalculatorEventListener {
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTANTS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
// one minute
|
||||
private static final long PREFERENCE_CHECK_INTERVAL = 1000L * 60L;
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* FIELDS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer();
|
||||
|
||||
@Nonnull
|
||||
private final AtomicLong counter = new AtomicLong(CalculatorUtils.FIRST_ID);
|
||||
|
||||
@Nonnull
|
||||
private final TextProcessor<PreparedExpression, String> preprocessor = ToJsclTextProcessor.getInstance();
|
||||
|
||||
@Nonnull
|
||||
private final Executor calculationsExecutor = Executors.newFixedThreadPool(10);
|
||||
|
||||
// NOTE: only one thread is responsible for events as all events must be done in order of their creating
|
||||
@Nonnull
|
||||
private final Executor eventExecutor = Executors.newFixedThreadPool(1);
|
||||
|
||||
private volatile boolean calculateOnFly = true;
|
||||
|
||||
private volatile long lastPreferenceCheck = 0L;
|
||||
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONSTRUCTORS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
public CalculatorImpl() {
|
||||
this.addCalculatorEventListener(this);
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* METHODS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
private static String doConversion(@Nonnull Generic generic,
|
||||
@Nonnull NumeralBase from,
|
||||
@Nonnull NumeralBase to) throws ConversionException {
|
||||
final String result;
|
||||
|
||||
if (from != to) {
|
||||
String fromString = generic.toString();
|
||||
if (!Strings.isEmpty(fromString)) {
|
||||
try {
|
||||
fromString = ToJsclTextProcessor.getInstance().process(fromString).getExpression();
|
||||
} catch (CalculatorParseException e) {
|
||||
// ok, problems while processing occurred
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result = Conversions.doConversion(CalculatorNumeralBase.getConverter(), fromString, CalculatorNumeralBase.valueOf(from), CalculatorNumeralBase.valueOf(to));
|
||||
} else {
|
||||
result = generic.toString();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEventData nextEventData() {
|
||||
long eventId = counter.incrementAndGet();
|
||||
return CalculatorEventDataImpl.newInstance(eventId, eventId);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEventData nextEventData(@Nonnull Object source) {
|
||||
long eventId = counter.incrementAndGet();
|
||||
return CalculatorEventDataImpl.newInstance(eventId, eventId, source);
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CALCULATION
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEventData nextEventData(@Nonnull Long sequenceId) {
|
||||
long eventId = counter.incrementAndGet();
|
||||
return CalculatorEventDataImpl.newInstance(eventId, sequenceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() {
|
||||
final CalculatorEditorViewState viewState = getEditor().getViewState();
|
||||
final CalculatorEventData eventData = fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState);
|
||||
this.evaluate(JsclOperation.numeric, viewState.getText(), eventData.getSequenceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate(@Nonnull Long sequenceId) {
|
||||
final CalculatorEditorViewState viewState = getEditor().getViewState();
|
||||
fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState, sequenceId);
|
||||
this.evaluate(JsclOperation.numeric, viewState.getText(), sequenceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simplify() {
|
||||
final CalculatorEditorViewState viewState = getEditor().getViewState();
|
||||
final CalculatorEventData eventData = fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState);
|
||||
this.evaluate(JsclOperation.simplify, viewState.getText(), eventData.getSequenceId());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEventData evaluate(@Nonnull final JsclOperation operation,
|
||||
@Nonnull final String expression) {
|
||||
|
||||
final CalculatorEventData eventDataId = nextEventData();
|
||||
|
||||
calculationsExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CalculatorImpl.this.evaluate(eventDataId.getSequenceId(), operation, expression, null);
|
||||
}
|
||||
});
|
||||
|
||||
return eventDataId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEventData evaluate(@Nonnull final JsclOperation operation, @Nonnull final String expression, @Nonnull Long sequenceId) {
|
||||
final CalculatorEventData eventDataId = nextEventData(sequenceId);
|
||||
|
||||
calculationsExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CalculatorImpl.this.evaluate(eventDataId.getSequenceId(), operation, expression, null);
|
||||
}
|
||||
});
|
||||
|
||||
return eventDataId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Locator.getInstance().getEngine().init();
|
||||
Locator.getInstance().getHistory().load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCalculateOnFly() {
|
||||
return calculateOnFly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCalculateOnFly(boolean calculateOnFly) {
|
||||
if (this.calculateOnFly != calculateOnFly) {
|
||||
this.calculateOnFly = calculateOnFly;
|
||||
if (this.calculateOnFly) {
|
||||
evaluate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private CalculatorConversionEventData newConversionEventData(@Nonnull Long sequenceId,
|
||||
@Nonnull Generic value,
|
||||
@Nonnull NumeralBase from,
|
||||
@Nonnull NumeralBase to,
|
||||
@Nonnull CalculatorDisplayViewState displayViewState) {
|
||||
return CalculatorConversionEventDataImpl.newInstance(nextEventData(sequenceId), value, from, to, displayViewState);
|
||||
}
|
||||
|
||||
private void evaluate(@Nonnull Long sequenceId,
|
||||
@Nonnull JsclOperation operation,
|
||||
@Nonnull String expression,
|
||||
@Nullable MessageRegistry mr) {
|
||||
|
||||
checkPreferredPreferences();
|
||||
|
||||
PreparedExpression preparedExpression = null;
|
||||
|
||||
try {
|
||||
|
||||
expression = expression.trim();
|
||||
|
||||
if (Strings.isEmpty(expression)) {
|
||||
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, CalculatorOutputImpl.newEmptyOutput(operation));
|
||||
} else {
|
||||
preparedExpression = prepareExpression(expression);
|
||||
|
||||
final String jsclExpression = preparedExpression.toString();
|
||||
|
||||
try {
|
||||
|
||||
final CalculatorMathEngine mathEngine = Locator.getInstance().getEngine().getMathEngine();
|
||||
|
||||
final MessageRegistry messageRegistry = new ListMessageRegistry();
|
||||
Locator.getInstance().getEngine().getMathEngine0().setMessageRegistry(messageRegistry);
|
||||
|
||||
final Generic result = operation.evaluateGeneric(jsclExpression, mathEngine);
|
||||
|
||||
// NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!)
|
||||
result.toString();
|
||||
|
||||
if (messageRegistry.hasMessage()) {
|
||||
final CalculatorLogger logger = Locator.getInstance().getLogger();
|
||||
try {
|
||||
final List<Message> messages = new ArrayList<Message>();
|
||||
while (messageRegistry.hasMessage()) {
|
||||
messages.add(messageRegistry.getMessage());
|
||||
}
|
||||
if (!messages.isEmpty()) {
|
||||
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_messages, messages);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// todo serso: not good but we need proper synchronization
|
||||
logger.error("Calculator", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
final CalculatorOutput data = CalculatorOutputImpl.newOutput(operation.getFromProcessor().process(result), operation, result);
|
||||
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, data);
|
||||
|
||||
} catch (AbstractJsclArithmeticException e) {
|
||||
handleException(sequenceId, operation, expression, mr, new CalculatorEvalException(e, e, jsclExpression));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (ArithmeticException e) {
|
||||
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_001, MessageType.error, e.getMessage())));
|
||||
} catch (StackOverflowError e) {
|
||||
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(expression, new CalculatorMessage(CalculatorMessages.msg_002, MessageType.error)));
|
||||
} catch (jscl.text.ParseException e) {
|
||||
handleException(sequenceId, operation, expression, mr, preparedExpression, new CalculatorParseException(e));
|
||||
} catch (ParseInterruptedException e) {
|
||||
|
||||
// do nothing - we ourselves interrupt the calculations
|
||||
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_cancelled, null);
|
||||
|
||||
} catch (CalculatorParseException e) {
|
||||
handleException(sequenceId, operation, expression, mr, preparedExpression, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPreferredPreferences() {
|
||||
final long currentTime = System.currentTimeMillis();
|
||||
|
||||
if (currentTime - lastPreferenceCheck > PREFERENCE_CHECK_INTERVAL) {
|
||||
lastPreferenceCheck = currentTime;
|
||||
Locator.getInstance().getPreferenceService().checkPreferredPreferences(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public PreparedExpression prepareExpression(@Nonnull String expression) throws CalculatorParseException {
|
||||
return preprocessor.process(expression);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEventData newCalculationEventData(@Nonnull JsclOperation operation,
|
||||
@Nonnull String expression,
|
||||
@Nonnull Long calculationId) {
|
||||
return new CalculatorEvaluationEventDataImpl(nextEventData(calculationId), operation, expression);
|
||||
}
|
||||
|
||||
private void handleException(@Nonnull Long sequenceId,
|
||||
@Nonnull JsclOperation operation,
|
||||
@Nonnull String expression,
|
||||
@Nullable MessageRegistry mr,
|
||||
@Nullable PreparedExpression preparedExpression,
|
||||
@Nonnull CalculatorParseException parseException) {
|
||||
|
||||
if (operation == JsclOperation.numeric
|
||||
&& preparedExpression != null
|
||||
&& preparedExpression.isExistsUndefinedVar()) {
|
||||
|
||||
evaluate(sequenceId, JsclOperation.simplify, expression, mr);
|
||||
} else {
|
||||
|
||||
fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(parseException));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* CONVERSION
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
private void handleException(@Nonnull Long calculationId,
|
||||
@Nonnull JsclOperation operation,
|
||||
@Nonnull String expression,
|
||||
@Nullable MessageRegistry mr,
|
||||
@Nonnull CalculatorEvalException evalException) {
|
||||
|
||||
if (operation == JsclOperation.numeric && evalException.getCause() instanceof NumeralBaseException) {
|
||||
evaluate(calculationId, JsclOperation.simplify, expression, mr);
|
||||
} else {
|
||||
fireCalculatorEvent(newCalculationEventData(operation, expression, calculationId), CalculatorEventType.calculation_failed, new CalculatorFailureImpl(evalException));
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEventData convert(@Nonnull final Generic value,
|
||||
@Nonnull final NumeralBase to) {
|
||||
final CalculatorEventData eventDataId = nextEventData();
|
||||
|
||||
final CalculatorDisplayViewState displayViewState = Locator.getInstance().getDisplay().getViewState();
|
||||
final NumeralBase from = Locator.getInstance().getEngine().getNumeralBase();
|
||||
|
||||
calculationsExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Long sequenceId = eventDataId.getSequenceId();
|
||||
|
||||
fireCalculatorEvent(newConversionEventData(sequenceId, value, from, to, displayViewState), CalculatorEventType.conversion_started, null);
|
||||
try {
|
||||
|
||||
final String result = doConversion(value, from, to);
|
||||
|
||||
fireCalculatorEvent(newConversionEventData(sequenceId, value, from, to, displayViewState), CalculatorEventType.conversion_result, result);
|
||||
|
||||
} catch (ConversionException e) {
|
||||
fireCalculatorEvent(newConversionEventData(sequenceId, value, from, to, displayViewState), CalculatorEventType.conversion_failed, new ConversionFailureImpl(e));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return eventDataId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConversionPossible(@Nonnull Generic generic, NumeralBase from, @Nonnull NumeralBase to) {
|
||||
try {
|
||||
doConversion(generic, from, to);
|
||||
return true;
|
||||
} catch (ConversionException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* EVENTS
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void addCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener) {
|
||||
calculatorEventContainer.addCalculatorEventListener(calculatorEventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener) {
|
||||
calculatorEventContainer.removeCalculatorEventListener(calculatorEventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCalculatorEvent(@Nonnull final CalculatorEventData calculatorEventData, @Nonnull final CalculatorEventType calculatorEventType, @Nullable final Object data) {
|
||||
eventExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
calculatorEventContainer.fireCalculatorEvent(calculatorEventData, calculatorEventType, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCalculatorEvents(@Nonnull final List<CalculatorEvent> calculatorEvents) {
|
||||
eventExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
calculatorEventContainer.fireCalculatorEvents(calculatorEvents);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEventData fireCalculatorEvent(@Nonnull final CalculatorEventType calculatorEventType, @Nullable final Object data) {
|
||||
final CalculatorEventData eventData = nextEventData();
|
||||
|
||||
fireCalculatorEvent(eventData, calculatorEventType, data);
|
||||
|
||||
return eventData;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEventData fireCalculatorEvent(@Nonnull final CalculatorEventType calculatorEventType, @Nullable final Object data, @Nonnull Object source) {
|
||||
final CalculatorEventData eventData = nextEventData(source);
|
||||
|
||||
fireCalculatorEvent(eventData, calculatorEventType, data);
|
||||
|
||||
return eventData;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorEventData fireCalculatorEvent(@Nonnull final CalculatorEventType calculatorEventType, @Nullable final Object data, @Nonnull Long sequenceId) {
|
||||
final CalculatorEventData eventData = nextEventData(sequenceId);
|
||||
|
||||
fireCalculatorEvent(eventData, calculatorEventType, data);
|
||||
|
||||
return eventData;
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* EVENTS HANDLER
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||
|
||||
switch (calculatorEventType) {
|
||||
case editor_state_changed:
|
||||
if (calculateOnFly) {
|
||||
final CalculatorEditorChangeEventData editorChangeEventData = (CalculatorEditorChangeEventData) data;
|
||||
|
||||
final String newText = editorChangeEventData.getNewValue().getText();
|
||||
final String oldText = editorChangeEventData.getOldValue().getText();
|
||||
|
||||
if (!newText.equals(oldText)) {
|
||||
evaluate(JsclOperation.numeric, editorChangeEventData.getNewValue().getText(), calculatorEventData.getSequenceId());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case display_state_changed:
|
||||
onDisplayStateChanged((CalculatorDisplayChangeEventData) data);
|
||||
break;
|
||||
|
||||
case constant_changed:
|
||||
final IConstant newConstant = ((Change<IConstant>) data).getNewValue();
|
||||
if (!newConstant.getName().equals(CalculatorVarsRegistry.ANS)) {
|
||||
evaluate();
|
||||
}
|
||||
break;
|
||||
|
||||
case constant_added:
|
||||
case constant_removed:
|
||||
case function_added:
|
||||
case function_changed:
|
||||
case function_removed:
|
||||
evaluate();
|
||||
break;
|
||||
|
||||
case engine_preferences_changed:
|
||||
evaluate(calculatorEventData.getSequenceId());
|
||||
break;
|
||||
|
||||
case use_constant:
|
||||
final IConstant constant = (IConstant) data;
|
||||
Locator.getInstance().getKeyboard().buttonPressed(constant.getName());
|
||||
break;
|
||||
|
||||
case use_operator:
|
||||
final Operator operator = (Operator) data;
|
||||
Locator.getInstance().getKeyboard().buttonPressed(operator.getName());
|
||||
break;
|
||||
|
||||
case use_function:
|
||||
final Function function = (Function) data;
|
||||
Locator.getInstance().getKeyboard().buttonPressed(function.getName());
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void onDisplayStateChanged(@Nonnull CalculatorDisplayChangeEventData displayChangeEventData) {
|
||||
final CalculatorDisplayViewState 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void doHistoryAction(@Nonnull HistoryAction historyAction) {
|
||||
final CalculatorHistory history = Locator.getInstance().getHistory();
|
||||
if (history.isActionAvailable(historyAction)) {
|
||||
final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState());
|
||||
if (newState != null) {
|
||||
setCurrentHistoryState(newState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CalculatorHistoryState getCurrentHistoryState() {
|
||||
return CalculatorHistoryState.newInstance(getEditor(), getDisplay());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentHistoryState(@Nonnull CalculatorHistoryState editorHistoryState) {
|
||||
editorHistoryState.setValuesFromHistory(getEditor(), getDisplay());
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* OTHER
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
@Nonnull
|
||||
private CalculatorEditor getEditor() {
|
||||
return Locator.getInstance().getEditor();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private CalculatorDisplay getDisplay() {
|
||||
return Locator.getInstance().getDisplay();
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 7:25 PM
|
||||
*/
|
||||
public interface CalculatorInput {
|
||||
|
||||
@Nonnull
|
||||
String getExpression();
|
||||
|
||||
@Nonnull
|
||||
JsclOperation getOperation();
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 7:26 PM
|
||||
*/
|
||||
public class CalculatorInputImpl implements CalculatorInput {
|
||||
|
||||
@Nonnull
|
||||
private String expression;
|
||||
|
||||
@Nonnull
|
||||
private JsclOperation operation;
|
||||
|
||||
public CalculatorInputImpl(@Nonnull String expression, @Nonnull JsclOperation operation) {
|
||||
this.expression = expression;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public JsclOperation getOperation() {
|
||||
return operation;
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/22/12
|
||||
* Time: 1:08 PM
|
||||
*/
|
||||
public interface CalculatorKeyboard {
|
||||
|
||||
boolean buttonPressed(@Nullable String text);
|
||||
|
||||
void roundBracketsButtonPressed();
|
||||
|
||||
void pasteButtonPressed();
|
||||
|
||||
void clearButtonPressed();
|
||||
|
||||
void copyButtonPressed();
|
||||
|
||||
void moveCursorLeft();
|
||||
|
||||
void moveCursorRight();
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static org.solovyev.android.calculator.NumeralBaseButtons.toggleNumericDigits;
|
||||
import static org.solovyev.android.calculator.Preferences.Gui.hideNumeralBaseDigits;
|
||||
import static org.solovyev.android.calculator.Preferences.Gui.showEqualsButton;
|
||||
import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.multiplicationSign;
|
||||
import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.numeralBase;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 25.09.12
|
||||
* Time: 12:25
|
||||
*/
|
||||
public class CalculatorKeyboardFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
@Nonnull
|
||||
private FragmentUi ui;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final SharedPreferences preferences = App.getPreferences();
|
||||
|
||||
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(preferences);
|
||||
if (!layout.isOptimized()) {
|
||||
ui = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_keyboard_mobile);
|
||||
} else {
|
||||
ui = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_keyboard);
|
||||
}
|
||||
|
||||
ui.onCreate(this);
|
||||
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return ui.onCreateView(this, inflater, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View root, Bundle savedInstanceState) {
|
||||
super.onViewCreated(root, savedInstanceState);
|
||||
ui.onViewCreated(this, root);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
this.ui.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
this.ui.onPause(this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
ui.onDestroyView(this);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
ui.onDestroy(this);
|
||||
App.getPreferences().unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||
if (numeralBase.isSameKey(key) || hideNumeralBaseDigits.isSameKey(key)) {
|
||||
toggleNumericDigits(this.getActivity(), preferences);
|
||||
}
|
||||
|
||||
if (showEqualsButton.isSameKey(key)) {
|
||||
CalculatorButtons.toggleEqualsButton(preferences, this.getActivity());
|
||||
}
|
||||
|
||||
if (multiplicationSign.isSameKey(key)) {
|
||||
CalculatorButtons.initMultiplicationButton(getView());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.math.MathType;
|
||||
import org.solovyev.common.text.Strings;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/22/12
|
||||
* Time: 1:08 PM
|
||||
*/
|
||||
public class CalculatorKeyboardImpl implements CalculatorKeyboard {
|
||||
|
||||
@Nonnull
|
||||
private final Calculator calculator;
|
||||
|
||||
public CalculatorKeyboardImpl(@Nonnull Calculator calculator) {
|
||||
this.calculator = calculator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean buttonPressed(@Nullable final String text) {
|
||||
if (!Strings.isEmpty(text)) {
|
||||
if (text == null) throw new AssertionError();
|
||||
|
||||
// process special buttons
|
||||
boolean processed = processSpecialButtons(text);
|
||||
|
||||
if (!processed) {
|
||||
processText(prepareText(text));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processText(@Nonnull String text) {
|
||||
int cursorPositionOffset = 0;
|
||||
final StringBuilder textToBeInserted = new StringBuilder(text);
|
||||
|
||||
final MathType.Result mathType = MathType.getType(text, 0, false);
|
||||
switch (mathType.getMathType()) {
|
||||
case function:
|
||||
textToBeInserted.append("()");
|
||||
cursorPositionOffset = -1;
|
||||
break;
|
||||
case operator:
|
||||
textToBeInserted.append("()");
|
||||
cursorPositionOffset = -1;
|
||||
break;
|
||||
case comma:
|
||||
textToBeInserted.append(" ");
|
||||
break;
|
||||
}
|
||||
|
||||
if (cursorPositionOffset == 0) {
|
||||
if (MathType.openGroupSymbols.contains(text)) {
|
||||
cursorPositionOffset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
final CalculatorEditor editor = Locator.getInstance().getEditor();
|
||||
editor.insert(textToBeInserted.toString(), cursorPositionOffset);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private String prepareText(@Nonnull String text) {
|
||||
if ("( )".equals(text) || "( )".equals(text)) {
|
||||
return "()";
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processSpecialButtons(@Nonnull String text) {
|
||||
boolean result = false;
|
||||
|
||||
final CalculatorSpecialButton button = CalculatorSpecialButton.getByActionCode(text);
|
||||
if (button != null) {
|
||||
button.onClick(this);
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void roundBracketsButtonPressed() {
|
||||
final CalculatorEditor editor = Locator.getInstance().getEditor();
|
||||
CalculatorEditorViewState viewState = editor.getViewState();
|
||||
|
||||
final int cursorPosition = viewState.getSelection();
|
||||
final String oldText = viewState.getText();
|
||||
|
||||
final StringBuilder newText = new StringBuilder(oldText.length() + 2);
|
||||
newText.append("(");
|
||||
newText.append(oldText.substring(0, cursorPosition));
|
||||
newText.append(")");
|
||||
newText.append(oldText.substring(cursorPosition));
|
||||
editor.setText(newText.toString(), cursorPosition + 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pasteButtonPressed() {
|
||||
final String text = Locator.getInstance().getClipboard().getText();
|
||||
if (text != null) {
|
||||
Locator.getInstance().getEditor().insert(text);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearButtonPressed() {
|
||||
Locator.getInstance().getEditor().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyButtonPressed() {
|
||||
final CalculatorDisplayViewState displayViewState = Locator.getInstance().getDisplay().getViewState();
|
||||
if (displayViewState.isValid()) {
|
||||
final CharSequence text = displayViewState.getText();
|
||||
if (!Strings.isEmpty(text)) {
|
||||
Locator.getInstance().getClipboard().setText(text);
|
||||
Locator.getInstance().getNotifier().showMessage(CalculatorMessage.newInfoMessage(CalculatorMessages.result_copied));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorLeft() {
|
||||
Locator.getInstance().getEditor().moveCursorLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorRight() {
|
||||
Locator.getInstance().getEditor().moveCursorRight();
|
||||
}
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 03.10.12
|
||||
* Time: 14:18
|
||||
*/
|
||||
public abstract class CalculatorListFragment extends ListFragment {
|
||||
|
||||
@Nonnull
|
||||
private final FragmentUi ui;
|
||||
|
||||
protected CalculatorListFragment(int layoutResId, int titleResId) {
|
||||
ui = CalculatorApplication.getInstance().createFragmentHelper(layoutResId, titleResId);
|
||||
}
|
||||
|
||||
protected CalculatorListFragment(@Nonnull CalculatorFragmentType fragmentType) {
|
||||
ui = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId());
|
||||
}
|
||||
|
||||
protected CalculatorListFragment(@Nonnull FragmentUi ui) {
|
||||
this.ui = ui;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
ui.onCreate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return ui.onCreateView(this, inflater, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
ui.onViewCreated(this, view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
this.ui.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
this.ui.onPause(this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
ui.onDestroyView(this);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
ui.onDestroy(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.history.CalculatorHistory;
|
||||
import org.solovyev.android.calculator.plot.CalculatorPlotter;
|
||||
import org.solovyev.android.calculator.text.TextProcessor;
|
||||
import org.solovyev.android.calculator.text.TextProcessorEditorResult;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: Solovyev_S
|
||||
* Date: 20.09.12
|
||||
* Time: 12:45
|
||||
*/
|
||||
public interface CalculatorLocator {
|
||||
|
||||
void init(@Nonnull Calculator calculator,
|
||||
@Nonnull CalculatorEngine engine,
|
||||
@Nonnull CalculatorClipboard clipboard,
|
||||
@Nonnull CalculatorNotifier notifier,
|
||||
@Nonnull CalculatorHistory history,
|
||||
@Nonnull CalculatorLogger logger,
|
||||
@Nonnull CalculatorPreferenceService preferenceService,
|
||||
@Nonnull CalculatorKeyboard keyboard,
|
||||
@Nonnull CalculatorPlotter plotter,
|
||||
@Nullable TextProcessor<TextProcessorEditorResult, String> editorTextProcessor);
|
||||
|
||||
@Nonnull
|
||||
Calculator getCalculator();
|
||||
|
||||
@Nonnull
|
||||
CalculatorEngine getEngine();
|
||||
|
||||
@Nonnull
|
||||
CalculatorDisplay getDisplay();
|
||||
|
||||
@Nonnull
|
||||
CalculatorEditor getEditor();
|
||||
|
||||
@Nonnull
|
||||
CalculatorKeyboard getKeyboard();
|
||||
|
||||
@Nonnull
|
||||
CalculatorClipboard getClipboard();
|
||||
|
||||
@Nonnull
|
||||
CalculatorNotifier getNotifier();
|
||||
|
||||
@Nonnull
|
||||
CalculatorHistory getHistory();
|
||||
|
||||
@Nonnull
|
||||
CalculatorLogger getLogger();
|
||||
|
||||
@Nonnull
|
||||
CalculatorPlotter getPlotter();
|
||||
|
||||
@Nonnull
|
||||
CalculatorPreferenceService getPreferenceService();
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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: 10/11/12
|
||||
* Time: 12:11 AM
|
||||
*/
|
||||
public interface CalculatorLogger {
|
||||
|
||||
void debug(@Nullable String tag, @Nonnull String message);
|
||||
|
||||
void debug(@Nullable String tag, @Nullable String message, @Nonnull Throwable e);
|
||||
|
||||
void error(@Nullable String tag, @Nullable String message, @Nonnull Throwable e);
|
||||
|
||||
void error(@Nullable String tag, @Nullable String message);
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 jscl.math.Generic;
|
||||
import jscl.text.ParseException;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/23/12
|
||||
* Time: 6:05 PM
|
||||
*/
|
||||
public interface CalculatorMathEngine {
|
||||
|
||||
@Nonnull
|
||||
String evaluate(@Nonnull String expression) throws ParseException;
|
||||
|
||||
@Nonnull
|
||||
String simplify(@Nonnull String expression) throws ParseException;
|
||||
|
||||
@Nonnull
|
||||
String elementary(@Nonnull String expression) throws ParseException;
|
||||
|
||||
@Nonnull
|
||||
Generic evaluateGeneric(@Nonnull String expression) throws ParseException;
|
||||
|
||||
@Nonnull
|
||||
Generic simplifyGeneric(@Nonnull String expression) throws ParseException;
|
||||
|
||||
@Nonnull
|
||||
Generic elementaryGeneric(@Nonnull String expression) throws ParseException;
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.solovyev.common.math.MathEntity;
|
||||
import org.solovyev.common.math.MathRegistry;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/30/11
|
||||
* Time: 1:02 AM
|
||||
*/
|
||||
public interface CalculatorMathRegistry<T extends MathEntity> extends MathRegistry<T> {
|
||||
|
||||
@Nullable
|
||||
String getDescription(@Nonnull String mathEntityName);
|
||||
|
||||
@Nullable
|
||||
String getCategory(@Nonnull T mathEntity);
|
||||
|
||||
void load();
|
||||
|
||||
void save();
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.Activity;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import org.solovyev.android.calculator.view.NumeralBaseConverterDialog;
|
||||
import org.solovyev.android.menu.LabeledMenuItem;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 4/23/12
|
||||
* Time: 2:25 PM
|
||||
*/
|
||||
enum CalculatorMenu implements LabeledMenuItem<MenuItem> {
|
||||
|
||||
settings(R.string.c_settings) {
|
||||
@Override
|
||||
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
|
||||
CalculatorActivityLauncher.showSettings(context);
|
||||
}
|
||||
},
|
||||
|
||||
history(R.string.c_history) {
|
||||
@Override
|
||||
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
|
||||
CalculatorActivityLauncher.showHistory(context);
|
||||
}
|
||||
},
|
||||
|
||||
plotter(R.string.cpp_plotter) {
|
||||
@Override
|
||||
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
|
||||
Locator.getInstance().getPlotter().plot();
|
||||
}
|
||||
},
|
||||
|
||||
conversion_tool(R.string.c_conversion_tool) {
|
||||
@Override
|
||||
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
|
||||
new NumeralBaseConverterDialog(null).show(context);
|
||||
}
|
||||
},
|
||||
|
||||
exit(R.string.c_exit) {
|
||||
@Override
|
||||
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
|
||||
if (context instanceof Activity) {
|
||||
((Activity) context).finish();
|
||||
} else {
|
||||
Log.e(CalculatorActivity.TAG, "Activity menu used with context");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
about(R.string.c_about) {
|
||||
@Override
|
||||
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
|
||||
CalculatorActivityLauncher.showAbout(context);
|
||||
}
|
||||
};
|
||||
|
||||
private final int captionResId;
|
||||
|
||||
private CalculatorMenu(int captionResId) {
|
||||
this.captionResId = captionResId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCaption(@Nonnull Context context) {
|
||||
return context.getString(captionResId);
|
||||
}
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.solovyev.common.msg.AbstractMessage;
|
||||
import org.solovyev.common.msg.Message;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 8:06 PM
|
||||
*/
|
||||
public class CalculatorMessage extends AbstractMessage {
|
||||
|
||||
public CalculatorMessage(@Nonnull String messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters) {
|
||||
super(messageCode, messageType, parameters);
|
||||
}
|
||||
|
||||
public CalculatorMessage(@Nonnull String messageCode, @Nonnull MessageType messageType, @Nonnull List<?> parameters) {
|
||||
super(messageCode, messageType, parameters);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Message newInfoMessage(@Nonnull String messageCode, @Nullable Object... parameters) {
|
||||
return new CalculatorMessage(messageCode, MessageType.info, parameters);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Message newWarningMessage(@Nonnull String messageCode, @Nullable Object... parameters) {
|
||||
return new CalculatorMessage(messageCode, MessageType.warning, parameters);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Message newErrorMessage(@Nonnull String messageCode, @Nullable Object... parameters) {
|
||||
return new CalculatorMessage(messageCode, MessageType.error, parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMessagePattern(@Nonnull Locale locale) {
|
||||
final ResourceBundle rb = CalculatorMessages.getBundle(locale);
|
||||
return rb.getString(getMessageCode());
|
||||
}
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.solovyev.common.msg.MessageType;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.solovyev.common.msg.MessageType.error;
|
||||
import static org.solovyev.common.msg.MessageType.info;
|
||||
import static org.solovyev.common.msg.MessageType.warning;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 8:10 PM
|
||||
*/
|
||||
public final class CalculatorMessages {
|
||||
|
||||
|
||||
/* Arithmetic error occurred: {0} */
|
||||
public static final String msg_001 = "msg_1";
|
||||
/* Too complex expression*/
|
||||
public static final String msg_002 = "msg_2";
|
||||
/* Too long execution time - check the expression*/
|
||||
public static final String msg_003 = "msg_3";
|
||||
/* Evaluation was cancelled*/
|
||||
public static final String msg_004 = "msg_4";
|
||||
/* No parameters are specified for function: {0}*/
|
||||
public static final String msg_005 = "msg_5";
|
||||
/* Infinite loop is detected in expression*/
|
||||
public static final String msg_006 = "msg_6";
|
||||
/**
|
||||
* Some data could not be loaded. Contact authors of application with information below.\n\nUnable to load:\n{0}
|
||||
*/
|
||||
public static final String msg_007 = "msg_7";
|
||||
/* Error */
|
||||
public static final String syntax_error = "syntax_error";
|
||||
/* Result copied to clipboard! */
|
||||
public static final String result_copied = "result_copied";
|
||||
/* Text copied to clipboard! */
|
||||
public static final String text_copied = "text_copied";
|
||||
/* Last calculated value */
|
||||
public static final String ans_description = "ans_description";
|
||||
|
||||
private CalculatorMessages() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ResourceBundle getBundle() {
|
||||
return getBundle(Locale.getDefault());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ResourceBundle getBundle(@Nonnull Locale locale) {
|
||||
try {
|
||||
return ResourceBundle.getBundle("org/solovyev/android/calculator/messages", locale);
|
||||
} catch (MissingResourceException e) {
|
||||
return ResourceBundle.getBundle("org/solovyev/android/calculator/messages", Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorMessage newErrorMessage(@Nonnull String messageCode, @Nullable Object... parameters) {
|
||||
return new CalculatorMessage(messageCode, error, parameters);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
static MessageType toMessageType(int messageLevel) {
|
||||
if (messageLevel < info.getMessageLevel()) {
|
||||
return info;
|
||||
} else if (messageLevel < warning.getMessageLevel()) {
|
||||
return warning;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.solovyev.common.msg.Message;
|
||||
import org.solovyev.common.msg.MessageType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/22/12
|
||||
* Time: 1:52 PM
|
||||
*/
|
||||
public interface CalculatorNotifier {
|
||||
|
||||
void showMessage(@Nonnull Message message);
|
||||
|
||||
void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nonnull List<Object> parameters);
|
||||
|
||||
void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters);
|
||||
|
||||
void showDebugMessage(@Nullable String tag, @Nonnull String message);
|
||||
}
|
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.solovyev.common.JBuilder;
|
||||
import org.solovyev.common.math.MathRegistry;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import jscl.math.operator.Operator;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 11/17/11
|
||||
* Time: 11:29 PM
|
||||
*/
|
||||
public class CalculatorOperatorsMathRegistry extends AbstractCalculatorMathRegistry<Operator, MathPersistenceEntity> {
|
||||
|
||||
@Nonnull
|
||||
private static final Map<String, String> substitutes = new HashMap<String, String>();
|
||||
@Nonnull
|
||||
private static final String OPERATOR_DESCRIPTION_PREFIX = "c_op_description_";
|
||||
|
||||
static {
|
||||
substitutes.put("Σ", "sum");
|
||||
substitutes.put("∏", "product");
|
||||
substitutes.put("∂", "derivative");
|
||||
substitutes.put("∫ab", "integral_ab");
|
||||
substitutes.put("∫", "integral");
|
||||
substitutes.put("Σ", "sum");
|
||||
}
|
||||
|
||||
public CalculatorOperatorsMathRegistry(@Nonnull MathRegistry<Operator> functionsRegistry,
|
||||
@Nonnull MathEntityDao<MathPersistenceEntity> mathEntityDao) {
|
||||
super(functionsRegistry, OPERATOR_DESCRIPTION_PREFIX, mathEntityDao);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected Map<String, String> getSubstitutes() {
|
||||
return substitutes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory(@Nonnull Operator operator) {
|
||||
for (OperatorCategory category : OperatorCategory.values()) {
|
||||
if (category.isInCategory(operator)) {
|
||||
return category.name();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
// not supported yet
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected JBuilder<? extends Operator> createBuilder(@Nonnull MathPersistenceEntity entity) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
// not supported yet
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MathPersistenceEntity transform(@Nonnull Operator entity) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected MathEntityPersistenceContainer<MathPersistenceEntity> createPersistenceContainer() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
*
|
||||
* STATIC
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 7:29 PM
|
||||
*/
|
||||
public interface CalculatorOutput {
|
||||
|
||||
@Nonnull
|
||||
String getStringResult();
|
||||
|
||||
@Nonnull
|
||||
JsclOperation getOperation();
|
||||
|
||||
|
||||
// null in case of empty expression
|
||||
@Nullable
|
||||
Generic getResult();
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.jscl.JsclOperation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.math.Generic;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/20/12
|
||||
* Time: 7:28 PM
|
||||
*/
|
||||
public class CalculatorOutputImpl implements CalculatorOutput {
|
||||
|
||||
@Nullable
|
||||
private Generic result;
|
||||
|
||||
@Nonnull
|
||||
private String stringResult;
|
||||
|
||||
@Nonnull
|
||||
private JsclOperation operation;
|
||||
|
||||
private CalculatorOutputImpl(@Nonnull String stringResult,
|
||||
@Nonnull JsclOperation operation,
|
||||
@Nullable Generic result) {
|
||||
this.stringResult = stringResult;
|
||||
this.operation = operation;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorOutput newOutput(@Nonnull String stringResult,
|
||||
@Nonnull JsclOperation operation,
|
||||
@Nonnull Generic result) {
|
||||
return new CalculatorOutputImpl(stringResult, operation, result);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorOutput newEmptyOutput(@Nonnull JsclOperation operation) {
|
||||
return new CalculatorOutputImpl("", operation, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public String getStringResult() {
|
||||
return stringResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public JsclOperation getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Generic getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.solovyev.common.msg.Message;
|
||||
import org.solovyev.common.msg.MessageLevel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/6/11
|
||||
* Time: 9:25 PM
|
||||
*/
|
||||
public class CalculatorParseException extends Exception implements Message {
|
||||
|
||||
@Nonnull
|
||||
private final Message message;
|
||||
|
||||
@Nonnull
|
||||
private final String expression;
|
||||
|
||||
@Nullable
|
||||
private final Integer position;
|
||||
|
||||
public CalculatorParseException(@Nonnull jscl.text.ParseException jsclParseException) {
|
||||
this.message = jsclParseException;
|
||||
this.expression = jsclParseException.getExpression();
|
||||
this.position = jsclParseException.getPosition();
|
||||
}
|
||||
|
||||
public CalculatorParseException(@Nullable Integer position,
|
||||
@Nonnull String expression,
|
||||
@Nonnull Message message) {
|
||||
this.message = message;
|
||||
this.expression = expression;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public CalculatorParseException(@Nonnull String expression,
|
||||
@Nonnull Message message) {
|
||||
this(null, expression, message);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getMessageCode() {
|
||||
return this.message.getMessageCode();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<Object> getParameters() {
|
||||
return this.message.getParameters();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public MessageLevel getMessageLevel() {
|
||||
return this.message.getMessageLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public String getLocalizedMessage() {
|
||||
return this.message.getLocalizedMessage(Locale.getDefault());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getLocalizedMessage(@Nonnull Locale locale) {
|
||||
return this.message.getLocalizedMessage(locale);
|
||||
}
|
||||
}
|
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.solovyev.common.JBuilder;
|
||||
import org.solovyev.common.math.MathRegistry;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import jscl.math.operator.Operator;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 11/19/11
|
||||
* Time: 1:48 PM
|
||||
*/
|
||||
public class CalculatorPostfixFunctionsRegistry extends AbstractCalculatorMathRegistry<Operator, MathPersistenceEntity> {
|
||||
|
||||
@Nonnull
|
||||
private static final Map<String, String> substitutes = new HashMap<String, String>();
|
||||
@Nonnull
|
||||
private static final String POSTFIX_FUNCTION_DESCRIPTION_PREFIX = "c_pf_description_";
|
||||
|
||||
static {
|
||||
substitutes.put("%", "percent");
|
||||
substitutes.put("!", "factorial");
|
||||
substitutes.put("!!", "double_factorial");
|
||||
substitutes.put("°", "degree");
|
||||
}
|
||||
|
||||
public CalculatorPostfixFunctionsRegistry(@Nonnull MathRegistry<Operator> functionsRegistry,
|
||||
@Nonnull MathEntityDao<MathPersistenceEntity> mathEntityDao) {
|
||||
super(functionsRegistry, POSTFIX_FUNCTION_DESCRIPTION_PREFIX, mathEntityDao);
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected Map<String, String> getSubstitutes() {
|
||||
return substitutes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory(@Nonnull Operator operator) {
|
||||
for (OperatorCategory category : OperatorCategory.values()) {
|
||||
if (category.isInCategory(operator)) {
|
||||
return category.name();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
// not supported yet
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected JBuilder<? extends Operator> createBuilder(@Nonnull MathPersistenceEntity entity) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
// not supported yet
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MathPersistenceEntity transform(@Nonnull Operator entity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected MathEntityPersistenceContainer<MathPersistenceEntity> createPersistenceContainer() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 jscl.AngleUnit;
|
||||
import jscl.NumeralBase;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 11/17/12
|
||||
* Time: 7:45 PM
|
||||
*/
|
||||
public interface CalculatorPreferenceService {
|
||||
|
||||
void setPreferredAngleUnits();
|
||||
|
||||
void setAngleUnits(@Nonnull AngleUnit angleUnit);
|
||||
|
||||
void setPreferredNumeralBase();
|
||||
|
||||
void setNumeralBase(@Nonnull NumeralBase numeralBase);
|
||||
|
||||
void checkPreferredPreferences(boolean force);
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public final class CalculatorReceiver extends BroadcastReceiver {
|
||||
|
||||
public static final String ACTION_BUTTON_ID_EXTRA = "buttonId";
|
||||
public static final String ACTION_BUTTON_PRESSED = "org.solovyev.android.calculator.BUTTON_PRESSED";
|
||||
|
||||
@Nonnull
|
||||
public static Intent newButtonClickedIntent(@Nonnull Context context, @Nonnull CalculatorButton button) {
|
||||
final Intent intent = new Intent(context, CalculatorReceiver.class);
|
||||
intent.setAction(ACTION_BUTTON_PRESSED);
|
||||
intent.putExtra(ACTION_BUTTON_ID_EXTRA, button.getButtonId());
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
|
||||
if (ACTION_BUTTON_PRESSED.equals(action)) {
|
||||
final int buttonId = intent.getIntExtra(ACTION_BUTTON_ID_EXTRA, 0);
|
||||
|
||||
final CalculatorButton button = CalculatorButton.getById(buttonId);
|
||||
if (button != null) {
|
||||
button.onClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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: 1/4/12
|
||||
* Time: 1:23 AM
|
||||
*/
|
||||
public final class CalculatorSecurity {
|
||||
|
||||
private CalculatorSecurity() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static String getPK() {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A");
|
||||
result.append("MIIBCgKCAQEAquP2a7dEhTaJEQeXtSyreH5dCmTDOd");
|
||||
result.append("dElCfg0ijOeB8JTxBiJTXLWnLA0kMaT/sRXswUaYI61YCQOoik82");
|
||||
result.append("qrFH7W4+OFtiLb8WGX+YPEpQQ/IBZu9qm3xzS9Nolu79EBff0/CLa1FuT9RtjO");
|
||||
result.append("iTW8Q0VP9meQdJEkfqJEyVCgHain+MGoQaRXI45EzkYmkz8TBx6X6aJF5NBAXnAWeyD0wPX1");
|
||||
result.append("uedHH7+LgLcjnPVw82YjyJSzYnaaD2GX0Y7PGoFe6J5K4yJGGX5mih45pe2HWcG5lAkQhu1uX2hCcCBdF3");
|
||||
result.append("W7paRq9mJvCsbn+BNTh9gq8QKui0ltmiWpa5U+/9L+FQIDAQAB");
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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.solovyev.common.text.Strings;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/20/12
|
||||
* Time: 2:05 PM
|
||||
*/
|
||||
public enum CalculatorSpecialButton {
|
||||
|
||||
history("history") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_history, null);
|
||||
}
|
||||
},
|
||||
history_detached("history_detached") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_history_detached, null);
|
||||
}
|
||||
},
|
||||
cursor_right("▷") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
keyboard.moveCursorRight();
|
||||
}
|
||||
},
|
||||
cursor_left("◁") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
keyboard.moveCursorLeft();
|
||||
}
|
||||
},
|
||||
settings("settings") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_settings, null);
|
||||
}
|
||||
},
|
||||
|
||||
settings_detached("settings_detached") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_settings_detached, null);
|
||||
}
|
||||
},
|
||||
|
||||
like("like") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_like_dialog, null);
|
||||
}
|
||||
},
|
||||
erase("erase") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getEditor().erase();
|
||||
}
|
||||
},
|
||||
paste("paste") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
keyboard.pasteButtonPressed();
|
||||
}
|
||||
},
|
||||
copy("copy") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
keyboard.copyButtonPressed();
|
||||
}
|
||||
},
|
||||
equals("=") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
final Calculator calculator = Locator.getInstance().getCalculator();
|
||||
if (!calculator.isCalculateOnFly()) {
|
||||
// no automatic calculations are => equals button must be used to calculate
|
||||
calculator.evaluate();
|
||||
return;
|
||||
}
|
||||
|
||||
final CalculatorDisplayViewState displayViewState = Locator.getInstance().getDisplay().getViewState();
|
||||
if (displayViewState.isValid()) {
|
||||
final CharSequence text = displayViewState.getText();
|
||||
if (!Strings.isEmpty(text)) {
|
||||
Locator.getInstance().getEditor().setText(text.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
clear("clear") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
keyboard.clearButtonPressed();
|
||||
}
|
||||
},
|
||||
functions("functions") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_functions, null);
|
||||
}
|
||||
},
|
||||
functions_detached("functions_detached") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_functions_detached, null);
|
||||
}
|
||||
},
|
||||
open_app("open_app") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.open_app, null);
|
||||
}
|
||||
},
|
||||
vars("vars") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_vars, null);
|
||||
}
|
||||
},
|
||||
vars_detached("vars_detached") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_vars_detached, null);
|
||||
}
|
||||
},
|
||||
operators("operators") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_operators, null);
|
||||
}
|
||||
},
|
||||
|
||||
operators_detached("operators_detached") {
|
||||
@Override
|
||||
public void onClick(@Nonnull CalculatorKeyboard keyboard) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_operators_detached, null);
|
||||
}
|
||||
};
|
||||
|
||||
@Nonnull
|
||||
private static Map<String, CalculatorSpecialButton> buttonsByActionCodes = new HashMap<>();
|
||||
|
||||
@Nonnull
|
||||
private final String actionCode;
|
||||
|
||||
CalculatorSpecialButton(@Nonnull String actionCode) {
|
||||
this.actionCode = actionCode;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CalculatorSpecialButton getByActionCode(@Nonnull String actionCode) {
|
||||
initButtonsByActionCodesMap();
|
||||
return buttonsByActionCodes.get(actionCode);
|
||||
}
|
||||
|
||||
private static void initButtonsByActionCodesMap() {
|
||||
if (buttonsByActionCodes.isEmpty()) {
|
||||
// if not initialized
|
||||
|
||||
final CalculatorSpecialButton[] specialButtons = values();
|
||||
|
||||
final Map<String, CalculatorSpecialButton> localButtonsByActionCodes = new HashMap<String, CalculatorSpecialButton>(specialButtons.length);
|
||||
for (CalculatorSpecialButton specialButton : specialButtons) {
|
||||
localButtonsByActionCodes.put(specialButton.getActionCode(), specialButton);
|
||||
}
|
||||
|
||||
buttonsByActionCodes = localButtonsByActionCodes;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getActionCode() {
|
||||
return actionCode;
|
||||
}
|
||||
|
||||
public abstract void onClick(@Nonnull CalculatorKeyboard keyboard);
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import jscl.math.Generic;
|
||||
import jscl.math.function.Constant;
|
||||
import jscl.math.function.IConstant;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/22/12
|
||||
* Time: 7:13 PM
|
||||
*/
|
||||
public final class CalculatorUtils {
|
||||
|
||||
static final long FIRST_ID = 0;
|
||||
|
||||
private CalculatorUtils() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CalculatorEventData createFirstEventDataId() {
|
||||
return CalculatorEventDataImpl.newInstance(FIRST_ID, FIRST_ID);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Set<Constant> getNotSystemConstants(@Nonnull Generic expression) {
|
||||
final Set<Constant> notSystemConstants = new HashSet<Constant>();
|
||||
|
||||
for (Constant constant : expression.getConstants()) {
|
||||
IConstant var = Locator.getInstance().getEngine().getVarsRegistry().get(constant.getName());
|
||||
if (var != null && !var.isSystem() && !var.isDefined()) {
|
||||
notSystemConstants.add(constant);
|
||||
}
|
||||
}
|
||||
|
||||
return notSystemConstants;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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.solovyev.android.calculator.model.MathEntityBuilder;
|
||||
import org.solovyev.android.calculator.model.Var;
|
||||
import org.solovyev.android.calculator.model.Vars;
|
||||
import org.solovyev.common.JBuilder;
|
||||
import org.solovyev.common.math.MathEntity;
|
||||
import org.solovyev.common.math.MathRegistry;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import jscl.math.function.IConstant;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 9/29/11
|
||||
* Time: 4:57 PM
|
||||
*/
|
||||
public class CalculatorVarsRegistry extends AbstractCalculatorMathRegistry<IConstant, Var> {
|
||||
|
||||
@Nonnull
|
||||
public static final String ANS = "ans";
|
||||
|
||||
@Nonnull
|
||||
private static final Map<String, String> substitutes = new HashMap<String, String>();
|
||||
|
||||
static {
|
||||
substitutes.put("π", "pi");
|
||||
substitutes.put("Π", "PI");
|
||||
substitutes.put("∞", "inf");
|
||||
substitutes.put("h", "h_reduced");
|
||||
substitutes.put("NaN", "nan");
|
||||
}
|
||||
|
||||
public CalculatorVarsRegistry(@Nonnull MathRegistry<IConstant> mathRegistry,
|
||||
@Nonnull MathEntityDao<Var> mathEntityDao) {
|
||||
super(mathRegistry, "c_var_description_", mathEntityDao);
|
||||
}
|
||||
|
||||
public static <T extends MathEntity> void saveVariable(@Nonnull CalculatorMathRegistry<T> registry,
|
||||
@Nonnull MathEntityBuilder<? extends T> builder,
|
||||
@Nullable T editedInstance,
|
||||
@Nonnull Object source, boolean save) {
|
||||
final T addedVar = registry.add(builder);
|
||||
|
||||
if (save) {
|
||||
registry.save();
|
||||
}
|
||||
|
||||
if (editedInstance == null) {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.constant_added, addedVar, source);
|
||||
} else {
|
||||
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.constant_changed, ChangeImpl.newInstance(editedInstance, addedVar), source);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected Map<String, String> getSubstitutes() {
|
||||
return substitutes;
|
||||
}
|
||||
|
||||
public synchronized void load() {
|
||||
super.load();
|
||||
|
||||
tryToAddAuxVar("x");
|
||||
tryToAddAuxVar("y");
|
||||
tryToAddAuxVar("t");
|
||||
tryToAddAuxVar("j");
|
||||
|
||||
|
||||
/*Log.d(AndroidVarsRegistry.class.getName(), vars.size() + " variables registered!");
|
||||
for (Var var : vars) {
|
||||
Log.d(AndroidVarsRegistry.class.getName(), var.toString());
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected JBuilder<? extends IConstant> createBuilder(@Nonnull Var entity) {
|
||||
return new Var.Builder(entity);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected MathEntityPersistenceContainer<Var> createPersistenceContainer() {
|
||||
return new Vars();
|
||||
}
|
||||
|
||||
private void tryToAddAuxVar(@Nonnull String name) {
|
||||
if (!contains(name)) {
|
||||
add(new Var.Builder(name, (String) null));
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected Var transform(@Nonnull IConstant entity) {
|
||||
if (entity instanceof Var) {
|
||||
return (Var) entity;
|
||||
} else {
|
||||
return new Var.Builder(entity).create();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(@Nonnull String mathEntityName) {
|
||||
final IConstant var = get(mathEntityName);
|
||||
if (var != null && !var.isSystem()) {
|
||||
return var.getDescription();
|
||||
} else {
|
||||
return super.getDescription(mathEntityName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory(@Nonnull IConstant var) {
|
||||
for (VarCategory category : VarCategory.values()) {
|
||||
if (category.isInCategory(var)) {
|
||||
return category.name();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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: 10/1/12
|
||||
* Time: 11:16 PM
|
||||
*/
|
||||
public interface Change<T> {
|
||||
|
||||
@Nonnull
|
||||
T getOldValue();
|
||||
|
||||
@Nonnull
|
||||
T getNewValue();
|
||||
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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: 10/1/12
|
||||
* Time: 11:18 PM
|
||||
*/
|
||||
public class ChangeImpl<T> implements Change<T> {
|
||||
|
||||
@Nonnull
|
||||
private T oldValue;
|
||||
|
||||
@Nonnull
|
||||
private T newValue;
|
||||
|
||||
private ChangeImpl() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static <T> Change<T> newInstance(@Nonnull T oldValue, @Nonnull T newValue) {
|
||||
final ChangeImpl<T> result = new ChangeImpl<T>();
|
||||
|
||||
result.oldValue = oldValue;
|
||||
result.newValue = newValue;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public T getOldValue() {
|
||||
return this.oldValue;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public T getNewValue() {
|
||||
return this.newValue;
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.solovyev.common.JPredicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* User: serso
|
||||
* Date: 10/3/11
|
||||
* Time: 12:54 AM
|
||||
*/
|
||||
public class CharacterAtPositionFinder implements JPredicate<Character> {
|
||||
|
||||
@Nonnull
|
||||
private final String targetString;
|
||||
private int i;
|
||||
|
||||
public CharacterAtPositionFinder(@Nonnull String targetString, int i) {
|
||||
this.targetString = targetString;
|
||||
this.i = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(@Nullable Character s) {
|
||||
return s != null && s.equals(targetString.charAt(i));
|
||||
}
|
||||
|
||||
public void setI(int i) {
|
||||
this.i = i;
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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: Solovyev_S
|
||||
* Date: 24.09.12
|
||||
* Time: 16:12
|
||||
*/
|
||||
public interface ConversionFailure {
|
||||
|
||||
@Nonnull
|
||||
Exception getException();
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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: Solovyev_S
|
||||
* Date: 24.09.12
|
||||
* Time: 16:12
|
||||
*/
|
||||
public class ConversionFailureImpl implements ConversionFailure {
|
||||
|
||||
@Nonnull
|
||||
private Exception exception;
|
||||
|
||||
public ConversionFailureImpl(@Nonnull Exception exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Exception getException() {
|
||||
return this.exception;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user