package husacct.graphics.domain.figures;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;
import java.util.ArrayList;
import java.util.Collection;
import org.jhotdraw.draw.AttributeKeys;
import org.jhotdraw.draw.ConnectionFigure;
import org.jhotdraw.draw.Figure;
import org.jhotdraw.draw.LineConnectionFigure;
import org.jhotdraw.draw.TextFigure;
import org.jhotdraw.draw.connector.Connector;
import org.jhotdraw.draw.event.FigureEvent;
import org.jhotdraw.draw.event.FigureListener;
import org.jhotdraw.draw.handle.BezierNodeHandle;
import org.jhotdraw.draw.handle.BezierOutlineHandle;
import org.jhotdraw.draw.handle.Handle;
import org.jhotdraw.draw.liner.Liner;
import org.jhotdraw.geom.BezierPath.Node;
public class RelationFigure extends BaseFigure implements ConnectionFigure,
FigureListener {
private static final long serialVersionUID = 1805821357919823648L;
private LineConnectionFigure line;
private RelationType relationType;
private TextFigure amountFigure;
private TextFigure fromMultiplicity;
private TextFigure toMultiplicity;
private boolean composite = false;
private boolean isUmlLink = false;
// private boolean violationRelation = false;
public RelationFigure(String name, RelationType relationType, String amount) {
super(name, name, "relation");
this.relationType = relationType;
line = new LineConnectionFigure();
add(line);
fromMultiplicity = new TextFigure();
toMultiplicity = new TextFigure();
amountFigure = new TextFigure(amount);
add(amountFigure);
line.addFigureListener(this);
}
public void setMultiplicity() {
this.isUmlLink = true;
this.fromMultiplicity.setText(composite ? "*" : "1");
}
public void setAmount(String amount){
this.amountFigure.setText(amount);
}
@Override
public void areaInvalidated(FigureEvent e) {
relayout();
relayoutMultiplicities();
}
@Override
public void attributeChanged(FigureEvent e) {
}
@Override
public boolean canConnect(Connector start) {
return line.canConnect(start);
}
@Override
public boolean canConnect(Connector start, Connector end) {
return line.canConnect(start, end);
}
@Override
public void changed() {
line.changed();
amountFigure.changed();
super.changed();
}
@Override
public RelationFigure clone() {
RelationFigure other = (RelationFigure) super.clone();
other.children = new ArrayList<Figure>();
other.line = line.clone();
other.children.add(other.line);
other.amountFigure = amountFigure.clone();
other.children.add(other.amountFigure);
return other;
}
@Override
public Collection<Handle> createHandles(int detailLevel) {
ArrayList<Handle> handles = new ArrayList<Handle>(getNodeCount());
switch (detailLevel) {
case -1:
handles.add(new BezierOutlineHandle(line, true));
break;
case 0:
handles.add(new BezierOutlineHandle(line));
if (getLiner() == null) for (int i = 1, n = getNodeCount() - 1; i < n; i++)
handles.add(new BezierNodeHandle(line, i));
break;
}
return handles;
}
@Override
public void draw(Graphics2D graphics) {
ArrowTipFix arrowTip = new ArrowTipFix(0.5, 7, 3.0);
set(AttributeKeys.END_DECORATION, arrowTip);
ModuleFigure startFigure = (ModuleFigure )line.getStartFigure();
ModuleFigure endFigure = (ModuleFigure )line.getEndFigure();
String startFigureType = startFigure.getType();
String endFigureType = endFigure.getType();
if(isUmlLink) {
if (isPackageType(startFigureType, endFigureType)) {
relationType = RelationType.ATTRIBUTELINK;
} else if (relationType == RelationType.ATTRIBUTELINK){
addMultiplicity();
removeAmountFigure();
} else {
removeAmountFigure();
}
}
switch(relationType) {
case DEPENDENCY:
double dashes = 4.0 / this.get(AttributeKeys.STROKE_WIDTH);
set(AttributeKeys.STROKE_DASHES, new double[] { 6.0, dashes });
break;
case VIOLATION:
set(AttributeKeys.STROKE_DASHES, new double[] { 2.0, 2.0 });
break;
case ATTRIBUTELINK:
// default is a straight line, so do nothing
break;
case INHERITANCELINK:
arrowTip = new ArrowTipFix(0.5, 13.0, 11.5, false, true, false);
set(AttributeKeys.END_DECORATION, arrowTip);
break;
case IMPLEMENTSLINK:
set(AttributeKeys.STROKE_DASHES, new double[] { 4.0, 4.0 });
arrowTip = new ArrowTipFix(0.5, 13.0, 11.5, false, true, true);
set(AttributeKeys.END_DECORATION, arrowTip);
break;
case RULELINK:
// default is a straight line, so do nothing
break;
default:
throw new IllegalStateException("Unknown relation type");
}
super.draw(graphics);
}
private void addMultiplicity() {
add(this.fromMultiplicity);
// add(this.toMultiplicity);
}
private void removeAmountFigure() {
remove(this.amountFigure);
}
private boolean isPackageType(String startFigureType, String endFigureType) {
return endFigureType.equals("package") || startFigureType.equals("package");
}
@Override
public void figureAdded(FigureEvent e) {
}
@Override
public void figureChanged(FigureEvent e) {
}
@Override
public void figureHandlesChanged(FigureEvent e) {
}
@Override
public void figureRemoved(FigureEvent e) {
}
@Override
public void figureRequestRemove(FigureEvent e) {
}
public int getAmount() {
String amountString = amountFigure.getText();
if (amountString.contains("/")){
String dependencyString = amountString.substring(amountString.indexOf("/") + 1);
return Integer.parseInt(dependencyString);
} else {
return Integer.parseInt(amountFigure.getText());
}
}
@Override
public Connector getEndConnector() {
return line.getEndConnector();
}
@Override
public Figure getEndFigure() {
return line.getEndFigure();
}
@Override
public Liner getLiner() {
return line.getLiner();
}
@Override
public Node getNode(int index) {
return line.getNode(index);
}
@Override
public int getNodeCount() {
return line.getNodeCount();
}
@Override
public Double getPoint(int index) {
return line.getPoint(index);
}
@Override
public Connector getStartConnector() {
return line.getStartConnector();
}
@Override
public Figure getStartFigure() {
return line.getStartFigure();
}
@Override
public boolean isLine() {
return true;
}
public RelationType getRelationType() {
return relationType;
}
@Override
public void lineout() {
line.lineout();
}
private void relayout() {
double midX = line.getBounds().x + line.getBounds().width / 2;
double midY = line.getBounds().y + line.getBounds().height / 2;
amountFigure.willChange();
amountFigure.setBounds(new Point2D.Double(midX, midY), null);
amountFigure.changed();
}
public void relayoutMultiplicities(){
double toFigureX = line.getStartPoint().x;
double toFigureY = line.getStartPoint().y;
double fromFigureX = line.getEndPoint().x;
double fromFigureY = line.getEndPoint().y;
double offsetX = toFigureX < fromFigureX ? 15 : -15;
double offsetY = toFigureY < fromFigureY ? 15 : -15;
toFigureX += offsetX;
toFigureY += offsetY;
fromFigureX -= offsetX;
fromFigureY -= offsetY;
fromMultiplicity.willChange();
fromMultiplicity.setBounds(new Point2D.Double(fromFigureX, fromFigureY), null);
fromMultiplicity.changed();
toMultiplicity.willChange();
toMultiplicity.setBounds(new Point2D.Double(toFigureX, toFigureY), null);
toMultiplicity.changed();
}
@Override
public void setBounds(Point2D.Double anchor, Point2D.Double lead) {
line.updateConnection();
relayout();
relayoutMultiplicities();
}
@Override
public void setEndConnector(Connector end) {
line.setEndConnector(end);
}
@Override
public void setEndPoint(Double p) {
line.setEndPoint(p);
}
public void setLineColor(Color newColor) {
set(AttributeKeys.STROKE_COLOR, newColor);
amountFigure.set(AttributeKeys.TEXT_COLOR, newColor);
}
@Override
public void setLiner(Liner newValue) {
willChange();
line.setLiner(newValue);
changed();
}
public void setLineThickness(double thickness) {
set(AttributeKeys.STROKE_WIDTH, thickness);
}
@Override
public void setNode(int index, Node node) {
line.setNode(index, node);
}
@Override
public void setPoint(int index, Double p) {
line.setPoint(index, p);
}
@Override
public void setStartConnector(Connector start) {
line.setStartConnector(start);
}
@Override
public void setStartPoint(Double p) {
line.setStartPoint(p);
}
@Override
public void transform(AffineTransform tx) {
line.updateConnection();
relayout();
relayoutMultiplicities();
}
@Override
public void updateConnection() {
line.updateConnection();
relayout();
relayoutMultiplicities();
}
@Override
public void willChange() {
line.willChange();
amountFigure.willChange();
super.willChange();
}
public void setComposite(boolean composite) {
this.composite = composite;
}
public void setIsUmlLink(boolean isUmlLink) {
this.isUmlLink = isUmlLink;
}
}