You are on page 1of 19

public interface CalculatorViewListener {

void handleCalculatorViewEvent(CalculatorViewEvent e);

package lec20.v10;

abstract public class CalculatorViewEvent {


public boolean isDigitEvent() {
return false;
}

public boolean isOperationEvent() {


return false;
}
public boolean isInversionEvent() {
return false;
}

public boolean isPointEvent() {


return false;
}

class DigitEvent extends CalculatorViewEvent {


private int value;
public DigitEvent(int value) {
this.value = value;
}
public int getValue() {
return value;
}

public String getString() {


return Integer.toString(value);
}
public boolean isDigitEvent() {
return true;
}
}

class OperationEvent extends CalculatorViewEvent {


private Operation.OpType op_type;
public OperationEvent(Operation.OpType op_type) {
this.op_type = op_type;
}

public Operation.OpType getOpType() {

return op_type;
}
public boolean isOperationEvent() {
return true;
}
}

class InversionEvent extends CalculatorViewEvent {


public boolean isInversionEvent() {
return true;
}
}

class PointEvent extends CalculatorViewEvent {


public boolean isPointEvent() {
return true;
}
}

public class Operation {

public enum OpType {ADD, MULT, DIV, SUB, SET}


private OpType type;
private double operand;
public Operation(OpType type, double operand) {

this.type = type;
this.operand = operand;
}
public OpType getType() {
return type;
}
public double getOperand() {
return operand;
}
public String toString() {
String str = "";
switch (type) {
case ADD:
str = "+ "; break;
case MULT:
str = "* "; break;
case DIV:
str = "/ "; break;
case SUB:
str = "- "; break;
case SET:
str = "= "; break;
}
str += operand;
return str;

}
}

public class CalculatorView extends JPanel implements ActionListener, KeyListener {


private JTextArea tape;
private JLabel display;
private JPanel button_panel;
private List<CalculatorViewListener> listeners;

public CalculatorView() {
setLayout(new BorderLayout());
tape = new JTextArea(10,20);
tape.setEditable(false);
add(new JScrollPane(tape), BorderLayout.CENTER);
JPanel subpanel = new JPanel();
subpanel.setLayout(new BorderLayout());
display = new JLabel("0");
display.setHorizontalAlignment(SwingConstants.RIGHT);
subpanel.add(display, BorderLayout.NORTH);

button_panel = new JPanel();


button_panel.setLayout(new GridLayout(5,4));

// First row of buttons

button_panel.add(new JButton("7"));
button_panel.add(new JButton("8"));
button_panel.add(new JButton("9"));
button_panel.add(new JButton("+"));

// Second row of buttons

button_panel.add(new JButton("4"));
button_panel.add(new JButton("5"));

button_panel.add(new JButton("6"));
button_panel.add(new JButton("-"));

// Third row of buttons

button_panel.add(new JButton("1"));
button_panel.add(new JButton("2"));
button_panel.add(new JButton("3"));
button_panel.add(new JButton("*"));

// Fourth row of buttons


button_panel.add(new JButton("."));
button_panel.add(new JButton("0"));
button_panel.add(new JButton("+/-"));
button_panel.add(new JButton("/"));

// Fifth row of buttons


button_panel.add(new JButton("C"));
button_panel.add(new JButton("CE"));
button_panel.add(new JButton("CT"));
button_panel.add(new JButton("="));

subpanel.add(button_panel, BorderLayout.SOUTH);
add(subpanel, BorderLayout.SOUTH);
for(Component c: button_panel.getComponents()) {

JButton b = (JButton) c;
b.addActionListener(this);
}
listeners = new ArrayList<CalculatorViewListener>();
this.setFocusable(true);
this.grabFocus();
this.addKeyListener(this);
}
public void setDisplay(String s) {
display.setText(s);
}
public void appendToDisplay(String s) {
display.setText(display.getText()+s);
}
public String getDisplay() {
return display.getText();
}

public void appendToTape(String s) {


tape.append(s);
}

@Override
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();

char first_char = button.getText().charAt(0);


if (first_char == '+') {
if (button.getText().equals("+/-")) {
first_char = 'i';
}
}
dispatchEventByChar(first_char);
}
private void dispatchEventByChar(char c) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
fireEvent(new DigitEvent(Integer.parseInt(Character.toString(c))));
break;
case '+':
fireEvent(new OperationEvent(Operation.OpType.ADD));
break;

case '-':
fireEvent(new OperationEvent(Operation.OpType.SUB));
break;
case '/':
fireEvent(new OperationEvent(Operation.OpType.DIV));
break;
case '*':
fireEvent(new OperationEvent(Operation.OpType.MULT));
break;
case '=':
fireEvent(new OperationEvent(Operation.OpType.SET));
break;
case 'i':
fireEvent(new InversionEvent());
break;
case '.':
fireEvent(new PointEvent());
break;

}
}
public void addCalculatorViewListener(CalculatorViewListener l) {
listeners.add(l);
}
public void removeCalculatorViewListener(CalculatorViewListener l) {

listeners.remove(l);
}
public void fireEvent(CalculatorViewEvent e) {
for (CalculatorViewListener l : listeners) {
l.handleCalculatorViewEvent(e);
}
}

