From ef141ed054df14b454cf97a397b1d22db18add14 Mon Sep 17 00:00:00 2001 From: Sergey Solovyev Date: Fri, 26 Oct 2012 22:13:17 +0400 Subject: [PATCH] Calculations on fly preference --- .../android/calculator/CalculatorImpl.java | 1006 +++++++++-------- calculatorpp/res/values/text_preferences.xml | 27 +- .../res/xml/calculations_preferences.xml | 115 +- .../android/calculator/AndroidCalculator.java | 25 +- .../calculator/CalculatorApplication.java | 2 +- .../calculator/CalculatorPreferences.java | 385 +++---- 6 files changed, 801 insertions(+), 759 deletions(-) diff --git a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorImpl.java b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorImpl.java index 20092c0a..dc3e088f 100644 --- a/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorImpl.java +++ b/calculatorpp-core/src/main/java/org/solovyev/android/calculator/CalculatorImpl.java @@ -1,499 +1,507 @@ -package org.solovyev.android.calculator; - -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; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -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.MessageRegistry; -import org.solovyev.common.msg.MessageType; -import org.solovyev.common.text.StringUtils; -import org.solovyev.math.units.ConversionException; -import org.solovyev.math.units.ConversionUtils; - -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicLong; - -/** - * User: Solovyev_S - * Date: 20.09.12 - * Time: 16:42 - */ -public class CalculatorImpl implements Calculator, CalculatorEventListener { - - @NotNull - private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer(); - - @NotNull - private final AtomicLong counter = new AtomicLong(CalculatorUtils.FIRST_ID); - - @NotNull - private final TextProcessor preprocessor = ToJsclTextProcessor.getInstance(); - - @NotNull - 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 - @NotNull - private final Executor eventExecutor = Executors.newFixedThreadPool(1); - - public CalculatorImpl() { - this.addCalculatorEventListener(this); - } - - @NotNull - private CalculatorEventData nextEventData() { - long eventId = counter.incrementAndGet(); - return CalculatorEventDataImpl.newInstance(eventId, eventId); - } - - @NotNull - private CalculatorEventData nextEventData(@NotNull Object source) { - long eventId = counter.incrementAndGet(); - return CalculatorEventDataImpl.newInstance(eventId, eventId, source); - } - - @NotNull - private CalculatorEventData nextEventData(@NotNull Long sequenceId) { - long eventId = counter.incrementAndGet(); - return CalculatorEventDataImpl.newInstance(eventId, sequenceId); - } - - /* - ********************************************************************** - * - * CALCULATION - * - ********************************************************************** - */ - - @Override - public void evaluate() { - final CalculatorEditorViewState viewState = getEditor().getViewState(); - fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState); - this.evaluate(JsclOperation.numeric, viewState.getText()); - } - - @Override - public void evaluate(@NotNull 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(); - fireCalculatorEvent(CalculatorEventType.manual_calculation_requested, viewState); - this.evaluate(JsclOperation.simplify, viewState.getText()); - } - - @NotNull - @Override - public CalculatorEventData evaluate(@NotNull final JsclOperation operation, - @NotNull 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; - } - - @NotNull - @Override - public CalculatorEventData evaluate(@NotNull final JsclOperation operation, @NotNull final String expression, @NotNull 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() { - CalculatorLocatorImpl.getInstance().getEngine().init(); - CalculatorLocatorImpl.getInstance().getHistory().load(); - } - - @NotNull - private CalculatorConversionEventData newConversionEventData(@NotNull Long sequenceId, - @NotNull Generic value, - @NotNull NumeralBase from, - @NotNull NumeralBase to, - @NotNull CalculatorDisplayViewState displayViewState) { - return CalculatorConversionEventDataImpl.newInstance(nextEventData(sequenceId), value, from, to, displayViewState); - } - - private void evaluate(@NotNull Long sequenceId, - @NotNull JsclOperation operation, - @NotNull String expression, - @Nullable MessageRegistry mr) { - - PreparedExpression preparedExpression = null; - - try { - - expression = expression.trim(); - - if (StringUtils.isEmpty(expression)) { - fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, CalculatorOutputImpl.newEmptyOutput(operation)); - } else { - preparedExpression = preprocessor.process(expression); - - final String jsclExpression = preparedExpression.toString(); - - try { - - final Generic result = operation.evaluateGeneric(jsclExpression, CalculatorLocatorImpl.getInstance().getEngine().getMathEngine()); - - // NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!) - result.toString(); - - 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); - } - } - - @NotNull - private CalculatorEventData newCalculationEventData(@NotNull JsclOperation operation, - @NotNull String expression, - @NotNull Long calculationId) { - return new CalculatorEvaluationEventDataImpl(nextEventData(calculationId), operation, expression); - } - - private void handleException(@NotNull Long sequenceId, - @NotNull JsclOperation operation, - @NotNull String expression, - @Nullable MessageRegistry mr, - @Nullable PreparedExpression preparedExpression, - @NotNull 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)); - } - } - - private void handleException(@NotNull Long calculationId, - @NotNull JsclOperation operation, - @NotNull String expression, - @Nullable MessageRegistry mr, - @NotNull 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)); - } - } - - /* - ********************************************************************** - * - * CONVERSION - * - ********************************************************************** - */ - - @NotNull - @Override - public CalculatorEventData convert(@NotNull final Generic value, - @NotNull final NumeralBase to) { - final CalculatorEventData eventDataId = nextEventData(); - - final CalculatorDisplayViewState displayViewState = CalculatorLocatorImpl.getInstance().getDisplay().getViewState(); - final NumeralBase from = CalculatorLocatorImpl.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; - } - - @NotNull - private static String doConversion(@NotNull Generic generic, - @NotNull NumeralBase from, - @NotNull NumeralBase to) throws ConversionException { - final String result; - - if (from != to) { - String fromString = generic.toString(); - if (!StringUtils.isEmpty(fromString)) { - try { - fromString = ToJsclTextProcessor.getInstance().process(fromString).getExpression(); - } catch (CalculatorParseException e) { - // ok, problems while processing occurred - } - } - - result = ConversionUtils.doConversion(CalculatorNumeralBase.getConverter(), fromString, CalculatorNumeralBase.valueOf(from), CalculatorNumeralBase.valueOf(to)); - } else { - result = generic.toString(); - } - - return result; - } - - @Override - public boolean isConversionPossible(@NotNull Generic generic, NumeralBase from, @NotNull NumeralBase to) { - try { - doConversion(generic, from, to); - return true; - } catch (ConversionException e) { - return false; - } - } - - /* - ********************************************************************** - * - * EVENTS - * - ********************************************************************** - */ - - @Override - public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) { - calculatorEventContainer.addCalculatorEventListener(calculatorEventListener); - } - - @Override - public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) { - calculatorEventContainer.removeCalculatorEventListener(calculatorEventListener); - } - - @Override - public void fireCalculatorEvent(@NotNull final CalculatorEventData calculatorEventData, @NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data) { - eventExecutor.execute(new Runnable() { - @Override - public void run() { - calculatorEventContainer.fireCalculatorEvent(calculatorEventData, calculatorEventType, data); - } - }); - } - - @Override - public void fireCalculatorEvents(@NotNull final List calculatorEvents) { - eventExecutor.execute(new Runnable() { - @Override - public void run() { - calculatorEventContainer.fireCalculatorEvents(calculatorEvents); - } - }); - } - - @NotNull - @Override - public CalculatorEventData fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data) { - final CalculatorEventData eventData = nextEventData(); - - fireCalculatorEvent(eventData, calculatorEventType, data); - - return eventData; - } - - @NotNull - @Override - public CalculatorEventData fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data, @NotNull Object source) { - final CalculatorEventData eventData = nextEventData(source); - - fireCalculatorEvent(eventData, calculatorEventType, data); - - return eventData; - } - - @NotNull - @Override - public CalculatorEventData fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data, @NotNull Long sequenceId) { - final CalculatorEventData eventData = nextEventData(sequenceId); - - fireCalculatorEvent(eventData, calculatorEventType, data); - - return eventData; - } - - /* - ********************************************************************** - * - * EVENTS HANDLER - * - ********************************************************************** - */ - - @Override - public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) { - - switch (calculatorEventType) { - case editor_state_changed: - 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 engine_preferences_changed: - evaluate(calculatorEventData.getSequenceId()); - break; - - case use_constant: - final IConstant constant = (IConstant)data; - CalculatorLocatorImpl.getInstance().getKeyboard().buttonPressed(constant.getName()); - break; - - case use_operator: - final Operator operator = (Operator)data; - CalculatorLocatorImpl.getInstance().getKeyboard().buttonPressed(operator.getName()); - break; - - case use_function: - final Function function = (Function)data; - CalculatorLocatorImpl.getInstance().getKeyboard().buttonPressed(function.getName()); - break; - - } - } - - private void onDisplayStateChanged(@NotNull CalculatorDisplayChangeEventData displayChangeEventData) { - final CalculatorDisplayViewState newState = displayChangeEventData.getNewValue(); - if (newState.isValid()) { - final String result = newState.getStringResult(); - if ( !StringUtils.isEmpty(result) ) { - final CalculatorMathRegistry varsRegistry = CalculatorLocatorImpl.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("ans_description")); - - CalculatorVarsRegistry.saveVariable(varsRegistry, varBuilder, ansVar, this, false); - } - } - } - - /* - ********************************************************************** - * - * HISTORY - * - ********************************************************************** - */ - - @Override - public void doHistoryAction(@NotNull HistoryAction historyAction) { - final CalculatorHistory history = CalculatorLocatorImpl.getInstance().getHistory(); - if (history.isActionAvailable(historyAction)) { - final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState()); - if (newState != null) { - setCurrentHistoryState(newState); - } - } - } - - @Override - public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) { - editorHistoryState.setValuesFromHistory(getEditor(), getDisplay()); - } - - @NotNull - @Override - public CalculatorHistoryState getCurrentHistoryState() { - return CalculatorHistoryState.newInstance(getEditor(), getDisplay()); - } - - /* - ********************************************************************** - * - * OTHER - * - ********************************************************************** - */ - - @NotNull - private CalculatorEditor getEditor() { - return CalculatorLocatorImpl.getInstance().getEditor(); - } - - @NotNull - private CalculatorDisplay getDisplay() { - return CalculatorLocatorImpl.getInstance().getDisplay(); - } -} +package org.solovyev.android.calculator; + +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; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +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.MessageRegistry; +import org.solovyev.common.msg.MessageType; +import org.solovyev.common.text.StringUtils; +import org.solovyev.math.units.ConversionException; +import org.solovyev.math.units.ConversionUtils; + +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicLong; + +/** + * User: Solovyev_S + * Date: 20.09.12 + * Time: 16:42 + */ +public class CalculatorImpl implements Calculator, CalculatorEventListener { + + @NotNull + private final CalculatorEventContainer calculatorEventContainer = new ListCalculatorEventContainer(); + + @NotNull + private final AtomicLong counter = new AtomicLong(CalculatorUtils.FIRST_ID); + + @NotNull + private final TextProcessor preprocessor = ToJsclTextProcessor.getInstance(); + + @NotNull + 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 + @NotNull + private final Executor eventExecutor = Executors.newFixedThreadPool(1); + + private volatile boolean calculateOnFly = true; + + public CalculatorImpl() { + this.addCalculatorEventListener(this); + } + + @NotNull + private CalculatorEventData nextEventData() { + long eventId = counter.incrementAndGet(); + return CalculatorEventDataImpl.newInstance(eventId, eventId); + } + + @NotNull + private CalculatorEventData nextEventData(@NotNull Object source) { + long eventId = counter.incrementAndGet(); + return CalculatorEventDataImpl.newInstance(eventId, eventId, source); + } + + @NotNull + private CalculatorEventData nextEventData(@NotNull Long sequenceId) { + long eventId = counter.incrementAndGet(); + return CalculatorEventDataImpl.newInstance(eventId, sequenceId); + } + + /* + ********************************************************************** + * + * CALCULATION + * + ********************************************************************** + */ + + @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(@NotNull 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()); + } + + @NotNull + @Override + public CalculatorEventData evaluate(@NotNull final JsclOperation operation, + @NotNull 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; + } + + @NotNull + @Override + public CalculatorEventData evaluate(@NotNull final JsclOperation operation, @NotNull final String expression, @NotNull 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() { + CalculatorLocatorImpl.getInstance().getEngine().init(); + CalculatorLocatorImpl.getInstance().getHistory().load(); + } + + public void setCalculateOnFly(boolean calculateOnFly) { + this.calculateOnFly = calculateOnFly; + } + + @NotNull + private CalculatorConversionEventData newConversionEventData(@NotNull Long sequenceId, + @NotNull Generic value, + @NotNull NumeralBase from, + @NotNull NumeralBase to, + @NotNull CalculatorDisplayViewState displayViewState) { + return CalculatorConversionEventDataImpl.newInstance(nextEventData(sequenceId), value, from, to, displayViewState); + } + + private void evaluate(@NotNull Long sequenceId, + @NotNull JsclOperation operation, + @NotNull String expression, + @Nullable MessageRegistry mr) { + + PreparedExpression preparedExpression = null; + + try { + + expression = expression.trim(); + + if (StringUtils.isEmpty(expression)) { + fireCalculatorEvent(newCalculationEventData(operation, expression, sequenceId), CalculatorEventType.calculation_result, CalculatorOutputImpl.newEmptyOutput(operation)); + } else { + preparedExpression = preprocessor.process(expression); + + final String jsclExpression = preparedExpression.toString(); + + try { + + final Generic result = operation.evaluateGeneric(jsclExpression, CalculatorLocatorImpl.getInstance().getEngine().getMathEngine()); + + // NOTE: toString() method must be called here as ArithmeticOperationException may occur in it (just to avoid later check!) + result.toString(); + + 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); + } + } + + @NotNull + private CalculatorEventData newCalculationEventData(@NotNull JsclOperation operation, + @NotNull String expression, + @NotNull Long calculationId) { + return new CalculatorEvaluationEventDataImpl(nextEventData(calculationId), operation, expression); + } + + private void handleException(@NotNull Long sequenceId, + @NotNull JsclOperation operation, + @NotNull String expression, + @Nullable MessageRegistry mr, + @Nullable PreparedExpression preparedExpression, + @NotNull 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)); + } + } + + private void handleException(@NotNull Long calculationId, + @NotNull JsclOperation operation, + @NotNull String expression, + @Nullable MessageRegistry mr, + @NotNull 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)); + } + } + + /* + ********************************************************************** + * + * CONVERSION + * + ********************************************************************** + */ + + @NotNull + @Override + public CalculatorEventData convert(@NotNull final Generic value, + @NotNull final NumeralBase to) { + final CalculatorEventData eventDataId = nextEventData(); + + final CalculatorDisplayViewState displayViewState = CalculatorLocatorImpl.getInstance().getDisplay().getViewState(); + final NumeralBase from = CalculatorLocatorImpl.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; + } + + @NotNull + private static String doConversion(@NotNull Generic generic, + @NotNull NumeralBase from, + @NotNull NumeralBase to) throws ConversionException { + final String result; + + if (from != to) { + String fromString = generic.toString(); + if (!StringUtils.isEmpty(fromString)) { + try { + fromString = ToJsclTextProcessor.getInstance().process(fromString).getExpression(); + } catch (CalculatorParseException e) { + // ok, problems while processing occurred + } + } + + result = ConversionUtils.doConversion(CalculatorNumeralBase.getConverter(), fromString, CalculatorNumeralBase.valueOf(from), CalculatorNumeralBase.valueOf(to)); + } else { + result = generic.toString(); + } + + return result; + } + + @Override + public boolean isConversionPossible(@NotNull Generic generic, NumeralBase from, @NotNull NumeralBase to) { + try { + doConversion(generic, from, to); + return true; + } catch (ConversionException e) { + return false; + } + } + + /* + ********************************************************************** + * + * EVENTS + * + ********************************************************************** + */ + + @Override + public void addCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) { + calculatorEventContainer.addCalculatorEventListener(calculatorEventListener); + } + + @Override + public void removeCalculatorEventListener(@NotNull CalculatorEventListener calculatorEventListener) { + calculatorEventContainer.removeCalculatorEventListener(calculatorEventListener); + } + + @Override + public void fireCalculatorEvent(@NotNull final CalculatorEventData calculatorEventData, @NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data) { + eventExecutor.execute(new Runnable() { + @Override + public void run() { + calculatorEventContainer.fireCalculatorEvent(calculatorEventData, calculatorEventType, data); + } + }); + } + + @Override + public void fireCalculatorEvents(@NotNull final List calculatorEvents) { + eventExecutor.execute(new Runnable() { + @Override + public void run() { + calculatorEventContainer.fireCalculatorEvents(calculatorEvents); + } + }); + } + + @NotNull + @Override + public CalculatorEventData fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data) { + final CalculatorEventData eventData = nextEventData(); + + fireCalculatorEvent(eventData, calculatorEventType, data); + + return eventData; + } + + @NotNull + @Override + public CalculatorEventData fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data, @NotNull Object source) { + final CalculatorEventData eventData = nextEventData(source); + + fireCalculatorEvent(eventData, calculatorEventType, data); + + return eventData; + } + + @NotNull + @Override + public CalculatorEventData fireCalculatorEvent(@NotNull final CalculatorEventType calculatorEventType, @Nullable final Object data, @NotNull Long sequenceId) { + final CalculatorEventData eventData = nextEventData(sequenceId); + + fireCalculatorEvent(eventData, calculatorEventType, data); + + return eventData; + } + + /* + ********************************************************************** + * + * EVENTS HANDLER + * + ********************************************************************** + */ + + @Override + public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull 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 engine_preferences_changed: + evaluate(calculatorEventData.getSequenceId()); + break; + + case use_constant: + final IConstant constant = (IConstant)data; + CalculatorLocatorImpl.getInstance().getKeyboard().buttonPressed(constant.getName()); + break; + + case use_operator: + final Operator operator = (Operator)data; + CalculatorLocatorImpl.getInstance().getKeyboard().buttonPressed(operator.getName()); + break; + + case use_function: + final Function function = (Function)data; + CalculatorLocatorImpl.getInstance().getKeyboard().buttonPressed(function.getName()); + break; + + } + } + + private void onDisplayStateChanged(@NotNull CalculatorDisplayChangeEventData displayChangeEventData) { + final CalculatorDisplayViewState newState = displayChangeEventData.getNewValue(); + if (newState.isValid()) { + final String result = newState.getStringResult(); + if ( !StringUtils.isEmpty(result) ) { + final CalculatorMathRegistry varsRegistry = CalculatorLocatorImpl.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("ans_description")); + + CalculatorVarsRegistry.saveVariable(varsRegistry, varBuilder, ansVar, this, false); + } + } + } + + /* + ********************************************************************** + * + * HISTORY + * + ********************************************************************** + */ + + @Override + public void doHistoryAction(@NotNull HistoryAction historyAction) { + final CalculatorHistory history = CalculatorLocatorImpl.getInstance().getHistory(); + if (history.isActionAvailable(historyAction)) { + final CalculatorHistoryState newState = history.doAction(historyAction, getCurrentHistoryState()); + if (newState != null) { + setCurrentHistoryState(newState); + } + } + } + + @Override + public void setCurrentHistoryState(@NotNull CalculatorHistoryState editorHistoryState) { + editorHistoryState.setValuesFromHistory(getEditor(), getDisplay()); + } + + @NotNull + @Override + public CalculatorHistoryState getCurrentHistoryState() { + return CalculatorHistoryState.newInstance(getEditor(), getDisplay()); + } + + /* + ********************************************************************** + * + * OTHER + * + ********************************************************************** + */ + + @NotNull + private CalculatorEditor getEditor() { + return CalculatorLocatorImpl.getInstance().getEditor(); + } + + @NotNull + private CalculatorDisplay getDisplay() { + return CalculatorLocatorImpl.getInstance().getDisplay(); + } +} diff --git a/calculatorpp/res/values/text_preferences.xml b/calculatorpp/res/values/text_preferences.xml index b9f6f3f9..9d4fb1e2 100644 --- a/calculatorpp/res/values/text_preferences.xml +++ b/calculatorpp/res/values/text_preferences.xml @@ -1,13 +1,16 @@ - - Toggle screen orientation change - If turned on calculator will change screen orientation automatically - - Show equals button - If turned on equals button is shown - - Hide numeral base digits - If turned on numeral base digits of other numeral bases will be hidden - - Show intermediate calculations in history - If turned on all calculations will be shown on history screen + + Toggle screen orientation change + If turned on calculator will change screen orientation automatically + + Show equals button + If turned on equals button is shown + + Hide numeral base digits + If turned on numeral base digits of other numeral bases will be hidden + + Show intermediate calculations in history + If turned on all calculations will be shown on history screen + + Result is calculated while typing expression + If turned on calculations are done automatically while typing expression \ No newline at end of file diff --git a/calculatorpp/res/xml/calculations_preferences.xml b/calculatorpp/res/xml/calculations_preferences.xml index 6d5feb3e..3ad0ccdb 100644 --- a/calculatorpp/res/xml/calculations_preferences.xml +++ b/calculatorpp/res/xml/calculations_preferences.xml @@ -1,56 +1,61 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculator.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculator.java index caf707bd..ac2626bc 100644 --- a/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculator.java +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/AndroidCalculator.java @@ -2,7 +2,10 @@ package org.solovyev.android.calculator; import android.app.Activity; import android.app.AlertDialog; +import android.app.Application; import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; @@ -21,13 +24,19 @@ import java.util.List; * Date: 9/22/12 * Time: 5:42 PM */ -public class AndroidCalculator implements Calculator, CalculatorEventListener { +public class AndroidCalculator implements Calculator, CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener { @NotNull - private final Calculator calculator = new CalculatorImpl(); + private final CalculatorImpl calculator = new CalculatorImpl(); - public AndroidCalculator() { + @NotNull + private final Application context; + + public AndroidCalculator(@NotNull Application application) { + this.context = application; this.calculator.addCalculatorEventListener(this); + + PreferenceManager.getDefaultSharedPreferences(application).registerOnSharedPreferenceChangeListener(this); } public static void showEvaluationError(@NotNull Context context, @NotNull final String errorMessage) { @@ -121,6 +130,9 @@ public class AndroidCalculator implements Calculator, CalculatorEventListener { @Override public void init() { this.calculator.init(); + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + this.calculator.setCalculateOnFly(CalculatorPreferences.Calculations.calculateOnFly.getPreference(prefs)); } @Override @@ -215,4 +227,11 @@ public class AndroidCalculator implements Calculator, CalculatorEventListener { break; } } + + @Override + public void onSharedPreferenceChanged(@NotNull SharedPreferences prefs, @NotNull String key) { + if ( CalculatorPreferences.Calculations.calculateOnFly.getKey().equals(key) ) { + this.calculator.setCalculateOnFly(CalculatorPreferences.Calculations.calculateOnFly.getPreference(prefs)); + } + } } diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java index 6ce50c46..a7100934 100644 --- a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorApplication.java @@ -83,7 +83,7 @@ public class CalculatorApplication extends android.app.Application { super.onCreate(); - final AndroidCalculator calculator = new AndroidCalculator(); + final AndroidCalculator calculator = new AndroidCalculator(this); CalculatorLocatorImpl.getInstance().init(calculator, new AndroidCalculatorEngine(this), diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorPreferences.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorPreferences.java index e3f5c4cc..5bdf3a77 100644 --- a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorPreferences.java +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorPreferences.java @@ -1,189 +1,196 @@ -package org.solovyev.android.calculator; - -import android.content.SharedPreferences; -import org.jetbrains.annotations.NotNull; -import org.solovyev.android.AndroidUtils; -import org.solovyev.android.calculator.math.MathType; -import org.solovyev.android.calculator.model.AndroidCalculatorEngine; -import org.solovyev.android.calculator.plot.GraphLineColor; -import org.solovyev.android.prefs.BooleanPreference; -import org.solovyev.android.prefs.IntegerPreference; -import org.solovyev.android.prefs.Preference; -import org.solovyev.android.prefs.StringPreference; -import org.solovyev.android.view.VibratorContainer; - -import java.text.DecimalFormatSymbols; -import java.util.Locale; - -/** - * User: serso - * Date: 4/20/12 - * Time: 12:42 PM - */ -public final class CalculatorPreferences { - - private CalculatorPreferences() { - throw new AssertionError(); - } - - public static final Preference appVersion = new IntegerPreference("application.version", -1); - public static final Preference appOpenedCounter = new IntegerPreference("app_opened_counter", 0); - - public static class Gui { - - public static final Preference theme = StringPreference.newInstance("org.solovyev.android.calculator.CalculatorActivity_calc_theme", Theme.metro_blue_theme, Theme.class); - public static final Preference layout = StringPreference.newInstance("org.solovyev.android.calculator.CalculatorActivity_calc_layout", Layout.main_calculator, Layout.class); - public static final Preference feedbackWindowShown = new BooleanPreference("feedback_window_shown", false); - public static final Preference notesppAnnounceShown = new BooleanPreference("notespp_announce_shown", false); - public static final Preference showReleaseNotes = new BooleanPreference("org.solovyev.android.calculator.CalculatorActivity_show_release_notes", true); - public static final Preference usePrevAsBack = new BooleanPreference("org.solovyev.android.calculator.CalculatorActivity_use_back_button_as_prev", false); - public static final Preference showEqualsButton = new BooleanPreference("showEqualsButton", true); - public static final Preference autoOrientation = new BooleanPreference("autoOrientation", true); - public static final Preference hideNumeralBaseDigits = new BooleanPreference("hideNumeralBaseDigits", true); - - @NotNull - public static Theme getTheme(@NotNull SharedPreferences preferences) { - return theme.getPreferenceNoError(preferences); - } - - @NotNull - public static Layout getLayout(@NotNull SharedPreferences preferences) { - return layout.getPreferenceNoError(preferences); - } - - public static enum Theme { - - default_theme(ThemeType.other, R.style.default_theme), - violet_theme(ThemeType.other, R.style.violet_theme), - light_blue_theme(ThemeType.other, R.style.light_blue_theme), - metro_blue_theme(ThemeType.metro, R.style.metro_blue_theme), - metro_purple_theme(ThemeType.metro, R.style.metro_purple_theme), - metro_green_theme(ThemeType.metro, R.style.metro_green_theme); - - @NotNull - private final ThemeType themeType; - - @NotNull - private final Integer themeId; - - Theme(@NotNull ThemeType themeType, Integer themeId) { - this.themeType = themeType; - this.themeId = themeId; - } - - @NotNull - public ThemeType getThemeType() { - return themeType; - } - - @NotNull - public Integer getThemeId() { - return themeId; - } - } - - public static enum ThemeType { - metro, - other - } - - public static enum Layout { - main_calculator(R.layout.main_calculator), - - // not used anymore - @Deprecated - main_cellphone(R.layout.main_calculator), - - simple(R.layout.main_calculator); - - private final int layoutId; - - Layout(int layoutId) { - this.layoutId = layoutId; - } - - public int getLayoutId() { - return layoutId; - } - } - } - - public static class Graph { - public static final Preference interpolate = new BooleanPreference("graph_interpolate", true); - public static final Preference lineColorReal = StringPreference.newInstance("graph_line_color_real", GraphLineColor.white, GraphLineColor.class); - public static final Preference lineColorImag = StringPreference.newInstance("graph_line_color_imag", GraphLineColor.blue, GraphLineColor.class); - } - - public static class History { - public static final Preference showIntermediateCalculations = new BooleanPreference("history_show_intermediate_calculations", false); - } - - - - static void setDefaultValues(@NotNull SharedPreferences preferences) { - if (!AndroidCalculatorEngine.Preferences.groupingSeparator.isSet(preferences)) { - final Locale locale = Locale.getDefault(); - if (locale != null) { - final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(locale); - int index = MathType.grouping_separator.getTokens().indexOf(String.valueOf(decimalFormatSymbols.getGroupingSeparator())); - final String groupingSeparator; - if (index >= 0) { - groupingSeparator = MathType.grouping_separator.getTokens().get(index); - } else { - groupingSeparator = " "; - } - - AndroidCalculatorEngine.Preferences.groupingSeparator.putPreference(preferences, groupingSeparator); - } - } - - if (!AndroidCalculatorEngine.Preferences.angleUnit.isSet(preferences)) { - AndroidCalculatorEngine.Preferences.angleUnit.putDefault(preferences); - } - - if (!AndroidCalculatorEngine.Preferences.numeralBase.isSet(preferences)) { - AndroidCalculatorEngine.Preferences.numeralBase.putDefault(preferences); - } - - if (!AndroidCalculatorEngine.Preferences.multiplicationSign.isSet(preferences)) { - if ( AndroidUtils.isPhoneModel(AndroidUtils.PhoneModel.samsung_galaxy_s) || AndroidUtils.isPhoneModel(AndroidUtils.PhoneModel.samsung_galaxy_s_2) ) { - // workaround ofr samsung galaxy s phones - AndroidCalculatorEngine.Preferences.multiplicationSign.putPreference(preferences, "*"); - } - } - - applyDefaultPreference(preferences, Gui.theme); - applyDefaultPreference(preferences, Gui.layout); - if ( Gui.layout.getPreference(preferences) == Gui.Layout.main_cellphone ) { - Gui.layout.putDefault(preferences); - } - applyDefaultPreference(preferences, Gui.feedbackWindowShown); - applyDefaultPreference(preferences, Gui.notesppAnnounceShown); - applyDefaultPreference(preferences, Gui.showReleaseNotes); - applyDefaultPreference(preferences, Gui.usePrevAsBack); - applyDefaultPreference(preferences, Gui.showEqualsButton); - applyDefaultPreference(preferences, Gui.autoOrientation); - applyDefaultPreference(preferences, Gui.hideNumeralBaseDigits); - - applyDefaultPreference(preferences, Graph.interpolate); - applyDefaultPreference(preferences, Graph.lineColorImag); - applyDefaultPreference(preferences, Graph.lineColorReal); - applyDefaultPreference(preferences, History.showIntermediateCalculations); - - if ( !VibratorContainer.Preferences.hapticFeedbackEnabled.isSet(preferences) ) { - VibratorContainer.Preferences.hapticFeedbackEnabled.putPreference(preferences, true); - } - - if ( !VibratorContainer.Preferences.hapticFeedbackDuration.isSet(preferences) ) { - VibratorContainer.Preferences.hapticFeedbackDuration.putPreference(preferences, 60L); - } - - } - - private static void applyDefaultPreference(@NotNull SharedPreferences preferences, @NotNull Preference preference) { - if (!preference.isSet(preferences)) { - preference.putDefault(preferences); - } - } - -} +package org.solovyev.android.calculator; + +import android.content.SharedPreferences; +import org.jetbrains.annotations.NotNull; +import org.solovyev.android.AndroidUtils; +import org.solovyev.android.calculator.math.MathType; +import org.solovyev.android.calculator.model.AndroidCalculatorEngine; +import org.solovyev.android.calculator.plot.GraphLineColor; +import org.solovyev.android.prefs.BooleanPreference; +import org.solovyev.android.prefs.IntegerPreference; +import org.solovyev.android.prefs.Preference; +import org.solovyev.android.prefs.StringPreference; +import org.solovyev.android.view.VibratorContainer; + +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +/** + * User: serso + * Date: 4/20/12 + * Time: 12:42 PM + */ +public final class CalculatorPreferences { + + private CalculatorPreferences() { + throw new AssertionError(); + } + + public static final Preference appVersion = new IntegerPreference("application.version", -1); + public static final Preference appOpenedCounter = new IntegerPreference("app_opened_counter", 0); + + public static class Calculations { + + public static final Preference calculateOnFly = new BooleanPreference("calculations_calculate_on_fly", true); + + } + + public static class Gui { + + public static final Preference theme = StringPreference.newInstance("org.solovyev.android.calculator.CalculatorActivity_calc_theme", Theme.metro_blue_theme, Theme.class); + public static final Preference layout = StringPreference.newInstance("org.solovyev.android.calculator.CalculatorActivity_calc_layout", Layout.main_calculator, Layout.class); + public static final Preference feedbackWindowShown = new BooleanPreference("feedback_window_shown", false); + public static final Preference notesppAnnounceShown = new BooleanPreference("notespp_announce_shown", false); + public static final Preference showReleaseNotes = new BooleanPreference("org.solovyev.android.calculator.CalculatorActivity_show_release_notes", true); + public static final Preference usePrevAsBack = new BooleanPreference("org.solovyev.android.calculator.CalculatorActivity_use_back_button_as_prev", false); + public static final Preference showEqualsButton = new BooleanPreference("showEqualsButton", true); + public static final Preference autoOrientation = new BooleanPreference("autoOrientation", true); + public static final Preference hideNumeralBaseDigits = new BooleanPreference("hideNumeralBaseDigits", true); + + @NotNull + public static Theme getTheme(@NotNull SharedPreferences preferences) { + return theme.getPreferenceNoError(preferences); + } + + @NotNull + public static Layout getLayout(@NotNull SharedPreferences preferences) { + return layout.getPreferenceNoError(preferences); + } + + public static enum Theme { + + default_theme(ThemeType.other, R.style.default_theme), + violet_theme(ThemeType.other, R.style.violet_theme), + light_blue_theme(ThemeType.other, R.style.light_blue_theme), + metro_blue_theme(ThemeType.metro, R.style.metro_blue_theme), + metro_purple_theme(ThemeType.metro, R.style.metro_purple_theme), + metro_green_theme(ThemeType.metro, R.style.metro_green_theme); + + @NotNull + private final ThemeType themeType; + + @NotNull + private final Integer themeId; + + Theme(@NotNull ThemeType themeType, Integer themeId) { + this.themeType = themeType; + this.themeId = themeId; + } + + @NotNull + public ThemeType getThemeType() { + return themeType; + } + + @NotNull + public Integer getThemeId() { + return themeId; + } + } + + public static enum ThemeType { + metro, + other + } + + public static enum Layout { + main_calculator(R.layout.main_calculator), + + // not used anymore + @Deprecated + main_cellphone(R.layout.main_calculator), + + simple(R.layout.main_calculator); + + private final int layoutId; + + Layout(int layoutId) { + this.layoutId = layoutId; + } + + public int getLayoutId() { + return layoutId; + } + } + } + + public static class Graph { + public static final Preference interpolate = new BooleanPreference("graph_interpolate", true); + public static final Preference lineColorReal = StringPreference.newInstance("graph_line_color_real", GraphLineColor.white, GraphLineColor.class); + public static final Preference lineColorImag = StringPreference.newInstance("graph_line_color_imag", GraphLineColor.blue, GraphLineColor.class); + } + + public static class History { + public static final Preference showIntermediateCalculations = new BooleanPreference("history_show_intermediate_calculations", false); + } + + + + static void setDefaultValues(@NotNull SharedPreferences preferences) { + if (!AndroidCalculatorEngine.Preferences.groupingSeparator.isSet(preferences)) { + final Locale locale = Locale.getDefault(); + if (locale != null) { + final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(locale); + int index = MathType.grouping_separator.getTokens().indexOf(String.valueOf(decimalFormatSymbols.getGroupingSeparator())); + final String groupingSeparator; + if (index >= 0) { + groupingSeparator = MathType.grouping_separator.getTokens().get(index); + } else { + groupingSeparator = " "; + } + + AndroidCalculatorEngine.Preferences.groupingSeparator.putPreference(preferences, groupingSeparator); + } + } + + if (!AndroidCalculatorEngine.Preferences.angleUnit.isSet(preferences)) { + AndroidCalculatorEngine.Preferences.angleUnit.putDefault(preferences); + } + + if (!AndroidCalculatorEngine.Preferences.numeralBase.isSet(preferences)) { + AndroidCalculatorEngine.Preferences.numeralBase.putDefault(preferences); + } + + if (!AndroidCalculatorEngine.Preferences.multiplicationSign.isSet(preferences)) { + if ( AndroidUtils.isPhoneModel(AndroidUtils.PhoneModel.samsung_galaxy_s) || AndroidUtils.isPhoneModel(AndroidUtils.PhoneModel.samsung_galaxy_s_2) ) { + // workaround ofr samsung galaxy s phones + AndroidCalculatorEngine.Preferences.multiplicationSign.putPreference(preferences, "*"); + } + } + + applyDefaultPreference(preferences, Gui.theme); + applyDefaultPreference(preferences, Gui.layout); + if ( Gui.layout.getPreference(preferences) == Gui.Layout.main_cellphone ) { + Gui.layout.putDefault(preferences); + } + applyDefaultPreference(preferences, Gui.feedbackWindowShown); + applyDefaultPreference(preferences, Gui.notesppAnnounceShown); + applyDefaultPreference(preferences, Gui.showReleaseNotes); + applyDefaultPreference(preferences, Gui.usePrevAsBack); + applyDefaultPreference(preferences, Gui.showEqualsButton); + applyDefaultPreference(preferences, Gui.autoOrientation); + applyDefaultPreference(preferences, Gui.hideNumeralBaseDigits); + + applyDefaultPreference(preferences, Graph.interpolate); + applyDefaultPreference(preferences, Graph.lineColorImag); + applyDefaultPreference(preferences, Graph.lineColorReal); + applyDefaultPreference(preferences, History.showIntermediateCalculations); + applyDefaultPreference(preferences, Calculations.calculateOnFly); + + if ( !VibratorContainer.Preferences.hapticFeedbackEnabled.isSet(preferences) ) { + VibratorContainer.Preferences.hapticFeedbackEnabled.putPreference(preferences, true); + } + + if ( !VibratorContainer.Preferences.hapticFeedbackDuration.isSet(preferences) ) { + VibratorContainer.Preferences.hapticFeedbackDuration.putPreference(preferences, 60L); + } + + } + + private static void applyDefaultPreference(@NotNull SharedPreferences preferences, @NotNull Preference preference) { + if (!preference.isSet(preferences)) { + preference.putDefault(preferences); + } + } + +}