// $Id: DrawableModule.java,v 3.1 1998/12/01 14:18:57 te3d Exp $
////////////////////////////////////////////////////////////////////////////
//
// File: DrawableModule.java
//
// Purpose: A DrawableModule is a graphical representation of
// a Module. It can be zoomed or unzoomed. Properties:
//
// o Elliptical shape
// o Name - label
// o Stable - green border is stable, red is unstable // change
// o Editable - white background is yes, gray is no // change
// o Nodes - if zoomed, these form an internal circle
//
// This is a base class, and can used by several modules.
// For that reason, we don't specify the Invoking modules.
//
// Authors:
// txe Travis Emmitt emmitt@virginia.edu
//
// Modifications:
// 28-OCT-1998 txe (v1) Initial creation (was screen.Module)
// 29-OCT-1998 txe Removed GetSelection
// 03-NOV-1998 txe Added comments, removed unused methods.
// 06-NOV-1998 rgb Added version control header info
//
// 13-NOV-1998 txe (v2) Extends Module, added Exceptions
// 16-NOV-1998 txe Improved exceptions, comments
// 19-NOV-1998 txe Shrank nodes
//
// 30-NOV-1998 txe (v3) Improved format, speed, contrast
//
////////////////////////////////////////////////////////////////////////////
import java.applet.*;
import java.awt.*;
public class DrawableModule extends Module {
private DrawableNode drawable_nodes[]; // drawable nodes (for when zoomed)
private int x; // X coordinate of northwest corner
private int y; // Y coordinate of northwest corner
private int w; // width
private int h; // height
private boolean editable; // true iff module is editable
private boolean zoomed; // true iff module is zoomed
private static final double
NODE_SIZE = 0.18; // size of node relative to module
private static final int
MAX_LABEL_LEN = 10, // maximum printable length of label
MIN_EDGE = 1, // minimum edge width
NORMAL_MODE = 0, // normal viewing mode
SHOW_ALL_NODES = 1, // mode option: show all nodes
DEPENDEE_MODE = 2, // mode option: we're a dependee
DEPENDER_MODE = 3; // mode option: we're a depender
private static final Color
LABEL_COLOR = new Color (0.0f, 0.0f, 0.0f), // black
STABLE_FCOLOR = new Color (0.0f, 0.3f, 0.0f), // dk green
STABLE_BCOLOR = new Color (0.8f, 1.0f, 0.8f), // lt green
UNSTABLE_FCOLOR = new Color (0.3f, 0.0f, 0.0f), // dk red
UNSTABLE_BCOLOR = new Color (1.0f, 0.8f, 0.8f), // lt red
EDITABLE_BCOLOR = new Color (0.9f, 0.9f, 1.0f), // white
UNEDITABLE_BCOLOR = null, // background
DEPENDEE_FCOLOR = new Color (1.0f, 1.0f, 1.0f), // white
DEPENDEE_BCOLOR = new Color (0.8f, 0.0f, 0.0f), // red
DEPENDER_FCOLOR = new Color (0.0f, 0.2f, 0.0f), // dk green
DEPENDER_BCOLOR = new Color (1.0f, 1.0f, 0.3f); // yellow
///////////////////////////////////////////////////////////////////
//
// Method: DrawableModule [constructor]
//
// Purpose: This creates a new DrawableModule representing the
// specified Module, with the specified bounds,
// editability, and zoom level.
//
///////////////////////////////////////////////////////////////////
public DrawableModule (Module new_module, int new_bounds[],
boolean new_editable, boolean new_zoomed)
throws BoundsException, IndexException, NewException, NullException {
if (new_module == null) {
throw new NullException ("new_module");
}
if (new_bounds == null) {
throw new NullException ("new_bounds");
}
Copy (new_module);
int i = 0;
try {
x = new_bounds[i++];
y = new_bounds[i++];
w = new_bounds[i++];
h = new_bounds[i++];
}
catch (Exception e) {
throw new IndexException ("new_bounds", i);
}
editable = new_editable;
zoomed = new_zoomed;
// Create and calculate positions of Nodes //
try {
drawable_nodes = new DrawableNode [num_nodes];
}
catch (Exception e) {
throw new NewException ("drawable_nodes", num_nodes);
}
int node_w = (int) (w * NODE_SIZE);
int node_h = (int) (node_w * 0.75);
int base_x = GetCenterX() - (node_w / 2);
int base_y = GetCenterY() - (node_h / 2);
double radius = (double) w * 0.32;
double angle = Math.PI / 2;
double delta = 2 * Math.PI / (double) Math.max (num_nodes, 1);
if (zoomed) {
base_y += (h / 15);
}
else {
radius = radius * 0.8;
}
for (i = 0; i < num_nodes; i++) {
int node_x = base_x + (int) (radius * Math.cos (angle));
int node_y = base_y - (int) (radius * Math.sin (angle));
int node_bounds[] = { node_x, node_y, node_w, node_h };
drawable_nodes[i] = new DrawableNode (nodes[i], node_bounds);
angle -= delta;
}
}
///////////////////////////////////////////////////////////////////
//
// Method: Draw
//
// Purpose: This displays the Module (including its DrawableNodes)
// on the screen.
//
///////////////////////////////////////////////////////////////////
public void Draw (Graphics graphics, int mode)
throws BoundsException, GraphicsException, IndexException, NullException {
if (graphics == null) {
throw new NullException ("graphics");
}
int font_size = (int) (2 * w / MAX_LABEL_LEN);
int label_len = Math.min (name.length(), MAX_LABEL_LEN);
int label_y = GetCenterY() + (int) (font_size / 2);
if (zoomed) {
font_size = font_size / 2;
label_y = GetCenterY() - (int) (h * .365);
}
int label_x = GetCenterX() - ((font_size * label_len) / 4);
String label = name.substring (0, label_len);
boolean stable = IsStable ();
Color edge_color = null;
Color fill_color = null;
Color label_color = null;
if (mode == SHOW_ALL_NODES) {
edge_color = (stable ? STABLE_FCOLOR : UNSTABLE_FCOLOR);
fill_color = (stable ? STABLE_BCOLOR : UNSTABLE_BCOLOR);
label_color = null;
}
else if (mode == DEPENDEE_MODE) {
edge_color = DEPENDEE_FCOLOR;
fill_color = DEPENDEE_BCOLOR;
label_color = edge_color;
}
else if (mode == DEPENDER_MODE) {
edge_color = DEPENDER_FCOLOR;
fill_color = DEPENDER_BCOLOR;
label_color = edge_color;
}
else {
edge_color = (stable ? STABLE_FCOLOR : UNSTABLE_FCOLOR);
fill_color = (editable ? EDITABLE_BCOLOR : UNEDITABLE_BCOLOR);
label_color = LABEL_COLOR;
}
try {
if (fill_color != null) {
graphics.setColor (fill_color);
graphics.fillOval (x, y, w, h);
}
graphics.setColor (edge_color);
graphics.drawOval (x, y, w, h);
if (label_color != null) {
graphics.setColor (label_color);
graphics.setFont (new Font ("Helvetica", Font.PLAIN, font_size));
graphics.drawString (label, label_x, label_y);
}
}
catch (Exception e) {
throw new GraphicsException (e);
}
if (zoomed || mode == SHOW_ALL_NODES) {
for (int i = 0; i < num_nodes; i++) {
GetDrawableNode(i).Draw (graphics, mode);
}
}
}
///////////////////////////////////////////////////////////////////
//
// Method: GetCenterX
//
// Purpose: Returns X coordinate of center of DrawableModule.
//
///////////////////////////////////////////////////////////////////
public int GetCenterX () {
return x + (w / 2);
}
///////////////////////////////////////////////////////////////////
//
// Method: GetCenterX
//
// Purpose: Returns X coordinate of center of specified
// DrawableNode.
//
///////////////////////////////////////////////////////////////////
public int GetCenterX (int node_id)
throws BoundsException, IndexException, NullException {
if (node_id < 0) {
return GetCenterX();
}
return GetDrawableNode(node_id).GetCenterX ();
}
///////////////////////////////////////////////////////////////////
//
// Method: GetCenterY
//
// Purpose: Returns Y coordinate of center of Module.
//
///////////////////////////////////////////////////////////////////
public int GetCenterY () {
return y + (h / 2);
}
///////////////////////////////////////////////////////////////////
//
// Method: GetCenterY
//
// Purpose: Returns Y coordinate of center of specified Node.
//
///////////////////////////////////////////////////////////////////
public int GetCenterY (int node_id)
throws BoundsException, IndexException, NullException {
if (node_id < 0) {
return GetCenterY();
}
return GetDrawableNode(node_id).GetCenterY ();
}
///////////////////////////////////////////////////////////////////
//
// Method: GetDrawableNode
//
// Purpose: Returns reference to specified DrawableNode.
//
///////////////////////////////////////////////////////////////////
public DrawableNode GetDrawableNode (int node_id)
throws BoundsException, IndexException, NullException {
if (node_id < 0 || node_id >= num_nodes) {
throw new BoundsException ("node_id", node_id, 0, num_nodes - 1);
}
DrawableNode drawable_node = null;
try {
drawable_node = drawable_nodes[node_id];
}
catch (Exception e) {
throw new IndexException ("drawable_nodes", node_id);
}
if (drawable_node == null) {
throw new NullException ("drawable_nodes", node_id);
}
return drawable_node;
}
///////////////////////////////////////////////////////////////////
//
// Method: Inside
//
// Purpose: This returns true if the specified coordinate
// is within the DrawableModule, false otherwise.
//
///////////////////////////////////////////////////////////////////
public boolean Inside (int new_x, int new_y) {
double dx = new_x - GetCenterX ();
double dy = new_y - GetCenterY ();
dy = (double) (dy * w) / (double) Math.max (h, 1);
return (Math.sqrt ((dx * dx) + (dy * dy)) < (double) w / 2);
}
///////////////////////////////////////////////////////////////////
//
// Method: InsideNode
//
// Purpose: This returns true if the specified coordinate is within
// the bounds of the specified DrawableNode, else false.
//
///////////////////////////////////////////////////////////////////
public boolean InsideNode (int node_id, int x, int y)
throws BoundsException, IndexException, NullException {
if (!zoomed) {
return false;
}
return GetDrawableNode(node_id).Inside (x, y);
}
}
////////////////////////////////////////////////////////////////////////////