寒川アクアブログ

美容師しながらアプリ開発していて水草が趣味の私のブログです

【電卓アプリを作るvol.4】ソースコード2/2

Calc

メインの電卓クラス
アクティビティからnewして使います。

public class Calc implements Context {

    //    ディスプレイ表示が変わるたびに、文字列をコールバックします
    public interface Callback{
        void onTextChanged(String string);
    }

    Callback callback;

  //  最大表示可能桁数
    private final int MAX_DIGIT = 12;

    static public final int KEY_00 = 10,
            KEY_DOT = 20,
            KEY_EQUAL = 21,
            KEY_TASU = 22,
            KEY_HIKU = 23,
            KEY_KAKERU = 24,
            KEY_WARU = 25,
            KEY_PERCENT = 26,
            KEY_SIGN_CHANGE = 27,
            KEY_C = 31,
            KEY_AC = 32,
            KEY_BACK_SPACE = 32;

    private StringBuilder stringBuilder;
    private double value1,value2;  //  左辺、右辺保持
    private int enzanshi;
    private State state;

  //  コンストラクター。ACで初期化しています
    public Calc() {
        allClear();
    }

    public void setListener(Callback callback){
        this.callback = callback;
    }

  //  現在の表示をdoubleで取得
    private double getValue(){
        return Double.valueOf(stringBuilder.toString());
    }

    //  文字列を表示用変数にセット
    private void set(String s){
        stringBuilder = new StringBuilder(s);
    }

   //  doubleを文字列に変換して、表示用変数にセット
    private void set(double d){
        stringBuilder = new StringBuilder(String.valueOf(d));
    }


    private boolean isENZAN_Key(int key) {
        if (key == KEY_TASU || key == KEY_HIKU || key == KEY_KAKERU || key == KEY_WARU){
            return true;
        }
        return false;
    }


    private boolean isNumber_key(int key) {
        if (0 <= key && key <= 9 || key == KEY_DOT){
            return true;
        }
        return false;
    }

  //  引数のキーを入力
    public void input(int inputKey) {
        if (isNumber_key(inputKey)) state.inputNumber(this, inputKey);
        else if (inputKey == KEY_00) {
            state.inputNumber(this, 0);
            state.inputNumber(this, 0);
        }
        else if (isENZAN_Key(inputKey)) state.inputEnzanshi(this, inputKey);
        else if (inputKey == KEY_EQUAL) state.inputEqual(this);
        else if (inputKey == KEY_C) state.inputClear(this);
        else if (inputKey == KEY_AC) allClear();
        else if (inputKey == KEY_BACK_SPACE) state.inputBackSpace(this);
        else if (inputKey == KEY_SIGN_CHANGE) signChange();
        else if (inputKey == KEY_PERCENT) state.inputPercent(this);

        callback.onTextChanged(stringBuilder.toString());
    }


  //  四則演算します
    private double calculation(double d1,int ope,double d2){
        try {
            double ans = 0;
            switch (ope) {
                case KEY_TASU:
                    ans = d1 + d2;
                    break;
                case KEY_HIKU:
                    ans = d1 - d2;
                    break;
                case KEY_KAKERU:
                    ans = d1 * d2;
                    break;
                case KEY_WARU:
                    if (d2 == 0){
                        // エラー
                        return 0;
                    } else {
                        ans = d1 / d2;
                    }
                    break;
            }
            return ans;
        } catch (java.lang.IllegalArgumentException a){
            // エラー
        }
        return 0;
    }


  //  +/-の変換
    private void signChange() {
        if (state.getStateValue(this) == State.STATE_B){
            setLeftDouble();
            set("-0");
            changeState(StateC.getInstance());
        } else {
            if (stringBuilder.indexOf("-") == -1){
                stringBuilder.insert(0,"-");
            } else {
                stringBuilder.deleteCharAt(0);
            }
        }
    }

  //  末尾に数字を追加
    @Override
    public void addNum(int key) {
        if (stringBuilder.length() >= MAX_DIGIT)return;
        if (key == KEY_DOT) {
            if (stringBuilder.indexOf(".") == -1) stringBuilder.append(".");
        } else if (stringBuilder.length() == 1 && stringBuilder.charAt(0) == '0') {
            stringBuilder.replace(0, 1, "" + key);
        } else if (stringBuilder.toString().equals("-0")) {
            stringBuilder.replace(1, 2, "" + key);
        } else {
            stringBuilder.append("" + key);
        }
    }

  //  表示されている数値を左辺として保持
    @Override
    public void setLeftDouble() {
        value1 = getValue();
    }

  //  表示されている数値を右辺として保持
    @Override
    public void setRightValue() {
        value2 = getValue();
    }

  //  押された演算子を保持
    @Override
    public void setEnzanshi(int key) {
        enzanshi = key;
    }


    @Override
    public void keisan() {
        double ans = calculation(value1,enzanshi,getValue());
        set(ans);
    }

  //  表示の数値と、保持していた右辺・演算子で計算
    @Override
    public void teisuKeisan() {
        double ans = calculation(getValue(),enzanshi,value2);
        set(ans);
    }

  //  演算子が+、-のときは左辺のxパーセント
    //    ×、÷のときは右辺の100分の1をセット
    @Override
    public void percent() {
        if (enzanshi == KEY_TASU || enzanshi == KEY_HIKU){
            set((getValue() * value1) / 100d);
        } else {
            set(getValue() / 100d);
        }
    }

    @Override
    public void dividedBy100() {
        set(getValue() / 100d);
    }

  //  1文字消す
    @Override
    public void backSpace() {
        if (stringBuilder.length() == 1){
            set("0");
        } else if (stringBuilder.length() == 2 && stringBuilder.indexOf("-") == 0){
            set("0");
        } else {
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            set(stringBuilder.toString());
        }
    }


    @Override
    public void clear() {
        if (stringBuilder.toString().equals("0")) {
            allClear();
        } else {
            set("0");
        }
    }


    @Override
    public void allClear() {
        set("0");
        enzanshi = -1;
        value1 = 0;
        value2 = 0;
        changeState(StateA.getInstance());

    }


    @Override
    public void dispZero() {
        set("0");
    }

  //    状態を明示的に変更
    @Override
    public void changeState(State instance) {
        this.state = instance;
    }

}