/**
* eCalc.java: An Abstract Java Based Calculator
*
* Copyright (c) 2000
* Ali Onur Cinar &060;cinar&064;zdo.com&062;
*
* License:
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for educational purposes and without fee is hereby
* granted, provided that the above copyright notice appear in all copies
* and that both the copyright notice and this permission notice and
* warranty disclaimer appear in supporting documentation, and that the name
* of Ali Onur Cinar not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior permission.
*
* To Compile:
*
* $ javac eCalc.java
*
* To Run:
*
* $ java eCalc
*
* @author A. Onur Cinar &060;cinar&064;zdo.com&062;
* @version %W% %G%
* @version $Id: eCalc.java,v 1.1 2004/08/17 21:31:25 cinar Exp $
* @since 1.0
*/
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
public class eCalc
{
/**
* Internal keypad action listener class
*/
public static class KeypadListener implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
actionHandler(e.getActionCommand());
}
}
/**
* Internal memory keypad action listener class
*/
public static class MemoryListener implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
String command = e.getActionCommand(); // get action command
int index = memoryl.getSelectedIndex(); // get mem list index
if (index == -1) // return if empty
return;
if ("Cut".equals(command)) // cut
{
memory.removeElementAt(index);
}
else if ("Copy".equals(command)) // copy
{
display.setText((String) memory.getElementAt(index));
}
else if ("Clear".equals(command)) // clear
{
memory.clear();
}
}
}
/**
* Internal keyboard listener class
*/
public static class KeyboardListener implements KeyListener
{
public void keyTyped (KeyEvent e)
{
actionHandler(String.valueOf(e.getKeyChar()));
}
public void keyPressed (KeyEvent e) { }
public void keyReleased (KeyEvent e) { }
}
/**
* Internal list cell rendered class
*/
public static class MemoryRenderer extends JLabel
implements ListCellRenderer
{
public Component getListCellRendererComponent (
JList list, Object value, int index,
boolean isSelected, boolean callHasFocus)
{
String str = value.toString();
// remove decimal part if not needed
if (str.length() > 2
&& str.substring(str.length()-2).equals(".0"))
{
str = str.substring(0,str.length()-2);
}
setText(str);
setHorizontalAlignment(RIGHT);
setEnabled(list.isEnabled());
setFont(list.getFont());
setOpaque(true);
if (isSelected)
{
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else
{
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
}
/**
* eCalc: constructor
*/
public eCalc()
{
init();
}
/**
* init: initialize the GUI
*/
protected static void init ()
{
JFrame frame = new JFrame("eCalc");
frame.addWindowListener(new WindowAdapter () {
public void windowClosing (WindowEvent e) { System.exit(0); }
});
frame.addKeyListener(new KeyboardListener());
JPanel mpane = new JPanel();
mpane.setBorder(BorderFactory.createEmptyBorder(4,4,4,4));
frame.getContentPane().add(mpane,BorderLayout.CENTER);
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gc = new GridBagConstraints();
mpane.setLayout(gb);
gc.weightx=0.0; gc.weighty=0.0;
gc.anchor=GridBagConstraints.NORTH;
gc.fill=GridBagConstraints.BOTH;
JPanel p = initMemory();
gc.gridx=0; gc.gridy=0; gc.gridwidth=2; gc.weightx=1.0;
gb.setConstraints(p, gc);
mpane.add(p);
// add register pad
JComponent r = initRegisterpad();
gc.gridx=0; gc.gridy=1;
gc.gridwidth=1; gc.gridheight=2; gc.weightx=0.0;
gb.setConstraints(r, gc);
mpane.add(r);
// add display
JComponent c = initDisplay();
gc.gridx=1; gc.gridy=1;
gc.gridwidth=1; gc.gridheight=1; gc.weightx=1.0;
gb.setConstraints(c, gc);
mpane.add(c);
// add keypad to main pane
p = initKeypads();
gc.gridx=1; gc.gridy=2;
gc.gridwidth=2; gc.weightx=1.0;
gb.setConstraints(p, gc);
mpane.add(p);
frame.pack();
frame.setVisible(true);
}
/**
* initDisplay: initialize display
* @return display as JComponent
*/
protected static JComponent initDisplay()
{
display = new JLabel("0",JLabel.RIGHT);
display.setOpaque(true);
display.setBackground(new Color(0xffffcc));
display.setForeground(Color.black);
display.setFont(new Font("Helvetica", Font.BOLD, 14));
display.setBorder(new BevelBorder(BevelBorder.LOWERED));
return display;
}
/**
* initMemory: initialize memory pane
* @return memory pane as JPanel
*/
protected static JPanel initMemory()
{
JPanel mpane = new JPanel();
mpane.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
MemoryListener mlistener = new MemoryListener();
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gc = new GridBagConstraints();
gc.weightx=1.0; gc.weighty=1.0;
gc.anchor=GridBagConstraints.NORTH;
gc.fill=GridBagConstraints.BOTH;
mpane.setLayout(gb);
// add the list
memoryl = new JList(memory);
memoryl.setVisibleRowCount(2);
memoryl.setBackground(new Color(0xffffcc));
memoryl.setForeground(Color.black);
memoryl.setCellRenderer(new MemoryRenderer()); // set cell renderer
JScrollPane memoryp = new JScrollPane(memoryl,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
gc.gridx=0; gc.gridy=0; gc.gridheight=3;
gb.setConstraints(memoryp, gc);
mpane.add(memoryp);
// add 'clear' button
gc.weightx=0.0;
JButton b = new JButton("Clear");
b.setOpaque(true);
b.setMargin(BUTTON_MARGIN);
b.setPreferredSize(LBUTTON_SIZE);
b.addActionListener(mlistener);
gc.gridx=1; gc.gridy=0; gc.gridheight=1;
gb.setConstraints(b, gc);
mpane.add(b);
// add 'remove' button
b = new JButton("Cut");
b.setOpaque(true);
b.setMargin(BUTTON_MARGIN);
b.setPreferredSize(LBUTTON_SIZE);
b.addActionListener(mlistener);
gc.gridx=1; gc.gridy=1;
gb.setConstraints(b, gc);
mpane.add(b);
// add 'copy' button
b = new JButton("Copy");
b.setOpaque(true);
b.setMargin(BUTTON_MARGIN);
b.setPreferredSize(LBUTTON_SIZE);
b.addActionListener(mlistener);
gc.gridx=1; gc.gridy=2;
gb.setConstraints(b, gc);
mpane.add(b);
// return pane
return mpane;
}
/**
* addKeys: add keys to given panel
* @param panel as JPanel
* @param list of keys as String[]
*/
protected static void addKeys (JPanel panel, String[] keys)
{
// add add keys to panel
for (int i=0; i<keys.length; i++)
{
JButton b = new JButton(keys[i]);
b.setOpaque(true);
b.setPreferredSize(BUTTON_SIZE);
b.setMargin(BUTTON_MARGIN);
b.addActionListener(alistener);
panel.add(b);
}
}
/**
* initRegisterpad: initialize register pad
* @return register pad as JPanel
*/
protected static JPanel initRegisterpad ()
{
JPanel keypad = new JPanel();
keypad.setBorder(new EtchedBorder());
GridBagLayout gb = new GridBagLayout();
GridBagConstraints gc = new GridBagConstraints();
gc.weightx=0.0; gc.weighty=0.0;
gc.anchor=GridBagConstraints.NORTH;
gc.fill=GridBagConstraints.BOTH;
keypad.setLayout(gb);
rdisp = new JLabel("0",JLabel.RIGHT);
rdisp.setOpaque(true);
rdisp.setBackground(Color.lightGray);
rdisp.setForeground(Color.black);
rdisp.setFont(new Font("Helvetica", Font.BOLD, 14));
rdisp.setBorder(new BevelBorder(BevelBorder.LOWERED));
rdisp.setPreferredSize(BUTTON_SIZE);
gc.gridx=0; gc.gridy=0;
gb.setConstraints(rdisp, gc);
keypad.add(rdisp);
// keypad components
String[] keypadcomp =
{
"MC","MR","MS","M+"
};
// add keypad components
JPanel keypad1 = new JPanel();
keypad1.setBorder(BorderFactory.createEmptyBorder(4,4,4,4));
keypad1.setLayout(new GridLayout(4,1));
addKeys(keypad1,keypadcomp);
gc.gridx=0; gc.gridy=1;
gb.setConstraints(keypad1, gc);
keypad.add(keypad1);
// return
return keypad;
}
/**
* initKeypads: initialize keypads
* @return keypad object as JPanel
*/
protected static JPanel initKeypads ()
{
// define the keypad 1
JPanel keypad1 = new JPanel();
keypad1.setBorder(BorderFactory.createEmptyBorder(4,4,4,4));
keypad1.setLayout(new GridLayout(4,5));
// keypad1 components
String[] keypad1comp =
{
"7","8","9","/","C",
"4","5","6","*","CE",
"1","2","3","-","DEL",
"0","+/-",".","+","="
};
// add keypad1 components
addKeys(keypad1,keypad1comp);
// define the keypad 3
JPanel keypad3 = new JPanel();
keypad3.setBorder(BorderFactory.createEmptyBorder(4,4,4,4));
keypad3.setLayout(new GridLayout(4,1));
// keypad3 components
String[] keypad3comp = {
"sin","cos","tan","Pi"
};
// add keypad3 components
addKeys(keypad3,keypad3comp);
// define the keypad 4
JPanel keypad4 = new JPanel();
keypad4.setBorder(BorderFactory.createEmptyBorder(4,4,4,4));
keypad4.setLayout(new GridLayout(4,1));
// keypad4 components
String[] keypad4comp = {
"1/x","x^2","n!","sqrt"
};
// add keypad4 components
addKeys(keypad4,keypad4comp);
// create big keypad box
JPanel keypad = new JPanel();
keypad.setLayout(new BoxLayout(keypad, BoxLayout.X_AXIS));
keypad.add(Box.createRigidArea (new Dimension (10,10)));
keypad.add(keypad4);
keypad.add(keypad3);
keypad.add(Box.createRigidArea (new Dimension (10,10)));
keypad.add(keypad1);
// return the keypad
return keypad;
}
/**
* updateDisplay: updates and formats the display
*/
protected static void updateDisplay (double d)
{
// first convert to integer
int i = new Double(d).intValue();
// check to see if we realy need the decimal
// part or not
if (d > i)
{
display.setText(Double.toString(d));
}
else
{
display.setText(Integer.toString(i));
}
}
/**
* actionHandler: action handler
* @param command as String
*/
protected static void calc ()
{
// current display's value
double dval = Double.valueOf(display.getText()).doubleValue();
// if operation is '='
if (operator == '=')
{
// simply copy display to total
total = dval;
}
else if (operator == '/') // divide total
{
total = total / dval;
}
else if (operator == '*') // multiply total
{
total = total * dval;
}
else if (operator == '-') // substract total
{
total = total - dval;
}
else if (operator == '+') // add total
{
total = total + dval;
}
// update the display with
// total's value
updateDisplay(total);
// don't need to keep display
keep_display=false;
// add total to memory list
// if operator is not =
if (operator != '=')
{
memory.addElement(Double.toString(total));
// make it visible
memoryl.ensureIndexIsVisible(memory.size()-1);
}
// set operator to = to avoid
// multiple presses
operator = '=';
}
/**
* actionHandler: action handler
* @param command as String
*/
protected static void actionHandler (String command)
{
// current display's value (may be needed)
double dval = Double.valueOf(display.getText()).doubleValue();
// check for operations
if ("sin".equals(command)) // sin
{
// convert display to radian
double d = dval * (Math.PI/180);
// set display to sin(display)
updateDisplay(Math.sin(d));
// don't need to keep display
keep_display=false;
}
else if ("cos".equals(command)) // cos
{
// convert display to radian
double d = dval * (Math.PI/180);
// set display to cos(display)
updateDisplay(Math.cos(d));
// don't need to keep display
keep_display=false;
}
else if ("tan".equals(command)) // tan
{
// convert display to radian
double d = dval * (Math.PI/180);
// set display to tan(display)
updateDisplay(Math.tan(d));
// don't need to keep display
keep_display=false;
}
else if ("Pi".equals(command)) // Pi
{
// set display to Pi
display.setText(Double.toString(Math.PI));
// don't need to keep display
keep_display=false;
}
else if ("MC".equals(command))
{
// clean the register
rdisp.setText(register = "0");
}
else if ("MR".equals(command)) // MC
{
// restore register to display
display.setText(register);
// don't need to keep display
keep_display=false;
}
else if ("MS".equals(command)) // MS
{
// store the display in register
rdisp.setText(register = display.getText());
// don't need to keep display
keep_display=false;
}
else if ("M+".equals(command)) // M+
{
// if register is empty
// then just return back
if ("0".equals(register))
return;
// first calculate previous
calc();
// restore register to display
display.setText(register);
// set operator to +
operator = '+';
// calculate again
calc();
}
else if ("+/-".equals(command)) // +/-
{
// set display to its inverse
updateDisplay(dval * -1.0);
// don't need to keep display
keep_display=false;
}
else if ("/".equals(command) // /
|| "*".equals(command) // *
|| "-".equals(command) // -
|| "+".equals(command) // +
|| "=".equals(command)) // =
{
// calculate previous operation
calc();
// set new operator
operator = command.charAt(0);
}
else if ("1/x".equals(command)) // 1/x
{
// set display to 1/(display)
updateDisplay(1/dval);
// don't need to keep display
keep_display=false;
}
else if ("x^2".equals(command)) // x^2
{
// set display to (display)^2
updateDisplay(dval*dval);
// don't need to keep display
keep_display=false;
}
else if ("n!".equals(command)) // n!
{
// set display to (display)!
updateDisplay(dval*(dval+1)/2);
// don't need to keep display
keep_display=false;
}
else if ("sqrt".equals(command)) // sqrt
{
// set display to sqrt(display)
updateDisplay(Math.sqrt(dval));
// don't need to keep display
keep_display=false;
}
else if ("C".equals(command)) // C
{
// clear only display
display.setText("0");
}
else if ("CE".equals(command)) // CE
{
// clear everything
display.setText("0");
rdisp.setText(register="0");
// clear the memory
memory.clear();
}
else if ("DEL".equals(command)) // DEL
{
// delete the last number
String str = display.getText();
// if there is only 1 number then
// set display to 0
str = (str.length() == 1) ?
"0" : str.substring(0,str.length()-1);
// set the display
display.setText(str);
}
else if (command.charAt(0) >= 46
&& command.charAt(0) <= 57)
{
String str = display.getText();
// can't write multiple 0s such as 0000
if ("0".equals(command) && "0".equals(str))
{
return;
}
// can't write multiple .s such as 0.00.0
if (".".equals(command) && str.indexOf('.') > -1)
{
return;
}
// otherwise add the number
// if it is the first number, or we don't need
// to keep the display, then remove the 0
// and add it, else concat it to existing display
str = ("0".equals(str) || !keep_display)
? command : str.concat(command);
// if display is just . then make it 0.
if (".".equals(str))
{
str = "0.";
}
// keep the display
keep_display=true;
// set the diplay
display.setText(str);
}
}
/**
* main: main entance point
* @param any arguments
*/
public static void main (String[] args)
{
new eCalc();
}
/** class constants */
protected static final Dimension BUTTON_SIZE = new Dimension(40,20);
protected static final Dimension LBUTTON_SIZE = new Dimension(40,15);
protected static final Insets BUTTON_MARGIN = new Insets(2,2,2,2);
protected static final DefaultListModel memory = new DefaultListModel();
protected static ActionListener alistener = new KeypadListener();
/** class data */
protected static JLabel display;
protected static JLabel rdisp;
protected static JList memoryl;
protected static boolean keep_display = true;
protected static String register = new String("0");
protected static char operator = '=';
protected static double total = 0.0;
}