/** MVCFramework.java -- standalone application demonstrating MVC (V2) */

import java.awt.*;
import java.util.*;

// The Shape classes, representing the "Model"

abstract class Shape
{
   public int centerX;
   public int centerY;
   
   Shape(int x, int y)
   {
      centerX = x;
      centerY = y;
   }
   
   // shapes know if a point is inside them or not
   abstract boolean inside(int x, int y);

   // shapes respond to draw methods through multiple polymorphism
   abstract void draw(View v, Graphics g);
}

class Rect extends Shape
{
   public int width;
   public int height;

   Rect(int x, int y, int w, int h)
   {
      super(x, y);
      width = w;
      height = h;
   }

   public boolean inside(int x, int y)
   {
      return (x > centerX-width/2 && x < centerX+width/2 &&
               y > centerY-height/2 && y < centerY+height/2);
   }

   // responds to draw operation calling the specific draw routine
   void draw(View v, Graphics g)
   {
      v.draw((Rect)this, g);
   }
}

class Circle extends Shape
{
   public int radius;

   Circle(int x, int y, int r)
   {
      super(x, y);
      radius = r;
   }

   public boolean inside(int x, int y)
   {
      float xdist = x - centerX;
      float ydist = y - centerY;

      return Math.sqrt(xdist*xdist + ydist*ydist) < radius;
   }

   void draw(View v, Graphics g)
   {
      v.draw((Circle)this, g);
   }
}

class ShapeCanvas extends Canvas
{
   private MVCFramework parent;

   public ShapeCanvas(MVCFramework p)
   {
      parent = p;
   }

   public boolean mouseDown(Event e, int x, int y)
   {
      parent.mousePressed(x, y);
      return true;
   }

}


// The standard shape Controller. Event handling is implemented here.

class Controller
{
   protected Shape shape;
   protected View view;

   Controller(Shape s, View v)
   {
      shape = s;
      view = v;
   }

   void pick(int x, int y)
   {
      view.toggleSelect();
   }

}

// The standard shape View. Drawing operations are implemented here.

abstract class View
{
   private Shape shape;
   protected boolean selected;

   View(Shape s)
   {
      shape = s;
   }

   void toggleSelect()
   {
      selected = !selected;
   } 

   // call the draw on the shape, passing 'this' as a parameter
   void draw(Graphics g)
   {
      shape.draw(this, g);
   }

   // shapes' draw methods call back the specific draw routine
   abstract void draw(Rect r, Graphics g);
   abstract void draw(Circle c, Graphics g);
}

class DisplayView extends View
{

   DisplayView(Shape s)
   {
      super(s);
   }

   // implement the specific draw routines for the display view
   void draw(Rect r, Graphics g)
   {
      if (selected)
         g.fillRect(r.centerX-r.width/2, r.centerY-r.height/2, r.width, r.height);
      else
         g.drawRect(r.centerX-r.width/2, r.centerY-r.height/2, r.width, r.height);
   }

   void draw(Circle c, Graphics g)
   {
      if (selected)
         g.fillOval(c.centerX-c.radius, c.centerY-c.radius,2*c.radius,2*c.radius);
      else
         g.drawOval(c.centerX-c.radius, c.centerY-c.radius,2*c.radius,2*c.radius);
   }
}


// The AWT "Frame"work

abstract class MVCFramework extends Frame
{
    private Canvas canvas;
    private Vector shapes;   // list of Shapes
    private Vector views;   // list of Views
    private Hashtable controllers;   // table of Controllers
   
    public MVCFramework()
    { 
        // create the Frame with title.
        super("MVC Demo"); 
        
        // Add a menubar, with a File menu, with a Quit button.
        MenuBar menubar = new MenuBar();
        Menu file = new Menu("File", true);
        menubar.add(file);
        file.add("Quit");
        file.add("Refresh");
        setMenuBar(menubar);
        
        //  make the Canvas and shape list
        canvas = new ShapeCanvas(this);
        shapes = new Vector();
        views = new Vector();
        controllers = new Hashtable();
        add("Center", canvas);
        resize(300, 300);
        
        startup();
   
        // pop up window
        show();
        draw();
    }
        
    // redraw entire screen
    void draw()
    {
        canvas.getGraphics().clearRect(0, 0, 300, 300);
        for (int i=0; i<views.size(); i++)
        {
            View view = (View)views.elementAt(i);
            view.draw(canvas.getGraphics());
        }
    }

    void addController(Controller controller, Shape shape)
    {
         controllers.put(shape, controller);
    }
    
    void addView(View view)
    {
         views.addElement(view);
    }
    
    void addShape(Shape shape)
    {
         shapes.addElement(shape);
    }
    
    // Handle the  menu buttons.
    public boolean action(Event e, Object arg)
    {
        if (e.target instanceof MenuItem)
        {
            String label = (String) arg;
            if (label.equals("Quit"))
                System.exit(0);
            else if (label.equals("Refresh"))
                draw();
        }
        return false;
    }

   // handle a mouse press
   public void mousePressed(int x, int y)
   {
      for (int i=0; i<shapes.size(); i++)
      {
         Shape shape = (Shape)shapes.elementAt(i);
         if (shape.inside(x, y))
         {
            Controller c = (Controller)controllers.get(shape);
            c.pick(x, y);
            draw();
         }
      }
   }

   abstract void startup();
    
}

/*
 * This is an example Application based on the MVC Framework. It extends
 * the MVCFramework abstract class, as well as the Controller class.
 * It displays a Rect and a Circle which can be selected or deselected.
 * The circle prints something out when this happens.
 */

class DebugView extends View
{

   DebugView(Shape s)
   {
      super(s);
   }

   void draw(Rect r, Graphics g)
   {
      System.out.println("Rectangle: width " + r.width + " height " + r.height);
   }

   void draw(Circle c, Graphics g)
   {
      System.out.println("Circle: radius " + c.radius);
   }
}


class DebugController extends Controller
{
   DebugController(Shape s, View v)
   {
      super(s, v);
   }

   void pick(int x, int y)
   {
      super.pick(x, y);
      System.out.println("picked! "+shape.getClass().getName()+" "+x+" "+y);
   }
} 

class MoveController extends Controller
{
   MoveController(Shape s, View v)
   {
      super(s, v);
   }

   void pick(int x, int y)
   {
      super.pick(x, y);
      shape.centerX = x;
      shape.centerY = y;
   }
} 

class MVCApplication extends MVCFramework
{
   public void startup()
   {
      // create the shapes

      // create a rectangle, attach a MoveController and a DisplayView
      Shape s = new Rect(100, 100, 40, 60);
      addShape(s);
      View v = new DisplayView(s);
      addView(v);
      addController(new MoveController(s, v), s);

      // attach an additional DebugView
      v = new DebugView(s);
      addView(v);

      // create a rectangle, attach a DebugController and DisplayView
      s = new Circle(200, 200, 30);
      addShape(s);
      v = new DisplayView(s);
      addView(v);
      addController(new DebugController(s, v), s);

      // attach an additional DebugView
      v = new DebugView(s);
      addView(v);
   }

   public static void main(String args[])
   {
      new MVCApplication();
   }
}
-------------------------------------------------------------------------------
Russell Turner    x3965    turner@cs.umbc.edu    http://www.cs.umbc.edu/~turner
-------------------------------------------------------------------------------
