Thursday, April 22, 2010

Java Call Center Program

import umontreal.iro.lecuyer.simevents.*;
import umontreal.iro.lecuyer.rng.*;
import umontreal.iro.lecuyer.randvar.*;
import umontreal.iro.lecuyer.probdist.*;
import umontreal.iro.lecuyer.stat.*;
import java.io.*;
import java.util.Scanner;
import java.util.LinkedList;
//http://www.iro.umontreal.ca/~lecuyer/ift6561/java/CallCenter.java
public class CallCenter {
static final double HOUR = 3600.0; // Time is in seconds.

// Data
// Arrival rates are per hour, service and patience times are in seconds.
double openingTime; // Opening time of the center (in hours).
int numPeriods; // Number of working periods (hours) in the day.
int[] numAgents; // Number of agents for each period.
double[] lambda; // Base arrival rate lambda_j for each j.
double alpha0; // Parameter of gamma distribution for B.
double p; // Probability that patience time is 0.
double nu; // Parameter of exponential for patience time.
double alpha, beta; // Parameters of gamma service time distribution.
double s; // Want stats on waiting times smaller than s.

// Variables
double busyness; // Current value of B.
double arrRate = 0.0; // Current arrival rate.
int nAgents; // Number of agents in current period.
int nBusy; // Number of agents occupied;
int nArrivals; // Number of arrivals today;
int nAbandon; // Number of abandonments during the day.
int nGoodQoS; // Number of waiting times less than s today.
double nCallsExpected; // Expected number of calls per day.

Event nextArrival = new Arrival(); // The next Arrival event.
LinkedList waitList = new LinkedList();

RandomStream streamB = new MRG32k3a(); // For B.
RandomStream streamArr = new MRG32k3a(); // For arrivals.
RandomStream streamPatience = new MRG32k3a(); // For patience times.
GammaGen genServ; // For service times; created in readData().

Tally[] allTal = new Tally [4];
Tally statArrivals = allTal[0] = new Tally ("Number of arrivals per day");
Tally statWaits = allTal[1] = new Tally ("Average waiting time per customer");
Tally statGoodQoS = allTal[2] = new Tally ("Proportion of waiting times < s");
Tally statAbandon = allTal[3] = new Tally ("Proportion of calls lost");
Tally statWaitsDay = new Tally ("Waiting times within a day");

public CallCenter (String fileName) throws IOException {
readData (fileName);
// genServ can be created only after its parameters are read.
// The acceptance/rejection method is much faster than inversion.
genServ = new GammaAcceptanceRejectionGen (new MRG32k3a(), alpha, beta);
}

// Reads data and construct arrays.
public void readData (String fileName) throws IOException {
BufferedReader input = new BufferedReader (new FileReader (fileName));
Scanner scan = new Scanner(input);
openingTime = scan.nextDouble(); scan.nextLine();
numPeriods = scan.nextInt(); scan.nextLine();
numAgents = new int[numPeriods];
lambda = new double[numPeriods];
nCallsExpected = 0.0;
for (int j = 0; j < numPeriods; j++) {
numAgents[j] = scan.nextInt();
lambda[j] = scan.nextDouble();
nCallsExpected += lambda[j]; scan.nextLine();
}
alpha0 = scan.nextDouble(); scan.nextLine();
p = scan.nextDouble(); scan.nextLine();
nu = scan.nextDouble(); scan.nextLine();
alpha = scan.nextDouble(); scan.nextLine();
beta = scan.nextDouble(); scan.nextLine();
s = scan.nextDouble();
scan.close();
}

// A phone call.
class Call {
double arrivalTime, serviceTime, patienceTime;

public Call() {
serviceTime = genServ.nextDouble(); // Generate service time.
if (nBusy < nAgents) { // Start service immediately.
nBusy++;
nGoodQoS++;
statWaitsDay.add (0.0);
new CallCompletion().schedule (serviceTime);
} else { // Join the queue.
patienceTime = generPatience();
arrivalTime = Sim.time();
waitList.addLast (this);
}
}

public void endWait() {
double wait = Sim.time() - arrivalTime;
if (patienceTime < wait) { // Caller has abandoned.
nAbandon++;
wait = patienceTime; // Effective waiting time.
} else {
nBusy++;
new CallCompletion().schedule (serviceTime);
}
if (wait < s) nGoodQoS++;
statWaitsDay.add (wait);
}
}

// Event: A new period begins.
class NextPeriod extends Event {
int j; // Number of the new period.
public NextPeriod (int period) { j = period; }
public void actions() {
if (j < numPeriods) {
nAgents = numAgents[j];
arrRate = busyness * lambda[j] / HOUR;
if (j == 0) {
nextArrival.schedule
(ExponentialDist.inverseF (arrRate, streamArr.nextDouble()));
} else {
checkQueue();
nextArrival.reschedule ((nextArrival.time() - Sim.time())
* lambda[j-1] / lambda[j]);
}
new NextPeriod(j+1).schedule (1.0 * HOUR);
} else
nextArrival.cancel(); // End of the day.
}
}

// Event: A call arrives.
class Arrival extends Event {
public void actions() {
nextArrival.schedule
(ExponentialDist.inverseF (arrRate, streamArr.nextDouble()));
nArrivals++;
new Call(); // Call just arrived.
}
}

// Event: A call is completed.
class CallCompletion extends Event {
public void actions() { nBusy--; checkQueue(); }
}

// Start answering new calls if agents are free and queue not empty.
public void checkQueue() {
while ((waitList.size() > 0) && (nBusy < nAgents))
(waitList.removeFirst()).endWait();
}

// Generates the patience time for a call.
public double generPatience() {
double u = streamPatience.nextDouble();
if (u <= p)
return 0.0;
else
return ExponentialDist.inverseF (nu, (1.0-u) / (1.0-p));
}

public void simulateOneDay (double busyness) {
Sim.init(); statWaitsDay.init();
nArrivals = 0; nAbandon = 0;
nGoodQoS = 0; nBusy = 0;
this.busyness = busyness;

new NextPeriod(0).schedule (openingTime * HOUR);
Sim.start();
// Here the simulation is running...

statArrivals.add ((double)nArrivals);
statAbandon.add ((double)nAbandon / nCallsExpected);
statGoodQoS.add ((double)nGoodQoS / nCallsExpected);
statWaits.add (statWaitsDay.sum() / nCallsExpected);
}

public void simulateOneDay () {
simulateOneDay (GammaDist.inverseF (alpha0, alpha0, 8,
streamB.nextDouble()));
}

static public void main (String[] args) throws IOException {
CallCenter cc = new CallCenter ("CallCenter.dat");
for (int i = 0; i < 1000; i++) cc.simulateOneDay();
System.out.println ("\nNum. calls expected = " + cc.nCallsExpected +"\n");
for (int i = 0; i < cc.allTal.length; i++) {
cc.allTal[i].setConfidenceIntervalStudent();
cc.allTal[i].setConfidenceLevel (0.90);
}
System.out.println (Tally.report ("CallCenter:", cc.allTal));
}
}

