package acm.program;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import junit.framework.Assert;
import acm.graphics.GFillable;
import acm.graphics.GLabel;
import acm.graphics.GLine;
import acm.graphics.GObject;
import acm.graphics.GPoint;
import acm.program.Filter;
public class TestableGraphicsProgram extends GraphicsProgram
{
/**
* getGObject returns an arbitrary shape that meets the specified parameters.
* That arbitrary shape is the first one that appears in the DrawableIterator
* for the canvas.
*
* @param shape the shape of the object. null for any shape.
* @param filter a Filter object that specifies which GObject to return
*
* @return an arbitrary shape that fits the parameters passed, or null
* if no such element exists.
*/
public GObject getGObject(GraphicFilter filter)
{
Iterator iter = iterator();
while(iter.hasNext())
{
GObject gobj = (GObject)iter.next();
if(filter.test(gobj))
return gobj;
}
return null;
}
public <T extends GObject> T getGObject(Class<T> type, GraphicFilter filter)
{
return (T)getGObject(filter.and(GraphicFilter.type(type)));
}
public GObject getExactlyOneGObject(GraphicFilter filter)
{
IllegalStateException ise;
GObject[] gobjs = getAllGObjects(filter);
if(gobjs.length == 0)
{
ise = new IllegalStateException("No GObjects matching filter found.");
StackTraceElement[] stack = ise.getStackTrace();
for(StackTraceElement ste : stack)
{
if(ste.getClassName().startsWith("org.junit.") || ste.getClassName().startsWith("junit."))
{
Assert.fail(ise.getMessage());
}
}
throw ise;
}
else if(gobjs.length > 1)
{
ise = new IllegalStateException("Multiple GObjects matching filter found.");
StackTraceElement[] stack = ise.getStackTrace();
for(StackTraceElement ste : stack)
{
if(ste.getClassName().startsWith("org.junit.") || ste.getClassName().startsWith("junit."))
{
Assert.fail(ise.getMessage());
}
}
throw ise;
}
return gobjs[0];
}
public <T extends GObject> T getExactlyOneGObject(Class<T> type, GraphicFilter filter)
{
return (T)getExactlyOneGObject(filter.and(GraphicFilter.type(type)));
}
/**
* getAllGObjects returns all GObjects on the canvas that meets the specified parameters.
*
* @param shape the shape of the object. null for any shape.
* @param filter a Filter object that specifies which GObjects to return
*
* @return an array of all of the GObjects that match the filter criteria
*/
public GObject[] getAllGObjects(GraphicFilter filter)
{
ArrayList<GObject> matches = new ArrayList<GObject>();
Iterator iter = iterator();
while(iter.hasNext())
{
GObject gobj = (GObject)iter.next();
if(filter.test(gobj))
matches.add(gobj);
}
GObject[] gobjs = new GObject[matches.size()];
int i = 0;
for(GObject gobj : matches)
{
gobjs[i] = gobj;
i++;
}
return gobjs;
}
@SuppressWarnings("unchecked")
public <T extends GObject> T[] getAllGObjects(Class<T> type, GraphicFilter filter)
{
GObject[] gobjs = getAllGObjects(filter.and(GraphicFilter.type(type)));
T[] tobjs = (T[]) Array.newInstance(type, gobjs.length);
for (int i = 0; i < gobjs.length; i++)
{
tobjs[i] = (T) gobjs[i];
}
return tobjs;
}
/**
* hasGObject determines existence of a graphic object that matches the
* specified filter
*
* @param shape the shape of the object. null for any shape.
* @param filter a Filter object that specifies which GObjects to search for
*
* @return true if it has the 2D object specified, false if not.
*/
public boolean hasGObject(GraphicFilter filter)
{
return getGObject(filter) != null;
}
/**
* assert version of hasGObject that has a specific hint to the user.
*
* @param hint error message that should be displayed for a failed assertion
* @param filters array of filters to use describing the object to be found
*/
public void assertHasGObject(String hint, GraphicFilter filter)
{
if(!hasGObject(filter))
Assert.fail(hint);
}
/**
* inverse of assertHasGObject, this method will fail if an object specified
* by the filters is found, succeed otherwise. Prints a custom message in
* the event of failure.
*
* @param hint error message that should be displayed for a failed assertion
* @param filters array of filters to use describing the object to be found
*
*/
public void assertNoGObject(String hint, GraphicFilter filter)
{
if(hasGObject(filter))
Assert.fail(hint);
}
public final void mouseClicked(double x, double y)
{
eventListener.mouseClicked(new MouseEvent(this.getContentPane(),
MouseEvent.BUTTON1,
System.currentTimeMillis(),
MouseEvent.BUTTON1_DOWN_MASK,
(int) x,
(int)y,
1,
false));
}
public final void mousePressed(double x, double y)
{
eventListener.mousePressed(new MouseEvent(this.getContentPane(),
MouseEvent.BUTTON1,
System.currentTimeMillis(),
MouseEvent.BUTTON1_DOWN_MASK,
(int) x,
(int)y,
1,
false));
}
public final void mouseDragged(double x, double y)
{
eventListener.mouseDragged(new MouseEvent(this.getContentPane(),
MouseEvent.BUTTON1,
System.currentTimeMillis(),
MouseEvent.BUTTON1_DOWN_MASK,
(int) x,
(int)y,
1,
false));
}
public final void mouseReleased(double x, double y)
{
eventListener.mouseReleased(new MouseEvent(this.getContentPane(),
MouseEvent.BUTTON1,
System.currentTimeMillis(),
MouseEvent.BUTTON1_DOWN_MASK,
(int) x,
(int)y,
1,
false));
}
public final void mouseMoved(double x, double y)
{
eventListener.mouseMoved(new MouseEvent(this.getContentPane(),
MouseEvent.BUTTON1,
System.currentTimeMillis(),
MouseEvent.BUTTON1_DOWN_MASK,
(int) x,
(int)y,
1,
false));
}
public final void mouseEntered()
{
eventListener.mouseEntered(new MouseEvent(this.getContentPane(),
MouseEvent.MOUSE_ENTERED,
System.currentTimeMillis(),
MouseEvent.BUTTON1,
1,
1,
1,
false));
}
public final void mouseExited()
{
eventListener.mouseExited(new MouseEvent(this.getContentPane(),
MouseEvent.MOUSE_EXITED,
System.currentTimeMillis(),
MouseEvent.BUTTON1,
1,
1,
1,
false));
}
public final void mouseEntered(double x, double y)
{
eventListener.mouseEntered(new MouseEvent(this.getContentPane(),
MouseEvent.MOUSE_ENTERED,
System.currentTimeMillis(),
MouseEvent.BUTTON1,
(int) x,
(int) y,
1,
false));
}
public final void mouseExited(double x, double y)
{
eventListener.mouseExited(new MouseEvent(this.getContentPane(),
MouseEvent.MOUSE_EXITED,
System.currentTimeMillis(),
MouseEvent.BUTTON1,
(int) x,
(int) y,
1,
false));
}
public static abstract class GraphicFilter extends Filter
{
public final GraphicFilter and(final GraphicFilter otherFilter)
{
final GraphicFilter self = this;
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
return self.test(gobj) && otherFilter.test(gobj);
}
};
f.description = "(" + this.description + " AND " + otherFilter.description + ")";
return f;
}
public final GraphicFilter or(final GraphicFilter otherFilter)
{
final GraphicFilter self = this;
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
return self.test(gobj) || otherFilter.test(gobj);
}
};
f.description = "(" + this.description + " OR " + otherFilter.description + ")";
return f;
}
public static final GraphicFilter not(final GraphicFilter otherFilter)
{
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
return !otherFilter.test(gobj);
}
};
f.description = " NOT " + otherFilter.description;
return f;
}
public static final GraphicFilter contains(final GPoint point)
{
GraphicFilter f = new GraphicFilter()
{
public boolean test(GObject gobj)
{
return (gobj.contains(point));
}
};
f.description = "contains ("+ point.getX() + ", " + point.getY() + ")";
return f;
}
public static final GraphicFilter contains(double x, double y)
{
return contains(new GPoint(x, y));
}
public static final GraphicFilter near(final GPoint point)
{
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
double distance = Math.sqrt(Math.pow(point.getX() - gobj.getX(), 2) +
Math.pow(point.getX() - gobj.getX(), 2));
return distance < 50;
}
};
f.description = "near (" + point.getX() + ", " + point.getY() + ")";
return f;
}
public static final GraphicFilter near(double x, double y)
{
return near(new GPoint(x,y));
}
public static final GraphicFilter near(final GPoint point, final double distance)
{
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
double d = Math.sqrt(Math.pow(point.getX() - gobj.getX(), 2) +
Math.pow(point.getX() - gobj.getX(), 2));
return d < distance;
}
};
f.description = "within " + distance + " pixels of (" + point.getX() + ", " + point.getY() + ")";
return f;
}
public static final GraphicFilter near(double x, double y, double distance)
{
return near(new GPoint(x, y), distance);
}
public static final GraphicFilter lineStartingAt(final GPoint point)
{
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
if(!(gobj instanceof GLine))
return false;
return ((GLine)gobj).getStartPoint().equals(point);
}
};
f.description = "line starting at (" + point.getX() + ", " + point.getY() + ")";
return f;
}
public static final GraphicFilter lineStartingAt(double x, double y)
{
return lineStartingAt(new GPoint(x, y));
}
public static final GraphicFilter lineEndingAt(final GPoint point)
{
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
if(!(gobj instanceof GLine))
return false;
return ((GLine)gobj).getEndPoint().equals(point);
}
};
f.description = "line ending at (" + point.getX() + ", " + point.getY() + ")";
return f;
}
public static final GraphicFilter lineEndingAt(double x, double y)
{
return lineEndingAt(new GPoint(x, y));
}
public static final GraphicFilter locatedAt(final GPoint point)
{
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
if(gobj.getLocation().equals(point))
return true;
return false;
}
};
f.description = "located at (" + point.getX() + ", " + point.getY() + ")";
return f;
}
public static final GraphicFilter locatedAt(double x, double y)
{
return locatedAt(new GPoint(x, y));
}
public static final GraphicFilter withText(final String text)
{
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
return gobj instanceof GLabel ? ((GLabel)gobj).getLabel().equals(text) : false;
}
};
f.description = "with text: \"" + text + "\"";
return f;
}
public static final GraphicFilter width(final int width)
{
GraphicFilter f = new GraphicFilter(){
public boolean test( GObject gobj )
{
if(gobj.getWidth() == width)
return true;
return false;
}
};
f.description = "width: " + width;
return f;
}
public static final GraphicFilter height(final int height)
{
GraphicFilter f = new GraphicFilter(){
public boolean test( GObject gobj )
{
if(gobj.getHeight() == height)
return true;
return false;
}
};
f.description = "height: " + height;
return f;
}
public static final GraphicFilter color(final Color color)
{
GraphicFilter f = new GraphicFilter(){
public boolean test( GObject gobj )
{
if(gobj.getColor().equals(color))
return true;
return false;
}
};
f.description = "color: " + color;
return f;
}
public static final GraphicFilter type(final Class c)
{
GraphicFilter f = new GraphicFilter(){
public boolean test(GObject gobj)
{
return c.isAssignableFrom(gobj.getClass());
}
};
f.description = "class: " + c.getSimpleName();
return f;
}
public static final GraphicFilter filled = new GraphicFilter() {
{ this.setDescription("filled"); }
public boolean test(GObject gobj)
{
return GFillable.class.isAssignableFrom(gobj.getClass()) && ((GFillable)gobj).isFilled();
}
};
public static final GraphicFilter not_filled = new GraphicFilter() {
{ this.setDescription("not filled"); }
public boolean test(GObject gobj)
{
return (GFillable.class.isAssignableFrom(gobj.getClass()) && !((GFillable)gobj).isFilled());
}
};
public static final GraphicFilter visible = new GraphicFilter() {
{ this.setDescription("visible"); }
public boolean test(GObject gobj)
{
return gobj.isVisible();
}
};
public static final GraphicFilter not_visible = new GraphicFilter() {
{ this.setDescription("not visible"); }
public boolean test(GObject gobj)
{
return !gobj.isVisible();
}
};
public static final GraphicFilter any = new GraphicFilter() {
{ this.setDescription("any"); }
public boolean test(GObject gobj)
{
return true;
}
};
public abstract boolean test(GObject gobj);
}
}