@Override
public void keyPressed(KeyEvent e) {
}

@Override
public void keyReleased(KeyEvent e) {
}

@Override
public void keyTyped(KeyEvent e) {
dispatchEventByChar(e.getKeyChar());
}
}

public class CalculatorModel extends Observable {

private List<Operation> history;


private double value;

public CalculatorModel() {
history = new ArrayList<Operation>();
value = 0.0;

public double getValue() {


return value;
}
public void eval(Operation op) {
history.add(op);
switch (op.getType()) {
case ADD:
value += op.getOperand();
break;
case SUB:
value -= op.getOperand();
break;
case MULT:
value *= op.getOperand();
break;
case DIV:
value /= op.getOperand();
break;
case SET:
value = op.getOperand();
break;
}
setChanged();

notifyObservers(op);
}
public void reset() {
history = new ArrayList<Operation>();
value = 0.0;
}
}

public class CalculatorController implements Observer, CalculatorViewListener {

CalculatorModel model;
CalculatorView view;

boolean start_of_number;
boolean point_pressed;
Operation.OpType in_progress;

public CalculatorController(CalculatorModel model, CalculatorView view) {


this.model = model;
this.view = view;

view.addCalculatorViewListener(this);

start_of_number = true;
point_pressed = false;
view.setDisplay("0");
in_progress = Operation.OpType.SET;

model.addObserver(this);
}

@Override
public void handleCalculatorViewEvent(CalculatorViewEvent e) {
if (e.isDigitEvent()) {
DigitEvent digit = (DigitEvent) e;
if (start_of_number) {
view.setDisplay(digit.getString());
start_of_number = false;
} else {
if (view.getDisplay().equals("0")) {
if (digit.getValue() != 0) {
view.setDisplay(digit.getString());
}
} else {
view.appendToDisplay(digit.getString());
}
}

} else if (e.isOperationEvent()) {
OperationEvent op_event = (OperationEvent) e;

if (!start_of_number) {
double disp_value = Double.parseDouble(view.getDisplay());
model.eval(new Operation(in_progress, disp_value));
}
start_of_number = true;
point_pressed = false;
in_progress = op_event.getOpType();
if (in_progress == Operation.OpType.SET) {
model.eval(new Operation(in_progress, model.getValue()));
}
} else if (e.isInversionEvent()) {
if (Double.parseDouble(view.getDisplay()) != 0) {
String in_display = view.getDisplay();
if (in_display.charAt(0) != '-') {
view.setDisplay("-" + in_display);
} else {
view.setDisplay(in_display.substring(1));
}
}
} else if (e.isPointEvent()) {
if (start_of_number) {
view.setDisplay("0.");

start_of_number = false;
} else if (!point_pressed) {
view.appendToDisplay(".");
}
point_pressed = true;
}
}

@Override
public void update(Observable o, Object arg) {
Operation op = (Operation) arg;

view.appendToTape(op.toString() + "\n");
view.setDisplay(Double.toString(model.getValue()));
start_of_number = true;
point_pressed = false;

}
public class Main {

public static void main(String[] args) {


CalculatorModel model = new CalculatorModel();

CalculatorView view = new CalculatorView();


CalculatorController controller = new CalculatorController(model, view);
JFrame main_frame = new JFrame();
main_frame.setTitle("MVC Calculator");
main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

main_frame.setContentPane(view);

main_frame.pack();
main_frame.setVisible(true);
}
}

You might also like