Wednesday, April 14, 2010

Undo and Redo Action

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.UndoManager;

public class UndoEditor extends JFrame {
private UndoManager undoManager = new UndoManager();
private JMenuBar menuBar = new JMenuBar();
private JMenu editMenu = new JMenu("Edit");
private UndoAction undoAction = new UndoAction();
private RedoAction redoAction = new RedoAction();

public UndoEditor() {
setLayout(new BorderLayout());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JTextPane editor = new JTextPane();
editor.getDocument().addUndoableEditListener(new UndoListener());

menuBar.add(editMenu);
editMenu.add(undoAction);
editMenu.add(redoAction);
this.setJMenuBar(menuBar);
add(new JScrollPane(editor));
setSize(400, 300);
setVisible(true);
}

public static void main(String[] args) {
UndoEditor e = new UndoEditor();
}

class UndoListener implements UndoableEditListener {
public void undoableEditHappened(UndoableEditEvent e) {
undoManager.addEdit(e.getEdit());
undoAction.update();
redoAction.update();
}
}

class UndoAction extends AbstractAction {
public UndoAction() {
this.putValue(Action.NAME, undoManager.getUndoPresentationName());
this.setEnabled(false);
}

public void actionPerformed(ActionEvent e) {
if (this.isEnabled()) {
undoManager.undo();
undoAction.update();
redoAction.update();
}
}

public void update() {
this.putValue(Action.NAME, undoManager.getUndoPresentationName());
this.setEnabled(undoManager.canUndo());
}
}

class RedoAction extends AbstractAction {
public RedoAction() {
this.putValue(Action.NAME, undoManager.getRedoPresentationName());
this.setEnabled(false);
}

public void actionPerformed(ActionEvent e) {
if (this.isEnabled()) {
undoManager.redo();
undoAction.update();
redoAction.update();
}
}

public void update() {
this.putValue(Action.NAME, undoManager.getRedoPresentationName());
this.setEnabled(undoManager.canRedo());
}
}
}

Thursday, April 8, 2010

