package pl.eternalsh.simplecalc.view;
import pl.eternalsh.simplecalc.common.events.ApplicationEvent;
import pl.eternalsh.simplecalc.common.events.CalculateExpressionEvent;
import java.awt.*;
import java.awt.event.*;
import java.math.BigDecimal;
import java.util.concurrent.BlockingQueue;
import javax.swing.*;
/**
* Main (and only) window of the application.
*
* @author Amadeusz Kosik
*/
class MainWindow extends JFrame
{
/** Blocking queue for events coming from the GUI. */
private final BlockingQueue<ApplicationEvent> blockingQueue;
/** Text field for user's expression meant to be calculated. */
private final JTextField inputExpressionField;
/** Field for user's expression;s result. */
private final JTextField resultField;
/** Layout of the window. */
private final GridBagLayout windowLayout;
/** Layout's constraints. */
private final GridBagConstraints windowLayoutConstraints;
/**
* Prepares object to be set up (installs blocking queue).
*
* @param blockingQueue
*/
MainWindow(final BlockingQueue<ApplicationEvent> blockingQueue)
{
this.blockingQueue = blockingQueue;
inputExpressionField = new JTextField();
resultField = new JTextField();
windowLayout = new GridBagLayout();
windowLayoutConstraints = new GridBagConstraints();
}
/**
* Shows the window and runs it (listens for user's activity).
*/
void run()
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
initialize();
setVisible(true);
}
});
}
/**
* Updates the value of the resultField.
*
* @param newResultString new value of resultField
*/
void updateResultField(final String newResultString)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
resultField.setText(newResultString);
inputExpressionField.setText("");
}
});
}
/**
* Creates all content of the window
* - layout
* - input and result fields
* - buttons.
*/
private void initialize()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
setTitle("SimpleCalc");
getContentPane().setLayout(windowLayout);
windowLayoutConstraints.weightx = 1.0;
windowLayoutConstraints.weighty = 1.0;
windowLayoutConstraints.gridheight = 1;
windowLayoutConstraints.fill = GridBagConstraints.BOTH;
/* First row: input expression text field. */
windowLayoutConstraints.gridwidth = 1;
windowLayoutConstraints.gridx = 0;
windowLayoutConstraints.gridy = 0;
JLabel inputExpressionLabel = new JLabel("Input:");
add(inputExpressionLabel, windowLayoutConstraints);
windowLayoutConstraints.gridwidth = 3;
windowLayoutConstraints.gridx = 1;
resultField.setEditable(false);
add(inputExpressionField, windowLayoutConstraints);
/* Second row: result text field. */
windowLayoutConstraints.gridwidth = 1;
windowLayoutConstraints.gridx = 0;
windowLayoutConstraints.gridy = 1;
JLabel resultLabel = new JLabel("Result:");
add(resultLabel, windowLayoutConstraints);
windowLayoutConstraints.gridwidth = 3;
windowLayoutConstraints.gridx = 1;
add(resultField, windowLayoutConstraints);
/* 4 buttons should pack up in one row. */
windowLayoutConstraints.gridwidth = 1;
/* Third row: buttons AC C. */
placeDeleteButton("AC", 0, 2);
placeBackspaceButton("C", 1, 2);
placeInputButton("(", 2, 2);
placeInputButton(")", 3, 2);
/* Fourth row: buttons 7 8 9 /. */
placeInputButton("7", 0, 3);
placeInputButton("8", 1, 3);
placeInputButton("9", 2, 3);
placeInputButton("/", 3, 3);
/* Fifth row: buttons 4 5 6 *. */
placeInputButton("4", 0, 4);
placeInputButton("5", 1, 4);
placeInputButton("6", 2, 4);
placeInputButton("*", 3, 4);
/* Sixth row: buttons 1 2 3 -. */
placeInputButton("1", 0, 5);
placeInputButton("2", 1, 5);
placeInputButton("3", 2, 5);
placeInputButton("-", 3, 5);
/* Seventh row: buttons 0 , = +. */
placeInputButton("0", 0, 6);
placeInputButton(",", 1, 6);
placeEqualsButton("=", 2, 6);
placeInputButton("+", 3, 6);
pack();
setSize(getPreferredSize());
}
/**
* Inserts a new button into the window.
*
* @param label button's label
* @param positionX x coordinate in the grid
* @param positionY y coordinate in the grid
* @param actionListener action performed when the button is pressed
*/
private void placeButton(final String label,
final int positionX,
final int positionY,
final ActionListener actionListener)
{
JButton newButton = new JButton(label);
newButton.addActionListener(actionListener);
windowLayoutConstraints.gridx = positionX;
windowLayoutConstraints.gridy = positionY;
add(newButton, windowLayoutConstraints);
}
/**
* Inserts a backspace button into the window (it removes last character from the input field).
*
* @param label button's label
* @param positionX x coordinate in the grid
* @param positionY y coordinate in the grid
*/
private void placeBackspaceButton(final String label, final int positionX, final int positionY)
{
placeButton(label, positionX, positionY, new ActionListener()
{
@Override
public void actionPerformed(final ActionEvent actionEvent)
{
SwingUtilities.invokeLater(new Runnable ()
{
public void run()
{
String oldInputText = inputExpressionField.getText();
/* It would be difficult to remove non-existing character. */
if(! oldInputText.isEmpty())
{
inputExpressionField.setText(oldInputText.substring(0, oldInputText.length() - 1));
}
}
});
}
});
}
/**
* Inserts a clear button into the window (it clears the input field).
*
* @param label button's label
* @param positionX x coordinate in the grid
* @param positionY y coordinate in the grid
*/
private void placeDeleteButton(final String label, final int positionX, final int positionY)
{
placeButton(label, positionX, positionY, new ActionListener()
{
@Override
public void actionPerformed(final ActionEvent actionEvent)
{
SwingUtilities.invokeLater(new Runnable ()
{
public void run()
{
inputExpressionField.setText("");
}
});
}
});
}
/**
* Inserts a calculate button into the window (it requests calculating the user's expression).
*
* @param label button's label
* @param positionX x coordinate in the grid
* @param positionY y coordinate in the grid
*/
private void placeEqualsButton(final String label, final int positionX, final int positionY)
{
placeButton(label, positionX, positionY, new ActionListener()
{
@Override
public void actionPerformed(final ActionEvent actionEvent)
{
blockingQueue.add(new CalculateExpressionEvent(inputExpressionField.getText()));
}
});
}
/**
* Inserts an input button into the window (it appends the input field).
*
* @param label button's label
* @param positionX x coordinate in the grid
* @param positionY y coordinate in the grid
*/
private void placeInputButton(final String inputCharacter, final int positionX, final int positionY)
{
placeButton(inputCharacter, positionX, positionY, new ActionListener()
{
@Override
public void actionPerformed(final ActionEvent actionEvent)
{
SwingUtilities.invokeLater(new Runnable ()
{
public void run()
{
inputExpressionField.setText(inputExpressionField.getText().concat(inputCharacter));
}
});
}
});
}
}