Numeral bases

This commit is contained in:
serso
2016-02-11 16:26:18 +01:00
parent 9e10640e54
commit 7350a9ed0c
23 changed files with 442 additions and 803 deletions

View File

@@ -30,12 +30,14 @@ import android.util.Log;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.calculations.CalculationCancelledEvent;
import org.solovyev.android.calculator.calculations.CalculationFailedEvent;
import org.solovyev.android.calculator.calculations.CalculationFinishedEvent;
import org.solovyev.android.calculator.calculations.ConversionFailedEvent;
import org.solovyev.android.calculator.calculations.ConversionFinishedEvent;
import org.solovyev.android.calculator.functions.FunctionsRegistry;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.units.CalculatorNumeralBase;
import org.solovyev.android.calculator.variables.CppVariable;
import org.solovyev.common.msg.ListMessageRegistry;
import org.solovyev.common.msg.Message;
@@ -43,8 +45,17 @@ 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 jscl.JsclArithmeticException;
import jscl.JsclMathEngine;
import jscl.NumeralBase;
import jscl.NumeralBaseException;
import jscl.math.Generic;
import jscl.math.function.Constants;
import jscl.math.function.IConstant;
import jscl.text.ParseInterruptedException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -58,15 +69,6 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import jscl.JsclArithmeticException;
import jscl.JsclMathEngine;
import jscl.NumeralBase;
import jscl.NumeralBaseException;
import jscl.math.Generic;
import jscl.math.function.Constants;
import jscl.math.function.IConstant;
import jscl.text.ParseInterruptedException;
@Singleton
public class Calculator implements SharedPreferences.OnSharedPreferenceChangeListener {
@@ -111,28 +113,12 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis
@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).getValue();
} catch (ParseException e) {
// ok, problems while processing occurred
}
}
result = Conversions.doConversion(CalculatorNumeralBase.getConverter(), fromString, CalculatorNumeralBase.valueOf(from), CalculatorNumeralBase.valueOf(to));
} else {
result = generic.toString();
private static String convert(@Nonnull Generic generic, @Nonnull NumeralBase to) throws ConversionException {
final BigInteger value = generic.toBigInteger();
if (value == null) {
throw new ConversionException();
}
return result;
return to.toString(value);
}
@Nonnull
@@ -142,12 +128,6 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis
}
@Nonnull
private CalculatorEventData nextEventData(@Nonnull Object source) {
long eventId = nextSequence();
return CalculatorEventDataImpl.newInstance(eventId, eventId, source);
}
@Nonnull
private CalculatorEventData nextEventData(@Nonnull Long sequenceId) {
long eventId = nextSequence();
return CalculatorEventDataImpl.newInstance(eventId, sequenceId);
@@ -211,15 +191,6 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis
}
}
@Nonnull
private CalculatorConversionEventData newConversionEventData(@Nonnull Long sequenceId,
@Nonnull Generic value,
@Nonnull NumeralBase from,
@Nonnull NumeralBase to,
@Nonnull DisplayState displayViewState) {
return CalculatorConversionEventDataImpl.newInstance(nextEventData(sequenceId), value, from, to, displayViewState);
}
private void evaluateAsync(long sequence, @Nonnull JsclOperation o, @Nonnull String e) {
evaluateAsync(sequence, o, e, new ListMessageRegistry());
}
@@ -240,7 +211,7 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis
pe = prepare(e);
try {
Locator.getInstance().getEngine().getMathEngine().setMessageRegistry(mr);
mathEngine.setMessageRegistry(mr);
final Generic result = o.evaluateGeneric(pe.value, mathEngine);
@@ -325,38 +296,33 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis
bus.post(new CalculationFailedEvent(operation, e, sequence, parseException));
}
@Nonnull
public CalculatorEventData convert(@Nonnull final Generic value,
@Nonnull final NumeralBase to) {
final CalculatorEventData eventDataId = nextEventData();
final DisplayState displayViewState = App.getDisplay().getState();
final NumeralBase from = Locator.getInstance().getEngine().getMathEngine().getNumeralBase();
public void convert(@Nonnull final DisplayState state, @Nonnull final NumeralBase to) {
final Generic value = state.getResult();
Check.isNotNull(value);
final NumeralBase from = mathEngine.getNumeralBase();
if (from == to) {
return;
}
background.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);
final String result = convert(value, to);
bus.post(new ConversionFinishedEvent(result, to, state));
} catch (ConversionException e) {
fireCalculatorEvent(newConversionEventData(sequenceId, value, from, to, displayViewState), CalculatorEventType.conversion_failed, new ConversionFailureImpl(e));
bus.post(new ConversionFailedEvent(state));
}
}
});
return eventDataId;
}
public boolean isConversionPossible(@Nonnull Generic generic, NumeralBase from, @Nonnull NumeralBase to) {
public boolean canConvert(@Nonnull Generic generic, @NonNull NumeralBase from, @Nonnull NumeralBase to) {
if(from == to) {
return false;
}
try {
doConversion(generic, from, to);
convert(generic, to);
return true;
} catch (ConversionException e) {
return false;
@@ -389,15 +355,6 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis
return eventData;
}
@Nonnull
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;
}
@Subscribe
public void onEditorChanged(@Nonnull Editor.ChangedEvent e) {
if (!calculateOnFly) {
@@ -476,4 +433,5 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis
public static long nextSequence() {
return SEQUENCER.incrementAndGet();
}
}

View File

@@ -1,126 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import javax.annotation.Nonnull;
import 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 DisplayState displayState;
private CalculatorConversionEventDataImpl() {
}
@Nonnull
public static CalculatorConversionEventData newInstance(@Nonnull CalculatorEventData calculatorEventData,
@Nonnull Generic value,
@Nonnull NumeralBase from,
@Nonnull NumeralBase to,
@Nonnull DisplayState 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 DisplayState 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;
}
}

View File

@@ -39,8 +39,6 @@ public enum CalculatorEventType {
*
**********************************************************************
*/
conversion_started,
// @Nonnull String conversion result
conversion_result,

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import javax.annotation.Nonnull;
/**
* User: Solovyev_S
* Date: 24.09.12
* Time: 16:12
*/
public interface ConversionFailure {
@Nonnull
Exception getException();
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import 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;
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import android.content.Context;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.menu.AMenuItem;
import javax.annotation.Nonnull;
import jscl.NumeralBase;
import jscl.math.Generic;
/**
* User: serso
* Date: 9/21/12
* Time: 12:11 AM
*/
enum ConversionMenuItem implements AMenuItem<DisplayState> {
convert_to_bin(NumeralBase.bin),
convert_to_dec(NumeralBase.dec),
convert_to_hex(NumeralBase.hex);
@Nonnull
private final NumeralBase toNumeralBase;
ConversionMenuItem(@Nonnull NumeralBase toNumeralBase) {
this.toNumeralBase = toNumeralBase;
}
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
boolean result = false;
if (operation == JsclOperation.numeric) {
if (generic.getConstants().isEmpty()) {
// conversion possible => return true
final NumeralBase fromNumeralBase = Locator.getInstance().getEngine().getMathEngine().getNumeralBase();
if (fromNumeralBase != toNumeralBase) {
result = Locator.getInstance().getCalculator().isConversionPossible(generic, fromNumeralBase, this.toNumeralBase);
}
}
}
return result;
}
@Override
public void onClick(@Nonnull DisplayState data, @Nonnull Context context) {
final Generic result = data.getResult();
if (result != null) {
Locator.getInstance().getCalculator().convert(result, this.toNumeralBase);
}
}
}

View File

@@ -22,17 +22,17 @@
package org.solovyev.android.calculator;
import jscl.NumeralBase;
import org.solovyev.android.calculator.keyboard.KeyboardUi;
import org.solovyev.android.calculator.units.CalculatorNumeralBase;
import org.solovyev.android.views.dragbutton.DirectionDragButton;
import org.solovyev.android.views.dragbutton.DragDirection;
import jscl.NumeralBase;
import javax.annotation.Nonnull;
public enum AndroidNumeralBase {
public enum CppNumeralBase {
bin(CalculatorNumeralBase.bin) {
bin(NumeralBase.bin) {
@Override
public void toggleButtons(boolean show, @Nonnull KeyboardUi ui) {
toggleButton(show, ui.button0);
@@ -40,7 +40,7 @@ public enum AndroidNumeralBase {
}
},
oct(CalculatorNumeralBase.oct) {
oct(NumeralBase.oct) {
@Override
public void toggleButtons(boolean show, @Nonnull KeyboardUi ui) {
bin.toggleButtons(show, ui);
@@ -53,7 +53,7 @@ public enum AndroidNumeralBase {
}
},
dec(CalculatorNumeralBase.dec) {
dec(NumeralBase.dec) {
@Override
public void toggleButtons(boolean show, @Nonnull KeyboardUi ui) {
oct.toggleButtons(show, ui);
@@ -62,7 +62,7 @@ public enum AndroidNumeralBase {
}
},
hex(CalculatorNumeralBase.hex) {
hex(NumeralBase.hex) {
@Override
public void toggleButtons(boolean show, @Nonnull KeyboardUi ui) {
dec.toggleButtons(show, ui);
@@ -81,17 +81,17 @@ public enum AndroidNumeralBase {
};
@Nonnull
private final CalculatorNumeralBase calculatorNumeralBase;
public final NumeralBase numeralBase;
AndroidNumeralBase(@Nonnull CalculatorNumeralBase calculatorNumeralBase) {
this.calculatorNumeralBase = calculatorNumeralBase;
CppNumeralBase(@Nonnull NumeralBase numeralBase) {
this.numeralBase = numeralBase;
}
@Nonnull
public static AndroidNumeralBase valueOf(@Nonnull NumeralBase nb) {
for (AndroidNumeralBase androidNumeralBase : values()) {
if (androidNumeralBase.calculatorNumeralBase.getNumeralBase() == nb) {
return androidNumeralBase;
public static CppNumeralBase valueOf(@Nonnull NumeralBase nb) {
for (CppNumeralBase cppNumeralBase : values()) {
if (cppNumeralBase.numeralBase == nb) {
return cppNumeralBase;
}
}
@@ -104,9 +104,4 @@ public enum AndroidNumeralBase {
button.setShowText(show);
button.invalidate();
}
@Nonnull
public NumeralBase getNumeralBase() {
return calculatorNumeralBase.getNumeralBase();
}
}

View File

@@ -22,19 +22,9 @@
package org.solovyev.android.calculator;
import static org.solovyev.android.calculator.BaseFragment.addMenu;
import static org.solovyev.android.calculator.CalculatorEventType.conversion_failed;
import static org.solovyev.android.calculator.CalculatorEventType.conversion_result;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.support.v7.app.AlertDialog;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.support.annotation.NonNull;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
@@ -43,11 +33,11 @@ import org.solovyev.android.Check;
import org.solovyev.android.calculator.calculations.CalculationCancelledEvent;
import org.solovyev.android.calculator.calculations.CalculationFailedEvent;
import org.solovyev.android.calculator.calculations.CalculationFinishedEvent;
import org.solovyev.android.calculator.calculations.ConversionFailedEvent;
import org.solovyev.android.calculator.calculations.ConversionFinishedEvent;
import org.solovyev.android.calculator.errors.FixableErrorsActivity;
import org.solovyev.android.calculator.jscl.JsclOperation;
import dagger.Lazy;
import jscl.math.Generic;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -55,10 +45,8 @@ import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class Display implements CalculatorEventListener, View.OnClickListener, View.OnCreateContextMenuListener, MenuItem.OnMenuItemClickListener {
public class Display {
@Nonnull
private final CalculatorEventHolder lastEvent;
@Nonnull
private final Bus bus;
@Inject
@@ -75,10 +63,8 @@ public class Display implements CalculatorEventListener, View.OnClickListener, V
private DisplayState state = DisplayState.empty();
@Inject
public Display(@Nonnull Calculator calculator, @Nonnull Bus bus) {
public Display(@Nonnull Bus bus) {
this.bus = bus;
lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
calculator.addCalculatorEventListener(this);
bus.register(this);
}
@@ -87,12 +73,13 @@ public class Display implements CalculatorEventListener, View.OnClickListener, V
copy();
}
private void copy() {
void copy() {
if (!state.valid) {
return;
}
clipboard.get().setText(state.text);
notifier.get().showMessage(CalculatorMessage.newInfoMessage(CalculatorMessages.result_copied));
notifier.get().showMessage(
CalculatorMessage.newInfoMessage(CalculatorMessages.result_copied));
}
@Subscribe
@@ -124,6 +111,22 @@ public class Display implements CalculatorEventListener, View.OnClickListener, V
setState(DisplayState.createError(e.operation, error, e.sequence));
}
@Subscribe
public void onConversionFinished(@NonNull ConversionFinishedEvent e) {
if (e.state.sequence != state.sequence) return;
final String result = e.numeralBase.getJsclPrefix() + e.result;
setState(DisplayState.createValid(e.state.getOperation(), e.state.getResult(), result,
e.state.sequence));
}
@Subscribe
public void onConversionFailed(@NonNull ConversionFailedEvent e) {
if (e.state.sequence != state.sequence) return;
setState(DisplayState.createError(e.state.getOperation(),
CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error),
e.state.sequence));
}
public void clearView(@Nonnull DisplayView view) {
Check.isMainThread();
if (this.view != view) {
@@ -135,7 +138,6 @@ public class Display implements CalculatorEventListener, View.OnClickListener, V
public void setView(@Nonnull DisplayView view) {
Check.isMainThread();
this.view = view;
this.view.setOnClickListener(this);
this.view.setState(state);
}
@@ -156,127 +158,6 @@ public class Display implements CalculatorEventListener, View.OnClickListener, V
bus.post(new ChangedEvent(oldState, newState));
}
@Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData,
@Nonnull CalculatorEventType calculatorEventType,
@Nullable Object data) {
if (calculatorEventType.isOfType(conversion_result, conversion_failed)) {
final CalculatorEventHolder.Result result = lastEvent.apply(calculatorEventData);
if (result.isNewAfter()) {
switch (calculatorEventType) {
case conversion_failed:
processConversationFailed((CalculatorConversionEventData) calculatorEventData);
break;
case conversion_result:
processConversationResult((CalculatorConversionEventData) calculatorEventData, (String) data);
break;
}
}
}
}
private void processConversationFailed(@Nonnull CalculatorConversionEventData calculatorEventData) {
setState(DisplayState.createError(calculatorEventData.getDisplayState().getOperation(), CalculatorMessages.getBundle().getString(CalculatorMessages.syntax_error), calculatorEventData.getSequenceId()));
}
private void processConversationResult(@Nonnull CalculatorConversionEventData calculatorEventData, @Nonnull String result) {
// add prefix
if (calculatorEventData.getFromNumeralBase() != calculatorEventData.getToNumeralBase()) {
result = calculatorEventData.getToNumeralBase().getJsclPrefix() + result;
}
final DisplayState displayState = calculatorEventData.getDisplayState();
setState(DisplayState.createValid(displayState.getOperation(), displayState.getResult(), result, calculatorEventData.getSequenceId()));
}
@Override
public void onClick(View v) {
if (state.valid) {
v.setOnCreateContextMenuListener(this);
v.showContextMenu();
v.setOnCreateContextMenuListener(null);
} else {
showEvaluationError(v.getContext(), state.text);
}
}
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, App.getTheme().alertDialogTheme)
.setPositiveButton(R.string.c_cancel, null)
.setView(errorMessageView);
builder.create().show();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
if (!state.valid) {
return;
}
addMenu(menu, R.string.c_copy, this);
final Generic result = state.getResult();
final JsclOperation operation = state.getOperation();
if (result != null) {
if (ConversionMenuItem.convert_to_bin.isItemVisibleFor(result, operation)) {
addMenu(menu, R.string.convert_to_bin, this);
}
if (ConversionMenuItem.convert_to_dec.isItemVisibleFor(result, operation)) {
addMenu(menu, R.string.convert_to_dec, this);
}
if (ConversionMenuItem.convert_to_hex.isItemVisibleFor(result, operation)) {
addMenu(menu, R.string.convert_to_hex, this);
}
if (operation == JsclOperation.numeric && result.getConstants().isEmpty()) {
addMenu(menu, R.string.c_convert, this);
}
if (Locator.getInstance().getPlotter().isPlotPossibleFor(result)) {
addMenu(menu, R.string.c_plot, this);
}
}
}
@Override
public boolean onMenuItemClick(MenuItem item) {
final Generic result = state.getResult();
switch (item.getItemId()) {
case R.string.c_copy:
copy();
return true;
case R.string.convert_to_bin:
ConversionMenuItem.convert_to_bin.onClick(state, App.getApplication());
return true;
case R.string.convert_to_dec:
ConversionMenuItem.convert_to_dec.onClick(state, App.getApplication());
return true;
case R.string.convert_to_hex:
ConversionMenuItem.convert_to_hex.onClick(state, App.getApplication());
return true;
case R.string.c_convert:
if (result != null) {
// FIXME: 2016-02-10
//new NumeralBaseConverterDialog(result.toString()).show(App.getApplication());
}
return true;
case R.string.c_plot:
if (result != null) {
Locator.getInstance().getPlotter().plot(result);
}
return true;
default:
return false;
}
}
public static class CopyOperation {
}

View File

@@ -22,18 +22,65 @@
package org.solovyev.android.calculator;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v7.app.AlertDialog;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.squareup.otto.Bus;
import org.solovyev.android.calculator.converter.ConverterFragment;
import org.solovyev.android.calculator.jscl.JsclOperation;
import butterknife.Bind;
import butterknife.ButterKnife;
import jscl.NumeralBase;
import jscl.math.Generic;
import javax.annotation.Nonnull;
import javax.inject.Inject;
public class DisplayFragment extends BaseFragment {
public class DisplayFragment extends BaseFragment implements View.OnClickListener,
MenuItem.OnMenuItemClickListener {
private enum ConversionMenuItem {
to_bin(NumeralBase.bin, R.string.convert_to_bin),
to_dec(NumeralBase.dec, R.string.convert_to_dec),
to_hex(NumeralBase.hex, R.string.convert_to_hex);
@Nonnull
public final NumeralBase toNumeralBase;
public final int title;
ConversionMenuItem(@Nonnull NumeralBase toNumeralBase, @StringRes int title) {
this.toNumeralBase = toNumeralBase;
this.title = title;
}
@Nullable
public static ConversionMenuItem getByTitle(int title) {
switch (title) {
case R.string.convert_to_bin:
return to_bin;
case R.string.convert_to_dec:
return to_dec;
case R.string.convert_to_hex:
return to_hex;
}
return null;
}
}
@Bind(R.id.calculator_display)
DisplayView displayView;
@@ -41,12 +88,10 @@ public class DisplayFragment extends BaseFragment {
SharedPreferences preferences;
@Inject
Display display;
@Override
protected void inject(@Nonnull AppComponent component) {
super.inject(component);
component.inject(this);
}
@Inject
Bus bus;
@Inject
Calculator calculator;
@Nonnull
@Override
@@ -60,10 +105,18 @@ public class DisplayFragment extends BaseFragment {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
protected void inject(@Nonnull AppComponent component) {
super.inject(component);
component.inject(this);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = super.onCreateView(inflater, container, savedInstanceState);
ButterKnife.bind(this, view);
display.setView(displayView);
displayView.setOnClickListener(this);
return view;
}
@@ -72,4 +125,115 @@ public class DisplayFragment extends BaseFragment {
display.clearView(displayView);
super.onDestroyView();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
final DisplayState state = display.getState();
if (!state.valid) {
return;
}
addMenu(menu, R.string.c_copy, this);
final Generic result = state.getResult();
final JsclOperation operation = state.getOperation();
if (result != null) {
if (operation == JsclOperation.numeric && result.getConstants().isEmpty()) {
for (ConversionMenuItem item : ConversionMenuItem.values()) {
if (isMenuItemVisible(item, result)) {
addMenu(menu, item.title, this);
}
}
if (result.toDouble() != null) {
addMenu(menu, R.string.c_convert, this);
}
}
if (Locator.getInstance().getPlotter().isPlotPossibleFor(result)) {
addMenu(menu, R.string.c_plot, this);
}
}
}
protected boolean isMenuItemVisible(@NonNull ConversionMenuItem menuItem,
@Nonnull Generic generic) {
final NumeralBase fromNumeralBase =
Locator.getInstance().getEngine().getMathEngine().getNumeralBase();
if (fromNumeralBase != menuItem.toNumeralBase) {
return calculator.canConvert(generic, fromNumeralBase, menuItem.toNumeralBase);
}
return false;
}
@Override
public void onClick(View v) {
final DisplayState state = display.getState();
if (state.valid) {
v.setOnCreateContextMenuListener(this);
v.showContextMenu();
v.setOnCreateContextMenuListener(null);
} else {
showEvaluationError(v.getContext(), state.text);
}
}
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, App.getTheme().alertDialogTheme)
.setPositiveButton(R.string.c_cancel, null)
.setView(errorMessageView);
builder.create().show();
}
@Override
public boolean onMenuItemClick(MenuItem item) {
final DisplayState state = display.getState();
final Generic result = state.getResult();
switch (item.getItemId()) {
case R.string.c_copy:
display.copy();
return true;
case R.string.convert_to_bin:
case R.string.convert_to_dec:
case R.string.convert_to_hex:
final ConversionMenuItem menuItem = ConversionMenuItem.getByTitle(item.getItemId());
if (menuItem == null) {
return false;
}
if (result != null) {
calculator.convert(state, menuItem.toNumeralBase);
}
return true;
case R.string.c_convert:
ConverterFragment.show(getActivity(), getValue(result));
return true;
case R.string.c_plot:
if (result != null) {
Locator.getInstance().getPlotter().plot(result);
}
return true;
default:
return false;
}
}
private static double getValue(@Nullable Generic result) {
if (result == null) {
return 1d;
}
final Double value = result.toDouble();
if (value == null) {
return 1d;
}
return value;
}
}

View File

@@ -0,0 +1,14 @@
package org.solovyev.android.calculator.calculations;
import android.support.annotation.NonNull;
import org.solovyev.android.calculator.DisplayState;
public class BaseConversionEvent {
@NonNull
public final DisplayState state;
public BaseConversionEvent(@NonNull DisplayState state) {
this.state = state;
}
}

View File

@@ -0,0 +1,12 @@
package org.solovyev.android.calculator.calculations;
import android.support.annotation.NonNull;
import org.solovyev.android.calculator.DisplayState;
public class ConversionFailedEvent extends BaseConversionEvent {
public ConversionFailedEvent(@NonNull DisplayState state) {
super(state);
}
}

View File

@@ -0,0 +1,21 @@
package org.solovyev.android.calculator.calculations;
import android.support.annotation.NonNull;
import org.solovyev.android.calculator.DisplayState;
import jscl.NumeralBase;
public class ConversionFinishedEvent extends BaseConversionEvent {
@NonNull
public final String result;
@NonNull
public final NumeralBase numeralBase;
public ConversionFinishedEvent(@NonNull String result, @NonNull NumeralBase numeralBase,
@NonNull DisplayState state) {
super(state);
this.result = result;
this.numeralBase = numeralBase;
}
}

View File

@@ -13,19 +13,33 @@ import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.*;
import butterknife.Bind;
import butterknife.ButterKnife;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Spinner;
import android.widget.TextView;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.BaseDialogFragment;
import org.solovyev.android.calculator.R;
import butterknife.Bind;
import butterknife.ButterKnife;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.measure.unit.Dimension;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import java.util.*;
public class ConverterFragment extends BaseDialogFragment
implements AdapterView.OnItemSelectedListener, View.OnFocusChangeListener, TextView.OnEditorActionListener, View.OnClickListener {
@@ -36,6 +50,7 @@ public class ConverterFragment extends BaseDialogFragment
private static final Map<MyDimension, List<Unit<?>>> units = new HashMap<>();
private static final String STATE_SELECTION_FROM = "selection.from";
private static final String STATE_SELECTION_TO = "selection.to";
private static final String EXTRA_VALUE = "value";
static {
for (Unit<?> unit : SI.getInstance().getUnits()) {
@@ -88,7 +103,15 @@ public class ConverterFragment extends BaseDialogFragment
}
public static void show(@Nonnull FragmentActivity activity) {
App.showDialog(new ConverterFragment(), "converter",
show(activity, 1d);
}
public static void show(@Nonnull FragmentActivity activity, double value) {
final ConverterFragment fragment = new ConverterFragment();
final Bundle args = new Bundle(1);
args.putDouble(EXTRA_VALUE, value);
fragment.setArguments(args);
App.showDialog(fragment, "converter",
activity.getSupportFragmentManager());
}
@@ -134,7 +157,7 @@ public class ConverterFragment extends BaseDialogFragment
swapButton.setOnClickListener(this);
if (savedInstanceState == null) {
editTextFrom.setText("1");
editTextFrom.setText(String.valueOf(getArguments().getDouble(EXTRA_VALUE, 1f)));
dimensionsSpinner.setSelection(0);
} else {
pendingFromSelection = savedInstanceState.getInt(STATE_SELECTION_FROM, View.NO_ID);

View File

@@ -1,5 +1,14 @@
package org.solovyev.android.calculator.keyboard;
import static jscl.NumeralBase.hex;
import static org.solovyev.android.calculator.Engine.Preferences.angleUnit;
import static org.solovyev.android.calculator.Engine.Preferences.multiplicationSign;
import static org.solovyev.android.calculator.Engine.Preferences.numeralBase;
import static org.solovyev.android.calculator.Preferences.Gui.hideNumeralBaseDigits;
import static org.solovyev.android.views.dragbutton.DragDirection.down;
import static org.solovyev.android.views.dragbutton.DragDirection.left;
import static org.solovyev.android.views.dragbutton.DragDirection.up;
import android.app.Activity;
import android.app.Application;
import android.content.SharedPreferences;
@@ -11,11 +20,12 @@ import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import butterknife.Bind;
import butterknife.ButterKnife;
import jscl.AngleUnit;
import jscl.NumeralBase;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.ActivityLauncher;
import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CppNumeralBase;
import org.solovyev.android.calculator.Engine;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.buttons.CppSpecialButton;
import org.solovyev.android.calculator.history.History;
import org.solovyev.android.calculator.view.AngleUnitsButton;
@@ -23,14 +33,14 @@ import org.solovyev.android.views.dragbutton.DirectionDragButton;
import org.solovyev.android.views.dragbutton.DragButton;
import org.solovyev.android.views.dragbutton.DragDirection;
import butterknife.Bind;
import butterknife.ButterKnife;
import jscl.AngleUnit;
import jscl.NumeralBase;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import static jscl.NumeralBase.hex;
import static org.solovyev.android.calculator.Engine.Preferences.*;
import static org.solovyev.android.calculator.Preferences.Gui.hideNumeralBaseDigits;
import static org.solovyev.android.views.dragbutton.DragDirection.*;
public class KeyboardUi extends BaseKeyboardUi {
@Bind(R.id.cpp_button_0)
@@ -100,18 +110,18 @@ public class KeyboardUi extends BaseKeyboardUi {
toggleNumericDigits(numeralBase.getPreference(preferences));
} else {
// set HEX to show all digits
AndroidNumeralBase.valueOf(hex).toggleButtons(true, this);
CppNumeralBase.valueOf(hex).toggleButtons(true, this);
}
}
public void toggleNumericDigits(@Nonnull NumeralBase currentNumeralBase) {
for (NumeralBase numeralBase : NumeralBase.values()) {
if (currentNumeralBase != numeralBase) {
AndroidNumeralBase.valueOf(numeralBase).toggleButtons(false, this);
CppNumeralBase.valueOf(numeralBase).toggleButtons(false, this);
}
}
AndroidNumeralBase.valueOf(currentNumeralBase).toggleButtons(true, this);
CppNumeralBase.valueOf(currentNumeralBase).toggleButtons(true, this);
}
public void onCreateView(@Nonnull Activity activity, @Nonnull View view) {

View File

@@ -1,119 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.units;
import org.solovyev.common.units.Unit;
import org.solovyev.common.units.UnitConverter;
import org.solovyev.common.units.UnitImpl;
import org.solovyev.common.units.UnitType;
import java.math.BigInteger;
import javax.annotation.Nonnull;
import jscl.NumeralBase;
/**
* User: Solovyev_S
* Date: 24.09.12
* Time: 16:05
*/
public enum CalculatorNumeralBase implements UnitType<String> {
bin(NumeralBase.bin),
oct(NumeralBase.oct),
dec(NumeralBase.dec),
hex(NumeralBase.hex);
@Nonnull
private static final CalculatorNumeralBase.Converter converter = new CalculatorNumeralBase.Converter();
@Nonnull
private final NumeralBase numeralBase;
CalculatorNumeralBase(@Nonnull NumeralBase numeralBase) {
this.numeralBase = numeralBase;
}
@Nonnull
public static CalculatorNumeralBase.Converter getConverter() {
return converter;
}
@Nonnull
public static CalculatorNumeralBase valueOf(@Nonnull NumeralBase nb) {
for (CalculatorNumeralBase calculatorNumeralBase : values()) {
if (calculatorNumeralBase.numeralBase == nb) {
return calculatorNumeralBase;
}
}
throw new IllegalArgumentException(nb + " is not supported numeral base!");
}
@Nonnull
public NumeralBase getNumeralBase() {
return numeralBase;
}
@Nonnull
@Override
public Class<String> getUnitValueClass() {
return String.class;
}
@Nonnull
public Unit<String> createUnit(@Nonnull String value) {
return UnitImpl.newInstance(value, this);
}
public static class Converter implements UnitConverter<String> {
private Converter() {
}
@Override
public boolean isSupported(@Nonnull UnitType<?> from, @Nonnull UnitType<String> to) {
return CalculatorNumeralBase.class.isAssignableFrom(from.getClass()) && CalculatorNumeralBase.class.isAssignableFrom(to.getClass());
}
@Nonnull
@Override
public Unit<String> convert(@Nonnull Unit<?> from, @Nonnull UnitType<String> toType) {
if (!isSupported(from.getUnitType(), toType)) {
throw new IllegalArgumentException("Types are not supported!");
}
final CalculatorNumeralBase fromTypeAndroid = (CalculatorNumeralBase) from.getUnitType();
final NumeralBase fromNumeralBase = fromTypeAndroid.numeralBase;
final NumeralBase toNumeralBase = ((CalculatorNumeralBase) toType).numeralBase;
final String fromValue = (String) from.getValue();
final BigInteger decBigInteger = fromNumeralBase.toBigInteger(fromValue);
return UnitImpl.newInstance(toNumeralBase.toString(decBigInteger), toType);
}
}
}