JTable Header

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
*
* @author Monirul
*/
public class JTableRowHeaders1 extends JFrame {

private JTable table;
private JPanel panel;
private JScrollPane scroll;
private JList rowHeaders;

public JTableRowHeaders1() {

initializeInventory();
}

private void initializeInventory() {
panel = new JPanel();
panel.setLayout(new GridLayout(1,0));
final String[] columnNames = {"Name", "Surname", "Age"};
final Object[][] data = {{"Jhon", "Java", "23"}, {"Stupid", "Stupido", "500"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Michael", "Winnie", "20"}, {"Winnie", "Thepoor", "23"},
{"Max", "Dumbass", "10"}, {"Melanie", "Martin", "500"},
{"Jollibe", "Mcdonalds", "15"}};

table = new JTable(data, columnNames);
Integer[] rowData = new Integer[data.length];
for (int x = 0; x <= rowData.length - 1; x++) {
rowData[x] = x + 1;
}

rowHeaders = new JList (rowData);
rowHeaders.setFixedCellWidth(50);
rowHeaders.setCellRenderer(new RowHeaderRenderer(table));
scroll = new JScrollPane(table);
scroll.setBounds(0, 100, 900, 500);
scroll.setRowHeaderView(rowHeaders);
panel.add(scroll);
getContentPane().add(panel);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(900, 700);
setLocationRelativeTo(null);
setVisible(true);
}

// class use for rendering the properties of the row headers
private class RowHeaderRenderer extends JLabel implements ListCellRenderer {
RowHeaderRenderer(JTable table) {
setOpaque(true);
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
setHorizontalAlignment(CENTER);
setForeground(new Color(100, 100, 100));
setFont(new Font("Monospaced", Font.BOLD, 11));
}
public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
setText((value == null) ? "" : value.toString());
return this;
}
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JTableRowHeaders1();
}
});
}
}

JTable Selecting and Dragging

Synchronized row header and row when selecting and dragging this is an example how to synchronize the row header with the row when a dragging event occurs in a JScrollPane

import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
/**
*
* @author Monirul
*/
public class JTableRowHeadersAndRowsSynchronized extends JFrame {
private JTable mainTable;
private JScrollPane scroll ;
private JViewport jv;
private JTable rowHeaderTableColumn;
private JPanel panel;
private TableModel tableModel;
private DefaultTableModel mainTableModel;
private Integer[] rowHeaderData;
public JTableRowHeadersAndRowsSynchronized() {
initComponents();
}
private void initComponents() {
panel = new JPanel();
tableModel = new AbstractTableModel() {
String[] header = {"Rows"};
public int getColumnCount() {
return 1;
}
public int getRowCount() {
return mainTable.getRowCount();
}
public String getColumnName(int col) {
// this will set the row headers column name
return header[0];
}

public Object getValueAt(int row, int col) {
// this will set the row headers row data
// instead of this;
// "return rowHeaderData[col] + row;"
// this one will generate its own count for each row' cell count
return 1 + row;
}
};

TableColumnModel rowHeaderModel = new DefaultTableColumnModel() {
boolean first = true;
public void addColumn(TableColumn tableColumn) {
if (first) {
tableColumn.setMaxWidth(tableColumn.getPreferredWidth());
super.addColumn(tableColumn);
tableColumn.setMaxWidth(100);
first = false;
}
}
};

String[] columns = {"Item Code", "Item Desciption", "Item Quantity", "Item Cost",
"Cost Extension", "Retail", "Retail Extension", "Expiration Code"};
Object[][] rows = new Object[200][columns.length];
mainTableModel = new DefaultTableModel(rows, columns);
mainTable = new JTable(mainTableModel);
rowHeaderTableColumn = new JTable(tableModel, rowHeaderModel);
rowHeaderTableColumn.createDefaultColumnsFromModel();
rowHeaderTableColumn.setBackground(Color.lightGray);
rowHeaderTableColumn.setColumnSelectionAllowed(false);
rowHeaderTableColumn.setCellSelectionEnabled(false);
jv = new JViewport();
jv.setView(rowHeaderTableColumn);
jv.setPreferredSize(rowHeaderTableColumn.getMaximumSize());
jv.addChangeListener(new RowHeaderAndRowTableSynchronizerChangeListener());
mainTable.setSelectionModel(rowHeaderTableColumn.getSelectionModel());
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
panel.setLayout(new GridLayout());
rowHeaderData = new Integer[mainTable.getRowCount()];
for (int count = 0; count <= mainTable.getRowCount() - 1; count++) {
rowHeaderData[count] = count + 1;
}

scroll = new JScrollPane(mainTable);
scroll.setRowHeader(jv);
scroll.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, rowHeaderTableColumn.getTableHeader());
panel.add(scroll);
getContentPane().add(panel);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500, 250);
setLocationRelativeTo(null);
setVisible(true);
}

// this listener will make the mouseDragged selection event in the rowHeader
// synchronized with the inventoryTable's rows
private class RowHeaderAndRowTableSynchronizerChangeListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
// Keep the scrolling of the row table in sync with main table
JViewport viewport = (JViewport) e.getSource();
JScrollPane scrollPane = (JScrollPane)viewport.getParent();
scrollPane.getVerticalScrollBar().setValue(viewport.getViewPosition().y);
}
}

public static void main(String args[]) {
new JTableRowHeadersAndRowsSynchronized();
}
}