import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.*;
/**
* @author Dung X. Nguyen
* @author Stephen B. Wong
*/
public class SortCtrl {
public final static int ArraySize = 20;
public final static int TimeSlice = 100; //
private SortGUI _frame = new SortGUI ();
private JTextArea _txtArea = _frame.getOutputTA(); // cached since called many times.
private JPanel _graphCanvas = _frame.getGraphCanvas(); // cached since called many times.
private OCInteger[] _gcDataArray = makeArray ();
private ACompareSorter _aCSorter;
/**
* Updates the view every 100 ms. Redraws array graph and redisplays array text.
*/
private Timer _timer = new Timer (TimeSlice, new ActionListener() {
public void actionPerformed (ActionEvent e) {
updateViews ();
}
});
private ILambda _appendCmd = new ILambda() {
public Object apply (Object x) {
_txtArea.append (""+ ((OCInteger)x).getValue ()+"\n");
return null; // returns "whatever"! Not an issue here.
}
};
/**
* Graphs the whole sorted array as rectangular bars. Uses ArraymapCar to
* traverse the sorted and graph one element at a time with another ILambda.
*/
class GraphBarsCmnd implements ILambda {
private Graphics _g;
private int _xIdx;
private int _maxVal = ArraySize;
private int _minVal = 1;
private int _maxY = ArraySize / 2;
private int _minY = _graphCanvas.getHeight () - _maxY;;
private double _m; // slope
private double _b; // y-intercept; y = _mx + _b.
private ILambda _drawing = new ILambda () { // graphs one element.
/**
* @param x an OCInteger
*/
public Object apply (Object x) {
int dotSize = 10;
_g.setColor (((OCInteger) x).getColor ());
_g.fillRect (dotSize * _xIdx++, (int)(_m * ((OCInteger)x).getValue () + _b),
dotSize- 4 , 10 + _minY - (int)(_m * ((OCInteger)x).getValue () + _b));
return x; // or whatever...
}
};
/**
* Graphs the whole array. The slope and y-intercept are computed here
* in order to adjust dynamically to the window size.
* @param g a Graphics
*/
public Object apply(Object g) {
_g = (Graphics)g;
_xIdx = 0;
_minY = _graphCanvas.getHeight () - _maxY;
_m = ((double)(_maxY - _minY)) / (_maxVal - _minVal);
_b = ((double)(_minY * _maxVal - _maxY * _minVal)) / (_maxVal - _minVal);
return ArrayMapCar.Singleton.apply (_gcDataArray, _drawing);
}
};
public SortCtrl() {
// load the drawing command into _graphCanvas:
((GraphCanvas)_graphCanvas).setDrawable(new GraphBarsCmnd());
_aCSorter = CInsertionSorter.Singleton;
_frame.getInsertionRBtn ().setSelected(true);
// Add a bunch of action listeners:
_frame.getInsertionRBtn ().addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
_aCSorter = CInsertionSorter.Singleton;
}
});
_frame.getQuickRBtn ().addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
_aCSorter = CQuickSorter.Singleton;
}
});
_frame.getMergeRBtn ().addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
_aCSorter = new CMergeSorter (ArraySize);
}
});
_frame.getSelectionRBtn ().addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
_aCSorter = CSelectionSorter.Singleton;
}
});
_frame.getRandomizeBtn ().addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
randomizeBtn_actionPerformed(e);
}
});
_frame.getSortBtn().addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
gSortBtn_actionPerformed (e);
}
});
_frame.validate ();
_frame.setVisible (true);
updateViews ();
}
/**
* Redraws array graph and redisplays array text.
*/
private void updateViews() {
_txtArea.setText ("");
ArrayMapCar.Singleton.apply (_gcDataArray, _appendCmd); // can be done using ILambda anynonymous class.
_graphCanvas.repaint ();
}
/**
* Runs the selected sorting algorithm in a separate thread.
*/
private void gSortBtn_actionPerformed(ActionEvent e) {
setEnabledBtns (false); // all GUI's buttons are disabled.
Thread sortThread = new Thread () {
public void run () {
_aCSorter.init ();
new GraphicSorter (_aCSorter).sort (_gcDataArray, 0, _gcDataArray.length - 1);
setEnabledBtns (true); // At this point, the sorting is done: let's enable all GUI's buttons.
_timer.stop ();
updateViews ();
}
};
_timer.start (); // the timer runs in the main thread.
sortThread.start (); // the sorting runs in a different thread.
}
/**
* Randomizes the data array.
*/
private void randomizeBtn_actionPerformed(ActionEvent e) {
for(int i = 0; i < _gcDataArray.length; i++) {
int x = (int) (_gcDataArray.length * Math.random());
OCInteger tmp = _gcDataArray[i];
_gcDataArray[i] = _gcDataArray[x];
_gcDataArray[x] = tmp;
}
updateViews ();
}
/**
* Creates a sorted data array ranging from 0 to ArraySize - 1 with a "middle-of-the-spectrum"
* RGB color.
*/
private OCInteger[] makeArray () {
int loColorValue = -16*1024*1024;
int hiColorValue = -1;
Color normalColor = new SorterColor((loColorValue+hiColorValue)/2, loColorValue, hiColorValue);
OCInteger[] temp = new OCInteger[ArraySize];
for (int i=0; i < temp.length; i++) {
temp [i] = new OCInteger (i + 1, normalColor);
}
return temp;
}
/**
* Enables/Disables all GUI's buttons.
* @param yes true means enable.
*/
private void setEnabledBtns (boolean yes) {
_frame.getInsertionRBtn ().setEnabled (yes);
_frame.getMergeRBtn ().setEnabled (yes);
_frame.getQuickRBtn ().setEnabled (yes);
_frame.getQuickRBtn ().setEnabled (yes);
_frame.getRandomizeBtn ().setEnabled (yes);
_frame.getSelectionRBtn ().setEnabled (yes);
_frame.getSortBtn ().setEnabled (yes);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {
}
new SortCtrl();
}
}