package ballworld; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.Timer; import command.*; /** * The "Controller" in a Model-View-Controller architecture * Sets up the appropriate wiring between the model and the view. * Uses event handlers to respond to user input and notifies the model and the view to update accordingly. * Uses a Timer object to update the model and the view at a regular time slice. This will give the effect of animation.   * @dependency ballModel.IStrategy uses * @dependency javax.swing.Timer uses */ public class BallControl { private IRandomizer _rand ; private int _MaxRadius = 20; private int _MinRadius = 5; private int _MaxSpeed = 20; private Rectangle _MaxVel = new Rectangle(-_MaxSpeed,-_MaxSpeed, _MaxSpeed, _MaxSpeed); private BallGUI _frame; private Dispatcher _dispatcher = new Dispatcher(); private SwitcherStrategy _switcher = new SwitcherStrategy(); private ILambda _paintCmd = new ILambda() { public Object apply(Object g) { _dispatcher.notifyAll(g); return null; } }; private ILambda _makeBallCmd = new ILambda(){ public Object apply(Object classname) { _dispatcher.addObserver(loadBall(loadStrategy((String)classname))); return null; } }; private ILambda _makeSwitcherCmd = new ILambda(){ public Object apply(Object nu) { _dispatcher.addObserver(loadBall(_switcher)); return null; } }; private ILambda _switchCmd = new ILambda(){ public Object apply(Object classname) { _switcher.setStrategy(loadStrategy((String) classname)); return null; } }; private ILambda _clearBallsCmd = new ILambda(){ public Object apply(Object nu) { _dispatcher.deleteObservers(); return null; } }; private int TimeSlice = 50; private Timer _timer = new Timer (TimeSlice, new ActionListener () { public void actionPerformed (ActionEvent e) { _frame.getContainer().repaint(); // _frame.repaint(); } }); /** * Constructor for the BallControl class * Instantiates the BallGUI frame with the required ILambdas for * making a ball, clearing the balls from the screen and for * painting the balls onto the Container * Starts the timer up. */ public BallControl (IRandomizer rand) { _rand = rand; _frame = new BallGUI (_makeBallCmd, _clearBallsCmd, _paintCmd, _makeSwitcherCmd, _switchCmd); _frame.validate (); _frame.setVisible (true); _timer.start (); } private Ball loadBall(IUpdateStrategy strategy) { return new Ball(_rand.randomLoc(_frame.getContainer().getSize()), _rand.randomInt(_MinRadius, _MaxRadius), _rand.randomVel(_MaxVel), _rand.randomColor(), _frame.getContainer(), strategy); } /** * Uses dynamic class loading to load and instantiate an ABall subclass, given * its class name. */ private IUpdateStrategy loadStrategy(String className) { try { java.lang.reflect.Constructor c = Class.forName(className).getConstructors()[0]; Object []args = new Object[]{ }; return (IUpdateStrategy) c.newInstance(args); } catch(Exception ex) { System.err.println("Class "+className+" not found! Using StraightStrategy instead."); return new StraightStrategy(); } } /** * Entry point to the program. Instantiates a BallControl object and goes away. */ public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch(Exception e) { } new BallControl(Randomizer.Singleton); } }