// ShapeOutline.java
import java.awt.Graphics;
import java.util.StringTokenizer;
/**
* Class of objects representing shapes that can be
* drawn and their area calculated.
*
* @author D. Nixon
*/
public abstract class ShapeOutline {
/** Width of shape in pixels */
private int width;
/** Count of ShapeOutline objects instantiated so far */
private static int objectCount = 0;
/**
* Creates a ShapeOutline with the specified width.
*
* @param w integer specifying width in pixels
* @exception NegativeSizeException if
* <code>w</code> < 0.
*/
public ShapeOutline( int w )
{
if ( w < 0 )
throw new NegativeSizeException(
getClass().getName()
+ " width " + w + " must be >= 0.");
width = w;
// So that getCount will know how many
// ShapeOutline objects have been created:
objectCount++;
} // constructor ShapeOutline(int)
/**
* Gets this ShapeOutline's width in pixels
*
* @return integer width
*/
public int getWidth() { return width; }
/**
* Draws this ShapeOutline at a specified location
* using a specified Graphics context, and using
* the Graphics context's pre-existing Color.
*
* @param g the Graphics context used
* @param pixelsFromLeft integer distance from left
* side of display area to left side of
* drawing of this ShapeOutline
* @param pixelsFromTop integer distance from top
* of display area to top of drawing of this
* ShapeOutline
*/
public abstract void draw( Graphics g,
int pixelsFromLeft,
int pixelsFromTop );
/**
* Determines approximate number of pixels
* enclosed by this ShapeOutline
*
* @return floating-point area of this
* ShapeOutline in pixels
*/
public abstract float getArea();
/**
* Determines whether this ShapeOutline
* is equal to another object.
*
* @param other the other object.
* @return <code>true</code> if <code>other</code>
* is of the same class and has the same
* width as this ShapeOutline,
* <code>false</code> otherwise.
*/
public boolean equals(Object other)
{
return ( other != null
&& getClass() == other.getClass()
&& width == ((ShapeOutline) other).width );
} // method equals
/**
* Returns a brief string describing
* this ShapeOutline, stating its class,
* width, and other dimension if any.
*/
public String toString()
{
return (getClass().getName() + " width=" + width);
} // method toString
/**
* Returns a full sentence describing this
* ShapeOutline, stating its class, width,
* other dimension, if any, and area.
* (Subclasses should override
* <code>secondDimensionDescriptor</code>
* rather than this method.)
*/
public final String toDescriptorString()
{
return("This " + getClass().getName()
+ " has width " + width
+ secondDimensionDescriptor()
+ " and area " + getArea() + ".");
} // method toDescriptorString()
/**
* Returns text to be inserted after "width"
* in the string returned by
* <code>toDescriptorString</code>.
* Empty by default.
* Should be overridden for a ShapeOutline
* with additional dimensions.
*/
protected String secondDimensionDescriptor() { return ""; }
/**
* Gets a count of ShapeOutline objects instantiated so far.
*
* @return integer number of ShapeOutline objects
*/
public static int getCount()
{
return objectCount;
} // method getCount()
/**
* Creates a ShapeOutline object specified by the
* parameter string <code>line</code>
*
* @param line string with a format consistent with the
* text returned by the toString method of
* at least one ShapeOutline subclass.
*
* @return a ShapeOutline object containing the data
* represented by <code>line</code>
*
* @exception ShapeTextFormatException if <code>line</code>
* is not a valid string representation of
* a ShapeOutline object
*/
public static ShapeOutline parseShape(String line)
{
String exceptionText = line + " <--- ";
StringTokenizer st = new StringTokenizer(line);
if ( ! st.hasMoreTokens() )
throw new ShapeTextFormatException(exceptionText
+ "(empty line)");
String className = st.nextToken();
if ( ! st.hasMoreTokens() )
throw new ShapeTextFormatException(exceptionText
+ "no dimensions");
String widthText = st.nextToken();
StringTokenizer widthTokens
= new StringTokenizer(widthText, "=");
if ( (! widthTokens.hasMoreTokens() )
|| (! widthTokens.nextToken().equals("width") )
|| (! widthTokens.hasMoreTokens() ) )
throw new ShapeTextFormatException(
exceptionText
+ "missing or invalid width text");
try {
int width = Integer.parseInt(widthTokens.nextToken());
String secondDimensionName = "";
int secondDimensionValue = 0;
if ( st.hasMoreTokens() )
{
String secondDimensionText = st.nextToken();
StringTokenizer dimensionTokens
= new StringTokenizer(secondDimensionText, "=");
if ( ! dimensionTokens.hasMoreTokens() )
throw new ShapeTextFormatException(
exceptionText
+ "invalid dimension format: "
+ secondDimensionText);
secondDimensionName = dimensionTokens.nextToken();
if ( ! dimensionTokens.hasMoreTokens() )
throw new ShapeTextFormatException(
exceptionText
+ "invalid dimension format: "
+ secondDimensionText);
secondDimensionValue
= Integer.parseInt(dimensionTokens.nextToken());
} // if
if ( className.equals("RightTriangle") )
{
if ( ! (secondDimensionName.equals("height")) )
throw new ShapeTextFormatException(
exceptionText
+ "Second dimension "
+ secondDimensionName
+ " should be height");
return new RightTriangle(width, secondDimensionValue);
}
else if ( className.equals("Circle") )
return new Circle(width);
else if ( className.equals("Wheel") )
{
if ( ! (secondDimensionName.equals("spokes")) )
throw new ShapeTextFormatException(
exceptionText
+ "Second dimension "
+ secondDimensionName
+ " should be spokes");
return new Wheel(width, secondDimensionValue);
}
else
throw new ShapeTextFormatException(
exceptionText + className
+ " not a known ShapeOutline subclass.");
} // try
catch (NumberFormatException nfe) {
throw new ShapeTextFormatException(exceptionText
+ nfe.getMessage());
} // catch
catch (NegativeSizeException nse) {
throw new ShapeTextFormatException(exceptionText
+ nse.getMessage());
} // catch
} // method parseShape
} // class ShapeOutline