import java.util.ArrayList; import java.awt.Color; import java.io.Serializable; /**** * * Class WorkSpace has a list of shapes, with methods to update and interrogate * the list. See the CSC 102 Program 3 spec for details. * * @author Gene Fisher (gfisher@calpoly.edu) * */ public class WorkSpace implements Serializable { /** The list of shapes in this workspace */ private ArrayList shapes = new ArrayList(); /** A reference to the currently selected shape. */ private Shape selection = null; /** * Add the given shape to the end of the list. */ public void add(Shape shape) { shapes.add(shape); } /** * Remove the Shape at the given index and return a reference to it or null * if the index is out-of-bounds. */ public Shape remove(int index) { if (index < 0 || index >= shapes.size()) { return null; } return shapes.remove(index); } /** * Remove the current selection, if any. Do nothing if no current * selection. */ public void remove() { if (selection != null) { shapes.remove(shapes.indexOf(selection)); selection = null; } } /** * Remove all of the shapes in this. Note that this method reassigns * this.shapes to a new (empty) ArrayList. This reassignment behavior is * not an issue at present, since there is no getShapes access method. If * in future such a method is added, it will be caveat caller in terms of * shared access to a common shapes list object. */ public void removeAll() { shapes = new ArrayList(); selection = null; } /** * Return the indexth Shape object from this WorkSpace. */ public Shape get(int index) { if (index < 0 || index >= shapes.size()) { return null; } return shapes.get(index); } /** * Return the number of Shapes contained in this WorkSpace. */ public int size() { return shapes.size(); } /** * Return an ArrayList of all of the Circle objects contained in this * WorkSpace. */ public ArrayList getCircles() { ArrayList circles = new ArrayList(); for (Shape s : shapes) { if (s instanceof Circle) { circles.add((Circle) s); } } return circles; } /** * Return an ArrayList of all of the Rectangle objects contained in this * WorkSpace. */ public ArrayList getRectangles() { ArrayList rects = new ArrayList(); for (Shape s : shapes) { if ((s instanceof Rectangle) && ! (s instanceof Square)) { rects.add((Rectangle) s); } } return rects; } /** * Return an ArrayList of all of the Triangle objects contained in this * WorkSpace. */ public ArrayList getTriangles() { ArrayList tris = new ArrayList(); for (Shape s : shapes) { if (s instanceof Triangle) { tris.add((Triangle) s); } } return tris; } /** * Return an ArrayList of all of the ConvexPolygon objects contained in * this WorkSpace. */ public ArrayList getConvexPolygons() { ArrayList polys = new ArrayList(); for (Shape s : shapes) { if (s.getClass() == ConvexPolygon.class) { polys.add((ConvexPolygon) s); } } return polys; } /** * Return an ArrayList of all Shape objects in the WorkSpace that match the * specified Color. */ public ArrayList getShapesByColor(Color color) { ArrayList list = new ArrayList(); for (Shape s : shapes) { if (s.getColor().equals(color)) { list.add(s); } } return list; } /** * Return the sum of the area of all Shape objects in the WorkSpace. */ public double getAreaOfAllShapes() { double area = 0; for (Shape s : shapes) { area += s.getArea(); } return area; } public Shape getSelection() { return selection; } /** * Set the current selection to the given shape, null included. This * method ensures that at most one shape is selected an any time. It does * so by (a) setting the current selection's selected flag to false (if the * current selection is non-null); (b) replacing the current selection with * the given selection; (c) setting the new selection's selected flag to * true (if the new selection is non-null). * * Note well that this is model-only selection. This method does nothing * with the canvas to highlight the selection. That's the job of whoever * calls this method, if the caller so chooses. */ public void setSelection(Shape s) { /* * Quit quickly if s is the same as the current selection. */ if (s == selection) { return; } /* * If the current selection is non-null, set its selected flag to * false. */ if (selection != null) { selection.selected = false; } /* * If the new selection is non-null, set its selected flag to true. */ if (s != null) { s.selected = true; } /* * In with the new, out with the old. */ selection = s; } /** * Set the current selection to the one with the given index i. This method * fails quitely, and sets the selection to null, if i is out of range, * i.e., < 0 or >= shapes.size(). A more robust version, i.e., one not * required in a CSC 102 class, would check for i being in range, and do * something smart if not, e.g., throw an exception. */ public void setSelection(int i) { Shape s = i >= 0 && i < shapes.size() ? shapes.get(i) : null; setSelection(s); } /** * Set the shapes list of this workspace to the shapes list in the given * other workspace. This method is used by the FileOpen dialog, q.v. */ public void setShapes(WorkSpace other) { shapes = other.shapes; } /** * Print the string representation of this, a newline-separated list of * shapes, each on eo which is output by its own toString method. */ public String toString() { return "Size = " + shapes.size() + shapes.toString(); } /** * Return the frontmost selection under the given x,y coordinates. See the * class comment for SelectingMovingListener for the precise definition of * what it means for a shape to be "under" a point at a given pair of mouse * coordinates. The given canvas height is used to de-normalize the y * coordinate so we can play nice with awt. */ public Shape getSelectionAt(int x, int y, int canvas_height) { Shape shape; // the next shape in the list java.awt.Shape jshape; // the Java awt rep of the shape /* * De-normalize y. */ int jy = canvas_height - y; /* * Build a 4x4 rectangle around the point, to be used in the intersects * query. */ java.awt.Rectangle rect = new java.awt.Rectangle( x - 2, jy - 2, 4, 4); /* * Cruise backwards through the shape list, looking for the first shape * that's under the given coordinates. */ for (int i = shapes.size() - 1; i >= 0; i--) { /* * Get the ith shape in the list. */ shape = shapes.get(i); /* * Get the Java awt rep of the shape, since that's what the * interesects and contains methods need. */ jshape = shape.getAwtRep(canvas_height); /* * Check first if the 4x4 rect intersects the jshape. If it does, * we've found the shape we're after, so we're done. */ if ((jshape.intersects(rect) && !(jshape.contains(rect)))) { return shape; } /* * If the shape is filled or text, check if the jshape contains the * rect, and if so we're done. */ if ((shape.getFilled() || shape instanceof Text) && jshape.contains(rect)) { return shape; } } /* * Return null if we've run out of shapes. */ return null; } /** * Move the current selection forward one position in the list, where * "forward" is a positive increment of the workspace index. Do nothing if * the current selection is already the frontmost shape, or there is no * current selection. */ public void moveForward() { if (selection != null) { int i = shapes.indexOf(selection); if (i < shapes.size() - 1) { swap(i, i+1); } } } /** * Move the current selection back one position in the list, where "back" * is a decrement of the workspace index. Do nothing if the current * selection is already the backmost shape, or there is no current * selection. */ public void moveBackward() { if (selection != null) { int i = shapes.indexOf(selection); if (i > 0) { swap(i, i-1); } } } /** * Move the current selection to the front of the list, where "front" means * at the highest index position. Between the end of the list and the * index of the current selection, shift each shape back one position. Do * nothing if the current selection is already the frontmost shape, or * there is no current selection. */ public void moveToFront() { if (selection != null) { for (int i = shapes.indexOf(selection); i < shapes.size() - 1; i++) { swap(i, i+1); } } } /** * Move the current selection to the back of the list, where "back" means * index 0. Between the beginning of the list and the index of the current * selection, shift each shape forward one position. Do nothing if the * current selection is already the frontmost shape, or there is no current * selection. */ public void moveToBack() { if (selection != null) { for (int i = shapes.indexOf(selection); i > 0; i--) { swap(i, i-1); } } } /** * Swap the shapes at positions i and j. */ private void swap(int i, int j) { Shape temp = shapes.get(i); shapes.set(i, shapes.get(j)); shapes.set(j, temp); } /** * Darn I hate type "System.out.println" a gazillion times. */ void p(String s) {System.out.println(s);} }