SortCtrl.java
Created with JBuilder
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();
    }
}

SortCtrl.java
Created with JBuilder