PertFigure.java
/*
* @(#)PertFigure.java
*
* Project: JHotdraw - a GUI framework for technical drawings
* http://www.jhotdraw.org
* http://jhotdraw.sourceforge.net
* Copyright: © by the original author(s) and all contributors
* License: Lesser GNU Public License (LGPL)
* http://www.opensource.org/licenses/lgpl-license.html
*/
package CH.ifa.draw.samples.pert;
import java.awt.*;
import java.util.*;
import java.io.*;
import CH.ifa.draw.framework.*;
import CH.ifa.draw.standard.*;
import CH.ifa.draw.figures.*;
import CH.ifa.draw.util.*;
/**
* @version <$CURRENT_VERSION$>
*/
public class PertFigure extends CompositeFigure {
private static final int BORDER = 3;
private Rectangle fDisplayBox;
private Vector fPreTasks;
private Vector fPostTasks;
/*
* Serialization support.
*/
private static final long serialVersionUID = -7877776240236946511L;
private int pertFigureSerializedDataVersion = 1;
public PertFigure() {
initialize();
}
public int start() {
int start = 0;
Enumeration i = fPreTasks.elements();
while (i.hasMoreElements()) {
PertFigure f = (PertFigure) i.nextElement();
start = Math.max(start, f.end());
}
return start;
}
public int end() {
return asInt(2);
}
public int duration() {
return asInt(1);
}
public void setEnd(int value) {
setInt(2, value);
}
public void addPreTask(PertFigure figure) {
if (!fPreTasks.contains(figure)) {
fPreTasks.addElement(figure);
}
}
public void addPostTask(PertFigure figure) {
if (!fPostTasks.contains(figure)) {
fPostTasks.addElement(figure);
}
}
public void removePreTask(PertFigure figure) {
fPreTasks.removeElement(figure);
}
public void removePostTask(PertFigure figure) {
fPostTasks.removeElement(figure);
}
private int asInt(int figureIndex) {
NumberTextFigure t = (NumberTextFigure)figureAt(figureIndex);
return t.getValue();
}
private String taskName() {
TextFigure t = (TextFigure)figureAt(0);
return t.getText();
}
private void setInt(int figureIndex, int value) {
NumberTextFigure t = (NumberTextFigure)figureAt(figureIndex);
t.setValue(value);
}
protected void basicMoveBy(int x, int y) {
fDisplayBox.translate(x, y);
super.basicMoveBy(x, y);
}
public Rectangle displayBox() {
return new Rectangle(
fDisplayBox.x,
fDisplayBox.y,
fDisplayBox.width,
fDisplayBox.height);
}
public void basicDisplayBox(Point origin, Point corner) {
fDisplayBox = new Rectangle(origin);
fDisplayBox.add(corner);
layout();
}
private void drawBorder(Graphics g) {
super.draw(g);
Rectangle r = displayBox();
Figure f = figureAt(0);
Rectangle rf = f.displayBox();
g.setColor(Color.gray);
g.drawLine(r.x, r.y+rf.height+2, r.x+r.width, r.y + rf.height+2);
g.setColor(Color.white);
g.drawLine(r.x, r.y+rf.height+3, r.x+r.width, r.y + rf.height+3);
g.setColor(Color.white);
g.drawLine(r.x, r.y, r.x, r.y + r.height);
g.drawLine(r.x, r.y, r.x + r.width, r.y);
g.setColor(Color.gray);
g.drawLine(r.x + r.width, r.y, r.x + r.width, r.y + r.height);
g.drawLine(r.x , r.y + r.height, r.x + r.width, r.y + r.height);
}
public void draw(Graphics g) {
drawBorder(g);
super.draw(g);
}
public Vector handles() {
Vector handles = new Vector();
handles.addElement(new NullHandle(this, RelativeLocator.northWest()));
handles.addElement(new NullHandle(this, RelativeLocator.northEast()));
handles.addElement(new NullHandle(this, RelativeLocator.southWest()));
handles.addElement(new NullHandle(this, RelativeLocator.southEast()));
handles.addElement(new ConnectionHandle(this, RelativeLocator.east(),
new PertDependency())
);
return handles;
}
private void initialize() {
fPostTasks = new Vector();
fPreTasks = new Vector();
fDisplayBox = new Rectangle(0, 0, 0, 0);
Font f = new Font("Helvetica", Font.PLAIN, 12);
Font fb = new Font("Helvetica", Font.BOLD, 12);
TextFigure name = new TextFigure();
name.setFont(fb);
name.setText("Task");
//name.setAttribute("TextColor",Color.white);
add(name);
NumberTextFigure duration = new NumberTextFigure();
duration.setValue(0);
duration.setFont(fb);
add(duration);
NumberTextFigure end = new NumberTextFigure();
end.setValue(0);
end.setFont(f);
end.setReadOnly(true);
add(end);
}
private void layout() {
Point partOrigin = new Point(fDisplayBox.x, fDisplayBox.y);
partOrigin.translate(BORDER, BORDER);
Dimension extent = new Dimension(0, 0);
FigureEnumeration k = figures();
while (k.hasMoreElements()) {
Figure f = k.nextFigure();
Dimension partExtent = f.size();
Point corner = new Point(
partOrigin.x+partExtent.width,
partOrigin.y+partExtent.height);
f.basicDisplayBox(partOrigin, corner);
extent.width = Math.max(extent.width, partExtent.width);
extent.height += partExtent.height;
partOrigin.y += partExtent.height;
}
fDisplayBox.width = extent.width + 2*BORDER;
fDisplayBox.height = extent.height + 2*BORDER;
}
private boolean needsLayout() {
Dimension extent = new Dimension(0, 0);
FigureEnumeration k = figures();
while (k.hasMoreElements()) {
Figure f = k.nextFigure();
extent.width = Math.max(extent.width, f.size().width);
}
int newExtent = extent.width + 2*BORDER;
return newExtent != fDisplayBox.width;
}
public void update(FigureChangeEvent e) {
if (e.getFigure() == figureAt(1)) {
// duration has changed
updateDurations();
}
if (needsLayout()) {
layout();
changed();
}
}
public void figureChanged(FigureChangeEvent e) {
update(e);
}
public void figureRemoved(FigureChangeEvent e) {
update(e);
}
public void notifyPostTasks() {
Enumeration i = fPostTasks.elements();
while (i.hasMoreElements()) {
((PertFigure) i.nextElement()).updateDurations();
}
}
public void updateDurations() {
int newEnd = start()+duration();
if (newEnd != end()) {
setEnd(newEnd);
notifyPostTasks();
}
}
public boolean hasCycle(Figure start) {
if (start == this) {
return true;
}
Enumeration i = fPreTasks.elements();
while (i.hasMoreElements()) {
if (((PertFigure) i.nextElement()).hasCycle(start)) {
return true;
}
}
return false;
}
//-- store / load ----------------------------------------------
public void write(StorableOutput dw) {
super.write(dw);
dw.writeInt(fDisplayBox.x);
dw.writeInt(fDisplayBox.y);
dw.writeInt(fDisplayBox.width);
dw.writeInt(fDisplayBox.height);
writeTasks(dw, fPreTasks);
writeTasks(dw, fPostTasks);
}
public void writeTasks(StorableOutput dw, Vector v) {
dw.writeInt(v.size());
Enumeration i = v.elements();
while (i.hasMoreElements()) {
dw.writeStorable((Storable) i.nextElement());
}
}
public void read(StorableInput dr) throws IOException {
super.read(dr);
fDisplayBox = new Rectangle(
dr.readInt(),
dr.readInt(),
dr.readInt(),
dr.readInt());
layout();
fPreTasks = readTasks(dr);
fPostTasks = readTasks(dr);
}
public Insets connectionInsets() {
Rectangle r = fDisplayBox;
int cx = r.width/2;
int cy = r.height/2;
return new Insets(cy, cx, cy, cx);
}
public Vector readTasks(StorableInput dr) throws IOException {
int size = dr.readInt();
Vector v = new Vector(size);
for (int i=0; i<size; i++) {
v.addElement((Figure)dr.readStorable());
}
return v;
}
}