package agg.editor.impl;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.util.Vector;
import java.util.Hashtable;
import javax.swing.undo.*;
import agg.attribute.AttrEvent;
import agg.attribute.AttrInstance;
import agg.attribute.view.AttrViewEvent;
import agg.attribute.view.AttrViewObserver;
import agg.attribute.view.AttrViewSetting;
import agg.attribute.impl.AttrTupleManager;
import agg.attribute.impl.ValueTuple;
import agg.attribute.impl.ValueMember;
import agg.attribute.impl.VarTuple;
import agg.attribute.impl.VarMember;
import agg.attribute.impl.ContextView;
import agg.util.XMLHelper;
import agg.util.XMLObject;
import agg.xt_basis.Arc;
import agg.xt_basis.Graph;
import agg.xt_basis.GraphObject;
import agg.xt_basis.Node;
import agg.xt_basis.TypeException;
import agg.gui.editor.EditorConstants;
import agg.gui.editor.GraphPanel;
import agg.layout.evolutionary.LayoutArc;
/**
* EdArc specifies an arc layout of an agg.xt_basis.Arc object
*
* @author $Author: olga $
* @version $Id: EdArc.java,v 1.60 2010/11/14 12:59:11 olga Exp $
*/
public class EdArc extends EdGraphObject implements AttrViewObserver,
XMLObject, StateEditable {
private Arc bArc;
private EdGraphObject from;
private EdGraphObject to;
private boolean directed = true;
private Point anchor;
transient private int anchorID = 0; // only for loop
transient private boolean hasDefaultAnchor;
transient private Point arrowPoint;
transient private Point tailPoint;
transient private Point textLocation;
protected Point textOffset, origTextOffset;
transient private Dimension textSize;
transient private Point srcMultiplicityLocation;
transient private Dimension srcMultiplicitySize;
transient private Point srcMultiplicityOffset;
transient private Point trgMultiplicityLocation;
transient private Dimension trgMultiplicitySize;
transient private Point trgMultiplicityOffset;
transient private int partOfText; // 0 attrText, 1/2 src/trg
private LayoutArc lArc;
/**
* Creates an arc layout specified by the EdType eType for an used object
* specified by the Arc bArc, EdGraphObject from, EdGraphObject to
*/
public EdArc(Arc bArc, EdType eType, EdGraphObject from, EdGraphObject to) throws TypeException {
super(eType);
if (bArc == null || bArc.getSource() == null || bArc.getTarget() == null) {
throw new TypeException("Basic node is null");
}
this.bArc = bArc;
this.from = from;
this.to = to;
this.directed = bArc.isDirected();
this.anchor = null;
this.hasDefaultAnchor = true;
this.x = 0;
this.y = 0;
this.w = 0;
this.h = 0;
this.textOffset = new Point(0, -22);
this.textLocation = new Point();
this.textSize = new Dimension();
if (this.bArc != null) {
this.contextUsage = String.valueOf(this.hashCode());
if (this.bArc.getAttribute() != null) {
addToAttributeViewObserver();
}
}
this.lArc = new LayoutArc(this);
}
/**
* Creates an arc layout specified by the EdType eType, EdGraphObject from,
* EdGraphObject to for an used object of the class agg.xt_basis.Arc that
* would be created from the graph specified by the Graph bGraph
*/
public EdArc(Graph bGraph, EdType eType, EdGraphObject from,
EdGraphObject to) throws TypeException {
this(bGraph, eType, from, to, null);
}
/**
* Creates an arc layout specified by the EdType eType, EdGraphObject from,
* EdGraphObject to, Point anchor ( bend ) for an used object of the class
* agg.xt_basis.Arc that would be created from the graph specified by the
* Graph bGraph
*/
public EdArc(Graph bGraph, EdType eType, EdGraphObject from,
EdGraphObject to, Point anchor) throws TypeException {
this((bGraph != null) ? bGraph.createArc(eType.bType, (Node) from
.getBasisObject(), (Node) to.getBasisObject()) : null, eType,
from, to);
setAnchor(anchor);
}
/** Marks this as element of a type graph */
public void markElementOfTypeGraph(boolean val) {
this.elemOfTG = val;
if (this.elemOfTG && !this.getContext().isInheritanceType(this.eType)) {
createMultiplicityVars();
}
}
private void createMultiplicityVars() {
if (this.srcMultiplicityLocation == null)
this.srcMultiplicityLocation = new Point();
if (this.srcMultiplicitySize == null)
this.srcMultiplicitySize = new Dimension();
if (this.srcMultiplicityOffset == null)
this.srcMultiplicityOffset = new Point();
if (this.trgMultiplicityLocation == null)
this.trgMultiplicityLocation = new Point();
if (this.trgMultiplicitySize == null)
this.trgMultiplicitySize = new Dimension();
if (this.trgMultiplicityOffset == null)
this.trgMultiplicityOffset = new Point();
}
/** Disposes myself */
public void dispose() {
if (this.attrObserver) {
removeFromAttributeViewObserver();
}
this.view = null;
if (this.lArc != null)
this.lArc.dispose();
this.lArc = null;
this.eGraph = null;
this.eType = null;
this.from = null;
this.to = null;
this.bArc = null;
this.myGraphPanel = null;
}
public void finalize() { }
public void storeState(Hashtable<Object, Object> state) {
ArcReprData data = new ArcReprData(this);
state.put(Integer.valueOf(this.hashCode()), data);
state.put(Integer.valueOf(data.hashCode()), data);
this.itsUndoReprDataHC = Integer.valueOf(data.hashCode());
}
public void restoreState(Hashtable<?, ?> state) {
// System.out.println("EdArc.restoreState:: "+state.get(Integer.valueOf(this.hashCode()))+" "+state.get(this.itsUndoReprDataHC));
ArcReprData data = (ArcReprData) state.get(Integer.valueOf(this.hashCode()));
if (data == null) {
data = (ArcReprData) state.get(this.itsUndoReprDataHC);
}
if (data != null) {
data.restoreArcFromArcRepr(this);
this.attrChanged = false;
}
}
public void restoreState(Hashtable<?, ?> state, String hashCode) {
// System.out.println("### EdArc.restoreState:: "+state.get(Integer.valueOf(hashCode))+" "+state.get(this.itsUndoReprDataHC));
ArcReprData data = (ArcReprData) state.get(Integer.valueOf(hashCode));
if (data == null) {
data = (ArcReprData) state.get(this.itsUndoReprDataHC);
}
if (data == null) {
data = (ArcReprData) state.get(Integer.valueOf(this.hashCode()));
}
if (data != null) {
data.restoreArcFromArcRepr(this);
this.attrChanged = false;
}
}
public void restoreState(ArcReprData data) {
data.restoreArcFromArcRepr(this);
this.attrChanged = false;
}
/** Returns an open view of my attribute */
protected AttrViewSetting getView() {
if (!this.init || this.view == null) {
this.view = ((AttrTupleManager)AttrTupleManager.getDefaultManager()).getDefaultOpenView();
this.view.setAllVisible(this.bArc.getAttribute(), true);
this.init = true;
}
return this.view;
}
public void setAttrViewSetting(AttrViewSetting aView) {
this.view = aView;
if (!this.attrObserver) {
this.view.addObserver(this, this.bArc.getAttribute());
this.attrObserver = true;
}
this.init = true;
}
public void addToAttributeViewObserver() {
getView().addObserver(this, this.bArc.getAttribute());
this.attrObserver = true;
}
public void removeFromAttributeViewObserver() {
if (this.bArc != null
&& this.bArc.getAttribute() != null
&& this.view != null) {
this.view.removeObserver(this, this.bArc.getAttribute());
this.view.getMaskedView()
.removeObserver(this, this.bArc.getAttribute());
}
}
public void createAttributeInstance() {
if (this.bArc != null && this.bArc.getAttribute() == null) {
this.bArc.createAttributeInstance();
addToAttributeViewObserver();
}
}
public void refreshAttributeInstance() {
if (this.bArc != null && this.bArc.getAttribute() != null) {
((ValueTuple) this.bArc.getAttribute()).getTupleType().refreshParents();
addToAttributeViewObserver();
}
}
/** Returns the layout arc of this arc. */
public LayoutArc getLArc() {
return this.lArc;
}
/** Returns the used object */
public final Arc getBasisArc() {
return this.bArc;
}
/** Returns the used object of this arc. */
public final GraphObject getBasisObject() {
return this.bArc;
}
/** Returns FALSE */
public final boolean isNode() {
return false;
}
/** Returns TRUE */
public final boolean isArc() {
return true;
}
/** Returns NULL */
public final EdNode getNode() {
return null;
}
/** Returns this arc */
public final EdArc getArc() {
return this;
}
public void setCritical(boolean b) {
this.bArc.setCritical(b);
}
public boolean isCritical() {
return this.bArc.isCritical();
}
/**
* States how to draw critical objects of CPA critical overlapping graphs:
* <code>EdGraphObject.CRITICAL_GREEN</code> or
* <code>EdGraphObject.CRITICAL_BLACK_BOLD</code>.
*/
public void setDrawingStyleOfCriticalObject(int criticalStyle) {
this.criticalStyle = criticalStyle;
}
/** Returns TRUE if this uses a line for the graphic */
public final boolean isLine() {
if (!this.from.equals(this.to))
return true;
return false;
}
/** Returns TRUE if <code>this</code> has a bend */
public boolean hasAnchor() {
return (((this.anchor != null) && !this.hasDefaultAnchor) ? true : false);
}
/** Returns the point of my bend (I am a line) */
public Point getAnchor() {
if (this.anchor != null)
return this.anchor;
if (isLine())
return new Point(getX(), getY());
return null;
}
/** Returns the point of my bend specified by the int id (I am a loop) */
public Point getAnchor(int id) {
if (this.anchor != null)
return this.anchor;
if (!isLine()) {
Loop loop = toLoop();
return loop.getAnchor(id);
}
return null;
}
/** Returns the id of my bend */
public int getAnchorID() {
return this.anchorID;
}
/** Returns TRUE if <code>this</code> has only one direction */
public boolean isDirected() {
if (this.bArc != null) {
this.directed = this.bArc.isDirected();
}
return this.directed;
}
public boolean isVisible() {
if (this.bArc != null) {
this.visible = this.bArc.isVisible() && this.from.isVisible() && this.to.isVisible();
if (this.getContext().getBasisGraph().isCompleteGraph()) {
this.visible = this.visible
&& this.getType().getBasisType().isObjectOfTypeGraphArcVisible(
this.getSource().getType().getBasisType(),
this.getTarget().getType().getBasisType());
}
}
return this.visible;
}
/**
* Returns the attributes which are shown
*/
public Vector<Vector<String>> getAttributes() {
// maybe this method can be moved to EdGraphObjec
Vector<Vector<String>> attrs = new Vector<Vector<String>>();
if (this.bArc != null && this.bArc.getAttribute() != null) {
AttrInstance attributes = this.bArc.getAttribute();
if (attributes != null && getView() != null) {
AttrViewSetting mvs = this.view.getMaskedView();
int number = mvs.getSize(attributes);
for (int i = 0; i < number; i++) {
Vector<String> tmpAttrVector = new Vector<String>();
int index = mvs.convertSlotToIndex(attributes, i);
tmpAttrVector.addElement(attributes.getTypeAsString(index));
tmpAttrVector.addElement(attributes.getNameAsString(index));
tmpAttrVector
.addElement(attributes.getValueAsString(index));
attrs.addElement(tmpAttrVector);
}
} else
attrs = setAttributes(this.bArc);
}
return attrs;
}
/** Sets my attributes to the attributes specified by the Arc bArc */
public Vector<Vector<String>> setAttributes(Arc bArc) {
Vector<Vector<String>> attrs = new Vector<Vector<String>>();
if (bArc == null)
return attrs;
if (bArc.getAttribute() == null)
return attrs;
int nattrs = bArc.getAttribute().getNumberOfEntries();
if (nattrs != 0) {
for (int i = 0; i < nattrs; i++) {
Vector<String> attr = new Vector<String>();
attr.addElement(bArc.getAttribute().getTypeAsString(i));
attr.addElement(bArc.getAttribute().getNameAsString(i));
attr.addElement(bArc.getAttribute().getValueAsString(i));
attrs.addElement(attr);
}
}
return attrs;
}
/** Sets my attributes to the attributes specified by the GraphObject obj */
public Vector<Vector<String>> setAttributes(GraphObject obj) {
return setAttributes((Arc) obj);
}
/** Sets my used object specified by the Arc bArc */
public void setBasisArc(Arc bArc) {
this.bArc = bArc;
}
/** Gets my source object */
public EdGraphObject getSource() {
return this.from;
}
/** Sets my source object */
public void setSource(EdGraphObject en) {
this.from = en;
}
/** Gets my target object */
public EdGraphObject getTarget() {
return this.to;
}
/** Sets my target object */
public void setTarget(EdGraphObject en) {
this.to = en;
}
/** Sets my direction */
public void setDirected(boolean direct) {
this.directed = direct;
if (this.bArc != null)
this.bArc.setDirected(direct);
}
/**
* Sets my bend (I am a line) to the position specified by the Point
* newAnchor
*/
public void setAnchor(Point newAnchor) {
this.anchor = newAnchor;
if (this.anchor == null) {
this.hasDefaultAnchor = true;
} else if (isLine()) {
setXY(this.anchor.x, this.anchor.y);
this.hasDefaultAnchor = false;
} else { // Loop
setAnchor(Loop.UPPER_LEFT, newAnchor);
}
}
/**
* Sets my bend (I am a loop) specified by the int id to the position
* specified by the Point newAnchor
*/
public void setAnchor(int id, Point newAnchor) {
this.anchor = newAnchor;
if (this.anchor == null) {
this.hasDefaultAnchor = true;
} else if (!isLine() && id == Loop.UPPER_LEFT) { /*
* 1 : anchor of
* loop
*/
setXY(this.anchor.x, this.anchor.y);
this.hasDefaultAnchor = false;
}
}
/** Sets my representation features: directed, visible, selected */
public void setReps(boolean direct, boolean vis, boolean sel) {
setDirected(direct);
setVisible(vis);
setSelected(sel);
}
/**
* Makes an exact copy. Only the basis arc is the same.
*/
public EdArc copy() {
try {
EdArc newArc = new EdArc(this.bArc, this.eType, this.from, this.to);
newArc.setAnchor(getAnchor());
return newArc;
} catch (TypeException ex) {
return null;
}
}
/** Gets myself as a line representation */
public final Line toLine() {
Line line = new Line(this.from.getX(), this.from.getY(), this.to.getX(), this.to.getY());
if ((this.anchor != null))
line.setAnchor(new Point(this.anchor.x, this.anchor.y));
return line;
}
/** Gets myself as a loop (rectangle) representation */
public final Loop toLoop() {
Loop loop = new Loop(this.x, this.y, this.w, this.h);
return loop;
}
/** Returns the size of the text */
public Dimension getTextSize(FontMetrics fm) {
this.textSize.setSize(new Dimension(super.getTextWidth(fm), super
.getTextHeight(fm)));
return this.textSize;
}
/** Updates the size of the text */
public void updateTextSize(FontMetrics fm) {
this.textSize.setSize(new Dimension(super.getTextWidth(fm), super
.getTextHeight(fm)));
}
/** Returns the text offset */
public Point getTextOffset() {
return this.textOffset;
}
/** Sets the text offset */
public void setTextOffset(int xOffset, int yOffset) {
this.textOffset.x = xOffset;
this.textOffset.y = yOffset;
}
/**
* Translates offset of an edge text to a new value specified by the dx and
* dy, if the text will be moved. The text can be an attribute text or a
* source multiplicity text or a target multiplicity text.
*/
public void translateTextOffset(int dx, int dy) {
if (this.partOfText == 0) {
this.textOffset.translate(dx, dy);
} else if (this.partOfText == 1) {
this.srcMultiplicityOffset.translate(dx, dy);
} else if (this.partOfText == 2) {
this.trgMultiplicityOffset.translate(dx, dy);
}
}
/**
* Returns TRUE if the point specified by the int X, int Y is inside of
* myself
*/
int in_offset = 10;
public boolean inside(int X, int Y) {
this.anchorID = 0;
Rectangle r = null;
if (isLine()) {
// check rectangle around the middle
r = new Rectangle(this.x - this.w/2 -in_offset,
this.y - this.h/2 -in_offset,
this.w +in_offset*2, this.h +in_offset*2);
if (r.contains(X, Y)) {
return true;
}
Point p = new Point(this.x, this.y);
if (this.anchor != null)
p = this.anchor;
if (this.arrowPoint != null) {
if (Line.inside(X, Y, p, this.arrowPoint, this.w +(in_offset*2)))
return true;
}
if (this.tailPoint != null) {
if (Line.inside(X, Y, this.tailPoint, p, this.w +(in_offset*2)))
return true;
}
return false;
}
/* Loop */
Loop loop = toLoop();
if (loop.contains(new Point(X, Y))) {
if (loop.anchorID == Loop.UPPER_LEFT) {
this.anchor = loop.anchor;
this.anchorID = loop.anchorID;
}
return true;
}
return false;
}
/**
* Returns TRUE if the point specified by the int X, int Y is inside of my
* text part
*/
public boolean insideTextOfArc(int X, int Y, FontMetrics fm) {
Rectangle r = getTextRectangle(fm);
if ((r != null) && (r.contains(X, Y))) {
this.partOfText = 0;
return true;
} else if (this.elemOfTG && !this.getContext().isInheritanceType(this.eType)) {
if (insideTextOfMultiplicity(X, Y, "source")) {
this.partOfText = 1;
return true;
} else if (insideTextOfMultiplicity(X, Y, "target")) {
this.partOfText = 2;
return true;
} else
return false;
} else
return false;
}
private Rectangle getTextRectangle(FontMetrics fm) {
Dimension d = getTextSize(fm);
// System.out.println(d);
int tw = (int) d.getWidth();
int th = (int) d.getHeight();
if (isLine()) {
int tx = 0, ty = 0;
// int x1 = from.getX();
// int y1 = from.getY();
// int x2 = to.getX();
// int y2 = to.getY();
if (this.anchor != null) {
tx = this.anchor.x;
ty = this.anchor.y;
} else {
tx = this.x;
ty = this.y;
}
tx = tx - tw/2;
this.textLocation.x = tx + this.textOffset.x;
this.textLocation.y = ty + this.textOffset.y;
return new Rectangle(this.textLocation.x, this.textLocation.y, tw, th);
}
// loop
this.textLocation.x = this.x + this.textOffset.x;
this.textLocation.y = this.y + this.textOffset.y;
return new Rectangle(this.textLocation.x, this.textLocation.y, tw, th);
}
/**
* Returns TRUE if the point specified by the int X, int Y is inside of my
* source or target multiplicity part
*/
private boolean insideTextOfMultiplicity(int X, int Y, String key) {
if (key.equals("target")) {
Rectangle r = new Rectangle(
this.trgMultiplicityLocation.x + this.trgMultiplicityOffset.x,
this.trgMultiplicityLocation.y + this.trgMultiplicityOffset.y - (int) this.trgMultiplicitySize.getHeight(),
(int) this.trgMultiplicitySize.getWidth(),
(int) this.trgMultiplicitySize.getHeight());
if (r.contains(X, Y)) {
return true;
}
return false;
} else if (key.equals("source")) {
Rectangle r = new Rectangle(
this.srcMultiplicityLocation.x + this.srcMultiplicityOffset.x,
this.srcMultiplicityLocation.y + this.srcMultiplicityOffset.y - (int) this.srcMultiplicitySize.getHeight(),
(int) this.srcMultiplicitySize.getWidth(),
(int) this.srcMultiplicitySize.getHeight());
if (r.contains(X, Y)) {
return true;
}
return false;
} else
return false;
}
public void applyScale(double scale) {
if (scale != this.itsScale) {
setX((int) (this.x * (scale / this.itsScale)));
setY((int) (this.x * (scale / this.itsScale)));
if (this.anchor != null) {
this.anchor.x = (int) (this.anchor.x * (scale / this.itsScale));
this.anchor.y = (int) (this.anchor.y * (scale / this.itsScale));
}
if (this.textOffset != null) {
this.textOffset.x = (int) (this.textOffset.x * (scale / this.itsScale));
this.textOffset.y = (int) (this.textOffset.y * (scale / this.itsScale));
}
if (!this.isLine()) {
this.w = (int) (this.w * (scale / this.itsScale));
this.h = (int) (this.h * (scale / this.itsScale));
}
this.itsScale = scale;
}
}
public void drawShadowGraphic(Graphics grs) {
if (this.visible) {
Graphics2D g = (Graphics2D) grs;
// save color, font style
Color lastColor = g.getColor();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setPaint(Color.LIGHT_GRAY);
g.setStroke(EditorConstants.defaultStroke);
if (this.isLine()) {
g.draw(new Rectangle2D.Double(this.anchor.x-10, this.anchor.y-10, 20, 20));
}
else {
g.draw(new Rectangle2D.Double(this.anchor.x-10, this.anchor.y-10, 20, 20));
}
// reset font style, color
g.setFont(EditorConstants.defaultFont);
g.setPaint(lastColor);
}
}
public void drawTextShadowGraphic(Graphics grs, int px, int py) {
if (this.visible) {
Graphics2D g = (Graphics2D) grs;
// save color, font style
Color lastColor = g.getColor();
int fontstyle = g.getFont().getStyle();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setPaint(Color.LIGHT_GRAY);
g.setStroke(EditorConstants.defaultStroke);
g.draw(new Rectangle2D.Double(px-10, py-10, 20, 20));
// reset font style, color
g.setFont(new Font("Dialog", fontstyle, g.getFont().getSize()));
g.setPaint(lastColor);
}
}
/** Draws myself in the graphics specified by the Graphics g */
public void drawGraphic(Graphics grs) {
// synchronized (this)
{
if (!this.visible) {
return;
}
this.criticalStyle = this.eGraph.criticalStyle;
Graphics2D g = (Graphics2D) grs;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (this.eType.filled) {
g.setStroke(EditorConstants.boldStroke);
} else {
g.setStroke(EditorConstants.defaultStroke);
}
// save the old color
Color lastColor = g.getColor();
if (this.backgroundColor != null && this.backgroundColor != Color.white) {
g.setPaint(this.backgroundColor);
if (this.from != this.to)
drawBackgroundLine(g);
else
drawBackgroundLoop(g);
}
boolean hiddenObjOfType = this.eGraph.isTypeGraph()
&& !this.eType.getBasisType().isObjectOfTypeGraphArcVisible(
this.from.getType().getBasisType(),
this.to.getType().getBasisType());
if (selected) {
g.setPaint(EditorConstants.selectColor);
} else if (hiddenObjOfType) {
g.setPaint(EditorConstants.hideColor);
} else if (isCritical()) {
if (this.criticalStyle == 0) {
g.setStroke(EditorConstants.criticalColorStroke);
g.setFont(EditorConstants.criticalFont);
g.setPaint(EditorConstants.criticalColor);
}
else {//if (this.criticalStyle == 1) {
g.setStroke(EditorConstants.criticalStroke);
g.setPaint(Color.BLACK);
}
} else {
g.setPaint(this.getColor());
}
if (this.from != this.to) {
drawArcAsLine(g, true);
} else {
drawArcAsLoop(g, true);
}
if (this.errorMode) {
showErrorAnchor(g);
}
g.setStroke(EditorConstants.defaultStroke);
g.setFont(EditorConstants.defaultFont);
g.setPaint(lastColor);
}
}
/** Draws text of my graphics */
public void drawText(Graphics grs, double scale) {
Graphics2D g = (Graphics2D) grs;
g.setPaint(this.getColor());
int tx, ty;
if (isLine()) {
int tw = (int) getTextSize(g.getFontMetrics()).getWidth();
// int tw = getTextWidth(g.getFontMetrics());
if (this.anchor != null) {
tx = this.anchor.x;
ty = this.anchor.y;
} else {
tx = getX();
ty = getY();
}
tx = tx - tw/2;
this.textLocation.x = tx + this.textOffset.x;
this.textLocation.y = ty + this.textOffset.y;
} else {
this.textLocation.x = this.x + this.textOffset.x;
this.textLocation.y = this.y + this.textOffset.y;
}
drawText(g, this.textLocation.x, this.textLocation.y);
}
/** Erases text of my graphics */
public void eraseText(Graphics grs) {
Graphics2D g = (Graphics2D) grs;
g.setPaint(Color.white);
Rectangle r;
if (isLine()) {
r = getTextRectangle(g.getFontMetrics());
g.fillRect(r.x, r.y, r.width, r.height);
} else {
r = getTextRectangle(g.getFontMetrics());
g.fillRect(r.x, r.y, r.width, r.height);
}
}
/** Erases my graphic */
public void eraseGraphic(Graphics grs) {
// System.out.println("EdArc.eraseGraphic");
Graphics2D g = (Graphics2D) grs;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// g.setStroke(EditorConstants.basicStroke);
g.setPaint(Color.white);
eraseMoveAnchor(g);
if (isLine()) {
eraseArcAsLine(g, true);
/*
* Rectangle r = getTextRectangle(g.getFontMetrics());
* g.fillRect(r.x, r.y, r.width, r.height); drawArcAsLine(g, scale,
* false);
*/
} else {
eraseArcAsLoop(g, true);
/*
* Rectangle r = getTextRectangle(g.getFontMetrics());
* g.fillRect(r.x, r.y, r.width, r.height); drawArcAsLoop(g, scale,
* false);
*/
}
// g.setStroke(stroke);
}
/** Gets the width of my representation like loop */
public int getWidthOfLoop() {
if (getWidth() == 0)
return Loop.DEFAULT_SIZE;
return getWidth();
}
/** Gets the height of my representation like loop */
public int getHeightOfLoop() {
if (getHeight() == 0)
return Loop.DEFAULT_SIZE;
return getHeight();
}
/** Shows the bend which will be moved */
public void showMoveAnchor(Graphics g) {
if (!this.from.equals(this.to))
showMoveAnchorOfLine(g);
else
showMoveAnchorOfLoop(g);
}
/** Erases the anchor marking of the bend */
public void eraseMoveAnchor(Graphics g) {
if (!this.from.equals(this.to))
eraseMoveAnchorOfLine(g);
else
eraseMoveAnchorOfLoop(g);
}
/**
* Implements the AttrViewObserver. Makes update graphics if the attributes
* of my used object are changed.
*/
public void attributeChanged(AttrViewEvent ev) {
if (ev.getID() == AttrEvent.GENERAL_CHANGE // 0
// || ev.getID() == AttrEvent.MEMBER_ADDED // 10
|| ev.getID() == AttrEvent.MEMBER_DELETED // 20
|| ev.getID() == AttrEvent.MEMBER_RETYPED // 60
|| ev.getID() == AttrEvent.MEMBER_RENAMED // 50
|| ev.getID() == AttrViewEvent.MEMBER_VISIBILITY // 220
|| ev.getID() == AttrViewEvent.MEMBER_MOVED ) { // 210
if (ev.getSource().getTupleType().isValid()) {
this.attrChanged = true;
}
} else if (ev.getID() == AttrEvent.MEMBER_VALUE_CORRECTNESS // 70
|| ev.getID() == AttrEvent.MEMBER_VALUE_MODIFIED) { // 80
if (ev.getSource().isValid()) {
this.attrChanged = true;
if (this.myGraphPanel != null) {
if (this.myGraphPanel.isAttrEditorActivated()) {
if (this.bArc.getContext().getAttrContext() != null) {
ValueMember val = ((ValueTuple) this.bArc.getAttribute())
.getValueMemberAt(ev.getIndex());
if (val.isSet() && val.getExpr().isVariable()) {
ContextView viewContext = (ContextView) ((ValueTuple) val
.getHoldingTuple()).getContext();
VarTuple variable = (VarTuple) viewContext
.getVariables();
VarMember var = variable.getVarMemberAt(val
.getExprAsText());
if (var == null)
return;
if (this.bArc.getContext().isNacGraph())
var.setMark(VarMember.NAC);
else if (this.bArc.getContext().isPacGraph())
var.setMark(VarMember.PAC);
else if (viewContext
.doesAllowComplexExpressions())
var.setMark(VarMember.RHS);
else
var.setMark(VarMember.LHS);
}
}
}
}
} else {
ValueTuple attr = (ValueTuple) this.bArc.getAttribute();
for (int i = 0; i < attr.getSize(); i++) {
ValueMember am = (ValueMember) attr.getMemberAt(i);
if (!am.isValid())
break;
}
}
}
}
public void setGraphPanel(GraphPanel gp) {
this.myGraphPanel = gp;
}
private void showMoveAnchorOfLine(Graphics grs) {
// System.out.println("showMoveAnchorOfLine");
Graphics2D g = (Graphics2D) grs;
Color lastColor = g.getColor();
g.setPaint(Line.MOVE_ANCHOR_COLOR);
g.fillRect(this.x - Line.MOVE_ANCHOR_OFFSET,
this.y - Line.MOVE_ANCHOR_OFFSET,
Line.MOVE_ANCHOR_SIZE,
Line.MOVE_ANCHOR_SIZE);
// g.fillOval(this.x - Line.MOVE_ANCHOR_SIZE/2,
// this.y - Line.MOVE_ANCHOR_SIZE/2,
// Line.MOVE_ANCHOR_SIZE,
// Line.MOVE_ANCHOR_SIZE);
g.setPaint(lastColor);
}
private void showMoveAnchorOfLoop(Graphics grs) {
Loop loop = new Loop(getX(), getY(), getWidth(), getHeight());
loop.drawMoveAnchor(grs, this.anchorID);
}
/**
* Draws a sign to mark wrong arcs. If {@link EdGraphObject#errorMode} is
* true, a green box will be shown.
*/
protected void showErrorAnchor(Graphics g) {
if (!this.from.equals(this.to))
showErrorAnchorOfLine(g);
else
showErrorAnchorOfLoop(g);
}// showErrorAnchor
/**
* Draws a sign to mark wrong arcs between different nodes. If
* {@link EdGraphObject#errorMode} is true, a green box will be shown.
*/
private void showErrorAnchorOfLine(Graphics grs) {
Graphics2D g = (Graphics2D) grs;
Color lastColor = g.getColor();
g.setPaint(Color.green);
g.fill(new Rectangle2D.Double(this.x - 6, this.y - 6, 12, 12));
g.setPaint(lastColor);
}// showErrorAnchorOfLine
/**
* Draws a sign to mark wrong arcs between the same node. If
* {@link EdGraphObject#errorMode} is true, a green box will be shown.
*/
private void showErrorAnchorOfLoop(Graphics grs) {
Graphics2D g = (Graphics2D) grs;
Color lastColor = g.getColor();
g.setPaint(Color.green);
Loop loop = new Loop(getX(), getY(), getWidth(), getHeight());
if (this.anchorID == Loop.UPPER_LEFT)
g.fill(new Rectangle2D.Double(loop.anch1.x - 6, loop.anch1.y - 6,
12, 12));
g.setPaint(lastColor);
}// showErrorAnchorOfLoop
private void eraseMoveAnchorOfLine(Graphics grs) {
Graphics2D g = (Graphics2D) grs;
Color lastColor = g.getColor();
g.setPaint(Color.white);
g.fill(new Rectangle2D.Double(this.x - 5, this.y - 5, 10, 10));
g.setPaint(lastColor);
}
private void eraseMoveAnchorOfLoop(Graphics grs) {
Graphics2D g = (Graphics2D) grs;
Color lastColor = g.getColor();
g.setPaint(Color.white);
Loop loop = new Loop(getX(), getY(), getWidth(), getHeight());
if (this.anchorID == Loop.UPPER_LEFT)
g.fill(new Rectangle2D.Double(loop.anch1.x - 5, loop.anch1.y - 5,
10, 10));
g.setPaint(lastColor);
}
private void drawArcAsLine(Graphics grs, boolean withText) {
Graphics2D g = (Graphics2D) grs;
boolean needAnchorTuning = true;
/* set the edge data */
int x1 = this.from.getX();
int y1 = this.from.getY();
int x2 = this.to.getX();
int y2 = this.to.getY();
int srcW = this.to.getWidth();
int srcH = this.to.getHeight();
int tarW = this.from.getWidth();
int tarH = this.from.getHeight();
Line line = this.toLine();
if (this.anchor != null) {
line.setAnchor(new Point(this.anchor.x, this.anchor.y));
needAnchorTuning = false;
}
/* set XY of move position of arc */
setXY(line.getAnchor().x, line.getAnchor().y);
/* set width, height */
if (getWidth() == getHeight() && getHeight() == 0) {
setWidth(14);
setHeight(14);
}
/* show arc */
line.setColor(g.getColor());
int sh = getShape();
switch (sh) {
case EditorConstants.SOLID:
line.drawColorSolidLine(g);
break;
case EditorConstants.DOT:
line.drawColorDotLine(g);
break;
case EditorConstants.DASH:
line.drawColorDashLine(g);
break;
default:
break;
}
if (weakselected) {
line.drawWeakselectedLine(g);
g.setColor(this.getColor());
}
if (this.elemOfTG) {
// Edges arrow and Multiplicity of edge target
// Head of edge
Arrow arrow = new Arrow(this.itsScale,
line.getAnchor().x, line.getAnchor().y,
x2, y2, srcW, srcH, 0);
this.arrowPoint = arrow.getHeadEnd();
if (this.bArc.isInheritance())
arrow.draw(g, false);
else if (this.directed)
arrow.draw(g);
Arrow backArrow = new Arrow(this.itsScale,
line.getAnchor().x, line.getAnchor().y,
x1, y1, tarW, tarH, 0);
this.tailPoint = backArrow.getHeadEnd();
if (this.directed && needAnchorTuning) {
Point beg = backArrow.getHeadEnd();
Point end = arrow.getHeadEnd();
if (beg != null && end != null) {
int anchX = beg.x + (end.x - beg.x) / 2;
int anchY = beg.y + (end.y - beg.y) / 2;
line.setAnchor(new Point(anchX, anchY));
setXY(anchX, anchY);
}
}
if (!this.bArc.isInheritance()) {
Point p = new Point();
// draw target multiplicity
if ((arrow.getRightEnd() != null) && (y2 > line.getAnchor().y)) {
p.y = arrow.getRightEnd().y - 5;
p.x = arrow.getRightEnd().x;
} else if (arrow.getLeftEnd() != null) {
p.y = arrow.getLeftEnd().y + 5;
p.x = arrow.getLeftEnd().x;
}
drawMultiplicity(g, "target", p, this.eType.getBasisType()
.getTargetMin(this.bArc.getSource().getType(),
this.bArc.getTarget().getType()),
this.eType.getBasisType().getTargetMax(
this.bArc.getSource().getType(),
this.bArc.getTarget().getType()));
// draw source multiplicity
if ((backArrow.getRightEnd() != null)
&& (y1 > line.getAnchor().y)) {
p.y = backArrow.getRightEnd().y - 5;
p.x = backArrow.getRightEnd().x;
} else if (backArrow.getLeftEnd() != null) {
p.y = backArrow.getLeftEnd().y + 5;
p.x = backArrow.getLeftEnd().x;
}
drawMultiplicity(g, "source", p, this.eType.getBasisType()
.getSourceMin(this.bArc.getSource().getType(),
this.bArc.getTarget().getType()),
this.eType.getBasisType().getSourceMax(
this.bArc.getSource().getType(),
this.bArc.getTarget().getType()));
}
}
else { // plain graph
if (this.directed) {
int headsize = (isCritical() && (this.criticalStyle == 1)) ? 17: 0;
Arrow arrow = new Arrow(this.itsScale, line.getAnchor().x, line.getAnchor().y,
x2, y2, srcW, srcH, headsize);
this.arrowPoint = arrow.getHeadEnd();
arrow.draw(g);
if (needAnchorTuning) {
Arrow backArrow = new Arrow(this.itsScale, line.getAnchor().x, line
.getAnchor().y, x1, y1, tarW, tarH, headsize);
this.tailPoint = backArrow.getHeadEnd();
Point beg = backArrow.getHeadEnd();
Point end = arrow.getHeadEnd();
if (beg != null && end != null) {
int anchX = beg.x + (end.x - beg.x) / 2;
int anchY = beg.y + (end.y - beg.y) / 2;
line.setAnchor(new Point(anchX, anchY));
setXY(anchX, anchY);
}
}
}
}
/* Text */
if (withText) {
g.setStroke(EditorConstants.defaultStroke);
this.textLocation.x = getX() + this.textOffset.x;
this.textLocation.y = getY() + this.textOffset.y;
drawText(g, this.textLocation.x, this.textLocation.y);
}
}
public void refreshTextLocation() {
Line line = this.toLine();
if (this.anchor != null) {
line.setAnchor(new Point(this.anchor.x, this.anchor.y));
}
/* set XY of move position of arc */
setXY(line.getAnchor().x, line.getAnchor().y);
this.textLocation.x = getX() + this.textOffset.x;
this.textLocation.y = getY() + this.textOffset.y;
}
private void drawBackgroundLine(Graphics grs) {
Graphics2D g = (Graphics2D) grs;
g.setStroke(new BasicStroke(5.0f));
Line line = toLine();
if ((this.anchor != null)) {
line.setAnchor(new Point(this.anchor.x, this.anchor.y));
}
/* set width, height */
if (getWidth() == getHeight() && getHeight() == 0) {
setWidth(14);
setHeight(14);
}
/* draw arc */
line.setColor(g.getColor());
line.drawColorSolidLine(g);
g.setStroke(EditorConstants.defaultStroke);
}
private void eraseArcAsLine(Graphics grs, boolean withText) {
Graphics2D g = (Graphics2D) grs;
int nX[] = new int[6];
int nY[] = new int[6];
int nP, n = 5, n1 = 5;
nX[0] = this.from.getX();
nY[0] = this.from.getY() - n;
nX[1] = getX();
nY[1] = getY() - n;
nX[2] = this.to.getX();
nY[2] = this.to.getY() - (n + n1);
nX[3] = this.to.getX();
nY[3] = this.to.getY() + (n + n1);
nX[4] = getX();
nY[4] = getY() + n;
nX[5] = this.from.getX();
nY[5] = this.from.getY() + n;
nP = 6;
g.fillPolygon(nX, nY, nP);
if (withText) {
Rectangle r = getTextRectangle(g.getFontMetrics());
g.fillRect(r.x, r.y, r.width, r.height);
}
}
private void drawArcAsLoop(Graphics grs, boolean withText) {
Graphics2D g = (Graphics2D) grs;
int fromX = this.from.getX();
int fromY = this.from.getY();
int fromW = this.from.getWidth();
int fromH = this.from.getHeight();
// rechne width und height um, wenn source node ist CIRCLE
if (((EdNode) this.from).getShape() == EditorConstants.CIRCLE) {
fromW = (int) (Math.acos(1/2) * (this.from.getWidth()/2));
fromH = fromW;
}
// rechne width und height um, wenn source node ist OVAL
else if (((EdNode) this.from).getShape() == EditorConstants.OVAL) {
int nn = 0;
if (fromW < fromH)
nn = fromW - (fromH - fromW)/2;
else
nn = fromH - (fromW - fromH)/2;
fromW = nn;
fromH = nn;
}
/* set the edge data for first time */
int w1 = 0, h1 = 0, x1 = 0, y1 = 0;
// int w2 = 0, h2 = 0, x2 = 0, y2 = 0;
int offsetX = 0, offsetY = 0;
if (getWidth() == getHeight() && getHeight() == 0) {
w1 = getWidthOfLoop();
h1 = w1;
offsetX = fromW/2 + w1/2 + w1/4;
offsetY = fromH/2 + h1/2 + h1/4;
x1 = fromX - offsetX;
y1 = fromY - offsetY;
/* set position of arc */
setXY(x1, y1);
/* set width, height */
setWidth(w1);
setHeight(h1);
} else {
/* use the edge data */
w1 = getWidth();
h1 = getHeight();
offsetX = fromW/2 + w1/2 + w1/4;
offsetY = fromH/2 + h1/2 + h1/4;
x1 = fromX - offsetX;
y1 = fromY - offsetY;
/* Teste ob die Loop haengt */
int difX = 0;
int difY = 0;
if ((x1 + w1) <= (fromX - fromW/2)) {
difX = (fromX - fromW/2) - (x1 + w1);
x1 = x1 + difX + 5;
} else if (x1 >= (fromX + fromW/2)) {
difX = x1 - (fromX + fromW/2);
x1 = x1 - difX - 5;
}
if ((y1 + h1) <= (fromY - fromH/2)) {
difY = (fromY - fromH/2) - (y1 + h1);
y1 = y1 + difY + 5;
} else if (y1 >= (fromY + fromH/2)) {
difY = y1 - (fromY + fromH/2);
y1 = y1 - difY - 5;
}
/* Teste ob die Loop ueberdeckt ist */
Loop tLoop = new Loop(x1, y1, w1, h1);
if (!tLoop.outside(((EdNode) this.from).toRectangle(), tLoop.anch1,
tLoop.anch2, tLoop.anch3, tLoop.anch4)) {
x1 = fromX - fromW/2 - w1/2 - w1/4;
y1 = fromY - fromH/2 - h1/2 - h1/4;
}
}
/* create a new loop of this */
Loop loop = new Loop(x1, y1, w1, h1);
/* set position of arc */
setXY(x1, y1);
/* set width, height */
setWidth(w1);
setHeight(h1);
loop.setColor(g.getColor());
int sh = getShape();
switch (sh) {
case EditorConstants.SOLID:
loop.drawColorSolidLoop(g);
break;
case EditorConstants.DOT:
loop.drawColorDotLoop(g);
break;
case EditorConstants.DASH:
loop.drawColorDashLoop(g);
break;
default:
break;
}
if (weakselected) {
loop.drawWeakselectedLoop(g);
g.setColor(this.getColor());
}
if (this.elemOfTG) {
// Edges arrow and Multiplicity of edge target
Arrow arrow = new Arrow(this.itsScale, loop.anch4.x, loop.anch4.y,
loop.anch3.x, loop.anch3.y,
(loop.anch3.x - (fromX - fromW/2)) * 2,
(loop.anch3.y - (fromY - fromH/2)) * 2,
0);
if (this.directed) {
arrow.draw(g);
}
if (arrow.getRightEnd() != null) {
drawMultiplicity(g, "target", arrow.getRightEnd(), this.eType
.getBasisType().getTargetMin(
this.bArc.getSource().getType(),
this.bArc.getTarget().getType()),
this.eType.getBasisType().getTargetMax(
this.bArc.getSource().getType(),
this.bArc.getTarget().getType()));
}
Arrow backArrow = new Arrow(this.itsScale, loop.anch2.x, loop.anch2.y,
loop.anch3.x, loop.anch3.y,
(loop.anch3.x - (fromX - fromW/2)) * 2,
(loop.anch3.y - (fromY - fromH/2)) * 2,
0);
if (backArrow.getLeftEnd() != null) {
Point p = new Point(backArrow.getLeftEnd().x, backArrow.getLeftEnd().y - 10);
drawMultiplicity(g, "source", p, this.eType.getBasisType()
.getSourceMin(this.bArc.getSource().getType(),
this.bArc.getTarget().getType()),
this.eType.getBasisType().getSourceMax(
this.bArc.getSource().getType(),
this.bArc.getTarget().getType()));
}
}
else { // plain graph
if (this.directed) {
int headsize = (isCritical() && (this.criticalStyle == 1)) ? 17: 0;
Arrow arrow = new Arrow(this.itsScale, loop.anch4.x, loop.anch4.y,
loop.anch3.x, loop.anch3.y,
(loop.anch3.x - (fromX - fromW/2)) * 2,
(loop.anch3.y - (fromY - fromH/2)) * 2,
headsize);
arrow.draw(g);
}
}
/* Attribute Text */
if (withText) {
g.setStroke(EditorConstants.defaultStroke);
this.textLocation.x = x1 + this.textOffset.x;
this.textLocation.y = y1 + this.textOffset.y;
drawText(g, this.textLocation.x, this.textLocation.y);
}
}
private void drawBackgroundLoop(Graphics grs) {
Graphics2D g = (Graphics2D) grs;
g.setStroke(new BasicStroke(5.0f));
int fromWidth = this.from.getWidth();
int fromHeight = this.from.getHeight();
/* set the edge data for first time */
int w1 = 0, h1 = 0, x1 = 0, y1 = 0;
if (getWidth() == getHeight() && getHeight() == 0) {
w1 = getWidthOfLoop();
h1 = w1;
x1 = this.from.getX() - (fromWidth/2 + w1);
y1 = this.from.getY() - (fromHeight/2 + h1);
} else {
/* use the edge data */
w1 = getWidth();
h1 = getHeight();
x1 = this.from.getX() - (fromWidth/2 + w1);
y1 = this.from.getY() - (fromHeight/2 + h1);
}
/* create a new loop of this */
Loop loop = new Loop(x1, y1, w1, h1);
loop.setColor(g.getColor());
loop.drawColorSolidLoop(g);
g.setStroke(EditorConstants.defaultStroke);
}
private void eraseArcAsLoop(Graphics grs, boolean withText) {
// bilde Poligon mit Color.white
Graphics2D g = (Graphics2D) grs;
g.fillRect(getX(), getY(), getWidth() + 2, getHeight() + 5);
if (withText) {
Rectangle r = getTextRectangle(g.getFontMetrics());
g.fillRect(r.x, r.y, r.width, r.height);
}
}
private void drawText(Graphics grs, int X, int Y) {
if (X > 0 && Y > 0) {
Graphics2D g = (Graphics2D) grs;
boolean underlined = false;
int tx = X;
int ty = Y;
// if (tx <= 0) tx = 2;
// if (ty <= 0) ty = 2;
FontMetrics fm = g.getFontMetrics();
// Type name
int tw = getTextWidth(fm); // (int)textSize.getWidth();
String typeStr = getTypeString();
int ty1 = ty + fm.getAscent();
g.drawString(typeStr, tx, ty1);
if ((g.getFont().getSize() < 8)
|| !this.attrVisible)
return;
/* Attribute anzeigen */
Vector<Vector<String>> attrs = getAttributes();
if (attrs != null && !attrs.isEmpty()) {
for (int i = 0; i < attrs.size(); i++) {
Vector<String> attr = attrs.elementAt(i);
if (!this.elemOfTG && (attr.elementAt(2).length() != 0)) {
String attrStr = attr.elementAt(1);
attrStr = attr.elementAt(1) + "=";
attrStr = attrStr + attr.elementAt(2);
if (!underlined) {
ty = ty + fm.getHeight();
g.drawLine(tx, ty, tx + tw, ty);
ty = ty + 2;
underlined = true;
}
ty1 = ty + fm.getAscent();
g.drawString(attrStr, tx, ty1);
ty = ty + fm.getHeight();
} else if (this.elemOfTG && (attr.elementAt(1) != null)) {
String attrStr = attr.elementAt(0);
attrStr = attrStr + " ";
attrStr = attrStr + attr.elementAt(1);
// Type graph: default attr value
if (attr.elementAt(2).length() != 0) {
attrStr = attrStr + "=" + attr.elementAt(2);
}
if (!underlined) {
ty = ty + fm.getHeight();
g.drawLine(tx, ty, tx + tw, ty);
ty = ty + 2;
underlined = true;
}
ty1 = ty + fm.getAscent();
g.drawString(attrStr, tx, ty1);
ty = ty + fm.getHeight();
}
}
}
}
}
private void drawMultiplicity(Graphics grs, String key, Point p, int min,
int max) {
Graphics2D g = (Graphics2D) grs;
String s = "";
if (min != -1) {
s = s.concat(String.valueOf(min));
s = s.concat("..");
if (max == -1)
s = s.concat("*");
} else { // min == -1
if (max != -1)
s = s.concat("0..");
else
s = "*";
}
if (max != -1) {
if (min != max)
s = s.concat(String.valueOf(max));
else
s = String.valueOf(max);
}
int w1 = g.getFontMetrics().stringWidth(s);
int h1 = g.getFontMetrics().getHeight();
if (key.equals("source")) {
if (this.srcMultiplicityOffset.x == 0 && this.srcMultiplicityOffset.y == 0) {
if (isLine())
this.srcMultiplicityOffset.x = -w1;
else
this.srcMultiplicityOffset.x = +5;
this.srcMultiplicityOffset.y = h1;
}
this.srcMultiplicityLocation.x = p.x;
this.srcMultiplicityLocation.y = p.y;
this.srcMultiplicitySize.setSize(new Dimension(w1, h1));
g.drawString(s,
this.srcMultiplicityLocation.x + this.srcMultiplicityOffset.x,
this.srcMultiplicityLocation.y + this.srcMultiplicityOffset.y);
} else if (key.equals("target")) {
if (this.trgMultiplicityOffset.x == 0 && this.trgMultiplicityOffset.y == 0) {
this.trgMultiplicityOffset.x = -w1;
this.trgMultiplicityOffset.y = h1/2;
}
this.trgMultiplicityLocation.x = p.x;
this.trgMultiplicityLocation.y = p.y;
this.trgMultiplicitySize.setSize(new Dimension(w1, h1));
g.drawString(s,
this.trgMultiplicityLocation.x + this.trgMultiplicityOffset.x,
this.trgMultiplicityLocation.y + this.trgMultiplicityOffset.y);
}
}
public void drawNameAttrOnly(Graphics grs) {
// if (!this.isVisible()) {
if (!this.visible) {
return;
}
this.criticalStyle = this.eGraph.criticalStyle;
Graphics2D g = (Graphics2D) grs;
if (this.eType.filled) {
g.setStroke(EditorConstants.boldStroke);
} else {
g.setStroke(EditorConstants.defaultStroke);
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setPaint(this.getColor());
if (!this.from.equals(this.to)) {
// drawArcAsLine(g, scale, true);
boolean needAnchorTuning = true;
/* set the edge data */
int x1 = this.from.getX();
int y1 = this.from.getY();
int x2 = this.to.getX();
int y2 = this.to.getY();
Line line = toLine();
if ((this.anchor != null)) {
line.setAnchor(new Point(this.anchor.x, this.anchor.y));
needAnchorTuning = false;
}
/* set XY of move position of arc */
setXY(line.getAnchor().x, line.getAnchor().y);
/* set width, height */
if (getWidth() == getHeight() && getHeight() == 0) {
setWidth(14);
setHeight(14);
}
/*
* if(getType().getBasisType().getName().equals("c"))
* line.setColor(conflictColor); else
* if(getType().getBasisType().getName().equals("d"))
* line.setColor(dependencyColor);
*/
line.setColor(this.getColor());
int sh = getShape();
switch (sh) {
case EditorConstants.SOLID:
line.drawColorSolidLine(g);
break;
case EditorConstants.DOT:
line.drawColorDotLine(g);
break;
case EditorConstants.DASH:
line.drawColorDashLine(g);
break;
default:
break;
}
/* Head of edge */
int headsize = (isCritical() && (this.criticalStyle == 1)) ? 17: 0;
Arrow arrow = new Arrow(this.itsScale, line.getAnchor().x,
line.getAnchor().y, x2, y2, this.to.getWidth(), this.to.getHeight(), headsize);
if (isDirected())
arrow.draw(g);
Arrow tmpBackArrow = new Arrow(this.itsScale, line.getAnchor().x, line
.getAnchor().y, x1, y1, this.from.getWidth(), this.from.getHeight(), headsize);
if (needAnchorTuning) {
// System.out.println("EdArc: do arc tuning");
Point beg = tmpBackArrow.getHeadEnd();
Point end = arrow.getHeadEnd();
if (beg != null && end != null) {
int anchX = beg.x + (end.x - beg.x)/2;
int anchY = beg.y + (end.y - beg.y)/2;
line.setAnchor(new Point(anchX, anchY));
setXY(anchX, anchY);
}
}
// g.setPaint(this.getColor());
this.textLocation.x = getX() + this.textOffset.x;
this.textLocation.y = getY() + this.textOffset.y;
showNameAttrOnly(g, this.textLocation.x, this.textLocation.y);
} else {
// drawArcAsLoop(g, scale, true);
int fromWidth = this.from.getWidth();
int fromHeight = this.from.getHeight();
/* set the edge data for first time */
int w1 = 0, h1 = 0, x1 = 0, y1 = 0;
// int w2 = 0, h2 = 0, x2 = 0, y2 = 0;
int offsetX = 0, offsetY = 0;
if (getWidth() == getHeight() && getHeight() == 0) {
w1 = getWidthOfLoop();
h1 = w1;
offsetX = fromWidth/2 + w1/2 + w1/4;
offsetY = fromHeight/2 + h1/2 + h1/4;
x1 = this.from.getX() - offsetX;
y1 = this.from.getY() - offsetY;
/* set position of arc */
setXY(x1, y1);
/* set width, height */
setWidth(w1);
setHeight(h1);
} else {
/* use the edge data */
w1 = getWidth();
h1 = getHeight();
offsetX = fromWidth/2 + w1/2 + w1/4;
offsetY = fromHeight/2 + h1/2 + h1/4;
x1 = this.from.getX() - offsetX;
y1 = this.from.getY() - offsetY;
/* Teste ob die Schlinge haengt */
int difX = 0;
int difY = 0;
if ((x1 + w1) <= (this.from.getX() - fromWidth/2)) {
difX = (this.from.getX() - fromWidth/2) - (x1 + w1);
x1 = x1 + difX + 5;
} else if (x1 >= (this.from.getX() + fromWidth/2)) {
difX = x1 - (this.from.getX() + fromWidth/2);
x1 = x1 - difX - 5;
}
if ((y1 + h1) <= (this.from.getY() - fromHeight/2)) {
difY = (this.from.getY() - fromHeight/2) - (y1 + h1);
y1 = y1 + difY + 5;
} else if (y1 >= (this.from.getY() + fromHeight/2)) {
difY = y1 - (this.from.getY() + fromHeight/2);
y1 = y1 - difY - 5;
}
/* Teste ob die Schlinge ueberdeckt ist */
Loop tLoop = new Loop(x1, y1, w1, h1);
if (!tLoop.outside(((EdNode) this.from).toRectangle(), tLoop.anch1,
tLoop.anch2, tLoop.anch3, tLoop.anch4)) {
x1 = this.from.getX() - fromWidth/2 - w1/2 - w1/4;
y1 = this.from.getY() - fromHeight/2 - h1/2 - h1/4;
}
}
/* create a new loop of this */
Loop loop = new Loop(x1, y1, w1, h1);
/* set position of arc */
setXY(x1, y1);
/* set width, height */
setWidth(w1);
setHeight(h1);
/*
* if(getType().getBasisType().getName().equals("c"))
* loop.setColor(conflictColor); else
* if(getType().getBasisType().getName().equals("d"))
* loop.setColor(dependencyColor);
*/
loop.setColor(this.getColor());
int sh = getShape();
switch (sh) {
case EditorConstants.SOLID:
loop.drawColorSolidLoop(g);
break;
case EditorConstants.DOT:
loop.drawColorDotLoop(g);
break;
case EditorConstants.DASH:
loop.drawColorDashLoop(g);
break;
default:
break;
}
/* Head of edge */
int headsize = (isCritical() && (this.criticalStyle == 1)) ? 17: 0;
Arrow arrow = new Arrow(this.itsScale, loop.anch4.x, loop.anch4.y,
loop.anch3.x, loop.anch3.y,
(loop.anch3.x - (this.from.getX() - fromWidth/2)) * 2,
(loop.anch3.y - (this.from.getY() - fromHeight/2)) * 2,
headsize);
arrow.draw(g);
// g.setPaint(this.getColor());
this.textLocation.x = x1 + this.textOffset.x;
this.textLocation.y = y1 + this.textOffset.y;
showNameAttrOnly(g, this.textLocation.x, this.textLocation.y);
}
g.setPaint(this.getColor());
g.setStroke(EditorConstants.defaultStroke);
}
private void showNameAttrOnly(Graphics grs, int X, int Y) {
Graphics2D g = (Graphics2D) grs;
int tx = X;
if (tx <= 0)
tx = 2;
int ty = Y;
if (ty <= 0)
ty = 2;
FontMetrics fm = g.getFontMetrics();
/* Attribute anzeigen */
Vector<Vector<String>> attrs = getAttributes();
if (attrs != null && !attrs.isEmpty()) {
for (int i = 0; i < attrs.size(); i++) {
Vector<String> attr =attrs.elementAt(i);
if (attr.elementAt(2).length() != 0) {
if (attr.elementAt(1).equals("name")) {
String attrStr = attr.elementAt(2);
if (!attrStr.equals("\"\"")) {
int ty1 = ty + fm.getAscent();
g.drawString(attrStr, tx, ty1);
}
return;
}
}
}
}
}
public void XwriteObject(XMLHelper xmlh) {
// wegen zooming statt x,y, textOffset origX ... nehmen
// was ist mit Loop???
if (xmlh.openObject(this.bArc, this)) {
xmlh.openSubTag("EdgeLayout");
int outX = (int) (this.textOffset.x / this.itsScale);
int outY = (int) (this.textOffset.y / this.itsScale);
xmlh.addAttr("textOffsetX", outX);
xmlh.addAttr("textOffsetY", outY);
if (isLine()) {
if (this.hasDefaultAnchor) {
xmlh.addAttr("bendX", 0);
xmlh.addAttr("bendY", 0);
} else {
outX = (int) (this.x / this.itsScale);
outY = (int) (this.y / this.itsScale);
xmlh.addAttr("bendX", outX);
xmlh.addAttr("bendY", outY);
}
} else { // is Loop
outX = (int) (this.x / this.itsScale);
outY = (int) (this.y / this.itsScale);
xmlh.addAttr("bendX", outX);
xmlh.addAttr("bendY", outY);
outX = (int) (this.w / this.itsScale);
outY = (int) (this.h / this.itsScale);
xmlh.addAttr("loopW", outX);
xmlh.addAttr("loopH", outY);
}
if (isElementOfTypeGraph()) {
outX = (int) (this.srcMultiplicityOffset.x / this.itsScale);
outY = (int) (this.srcMultiplicityOffset.y / this.itsScale);
xmlh.addAttr("sourceMultiplicityOffsetX", outX);
xmlh.addAttr("sourceMultiplicityOffsetY", outY);
outX = (int) (this.trgMultiplicityOffset.x / this.itsScale);
outY = (int) (this.trgMultiplicityOffset.y / this.itsScale);
xmlh.addAttr("targetMultiplicityOffsetX", outX);
xmlh.addAttr("targetMultiplicityOffsetY", outY);
}
xmlh.close();
// LayoutArc speichern:
if (this.lArc != null) {
xmlh.addObject("", this.lArc, true);
}
xmlh.close();
}
}
public void XreadObject(XMLHelper xmlh) {
int loopW = 0;
int loopH = 0;
xmlh.peekObject(this.bArc, this);
if (xmlh.readSubTag("EdgeLayout")) {
this.textOffset = new Point();
String s = xmlh.readAttr("textOffsetX");
if (s.length() == 0)
this.textOffset.x = 0;
else
this.textOffset.x = (new Integer(s)).intValue();
s = xmlh.readAttr("textOffsetY");
if (s.length() == 0)
this.textOffset.y = 0;
else
this.textOffset.y = (new Integer(s)).intValue();
s = xmlh.readAttr("bendX");
if ((s.length() == 0) || (s.equals("0"))) {
this.x = 0;
}
else {
this.x = (new Integer(s)).intValue();
if (this.x < 0) {
this.x = 0;
}
// else if (x > 1600) {
// x = (int) (Math.random()*1000);
// }
}
s = xmlh.readAttr("bendY");
if ((s.length() == 0) || (s.equals("0"))) {
this.y = 0;
}
else {
this.y = (new Integer(s)).intValue();
if (this.y < 0) {
this.y = 0;
}
// else if (y > 1000) {
// y = (int) (Math.random()*1000);
// }
}
if (!isLine()) { // is Loop
s = xmlh.readAttr("loopW");
if (s.length() == 0)
loopW = 0;
else
loopW = (new Integer(s)).intValue();
s = xmlh.readAttr("loopH");
if (s.length() == 0)
loopH = 0;
else
loopH = (new Integer(s)).intValue();
}
if (this.elemOfTG) {
createMultiplicityVars();
s = xmlh.readAttr("sourceMultiplicityOffsetX");
if (s.length() == 0)
this.srcMultiplicityOffset.x = 0;
else
this.srcMultiplicityOffset.x = (new Integer(s)).intValue();
s = xmlh.readAttr("sourceMultiplicityOffsetY");
if (s.length() == 0)
this.srcMultiplicityOffset.y = 0;
else
this.srcMultiplicityOffset.y = (new Integer(s)).intValue();
s = xmlh.readAttr("targetMultiplicityOffsetX");
if (s.length() == 0)
this.trgMultiplicityOffset.x = 0;
else
this.trgMultiplicityOffset.x = (new Integer(s)).intValue();
s = xmlh.readAttr("targetMultiplicityOffsetY");
if (s.length() == 0)
this.trgMultiplicityOffset.y = 0;
else
this.trgMultiplicityOffset.y = (new Integer(s)).intValue();
}
xmlh.close();
// set anchor of edge
if (isLine()) {
Line line = toLine();
Point p = line.getAnchor();
if (((this.x == 0) && (this.y == 0))
|| ((p.x == this.x) && (p.y == this.y))) {
this.hasDefaultAnchor = true;
} else {
this.hasDefaultAnchor = false;
setAnchor(new Point(this.x, this.y));
}
} else { /* a loop */
if (xmlh.getDocumentVersion().equals("1.0")) {
if ((loopW != 0) && (loopH != 0)) {
this.anchor = new Point(this.x, this.y);
this.anchorID = Loop.UPPER_LEFT;
this.hasDefaultAnchor = false;
setXY(this.x, this.y);
setWidth(loopW);
setHeight(loopH);
} else {
setAnchor(new Point(this.x, this.y));
this.hasDefaultAnchor = true;
}
} else {
setAnchor(new Point(this.x, this.y));
this.hasDefaultAnchor = true;
}
}
}
// layoutArc einlesen:
xmlh.enrichObject(this.lArc);
xmlh.close();
this.attrVisible = true;
this.attrChanged = false;
}
}
// $Log: EdArc.java,v $
// Revision 1.60 2010/11/14 12:59:11 olga
// tuning
//
// Revision 1.59 2010/11/12 15:14:53 olga
// tuning
//
// Revision 1.58 2010/11/10 01:14:49 olga
// tuning
//
// Revision 1.57 2010/11/09 16:41:25 olga
// tuning
//
// Revision 1.56 2010/08/25 00:33:06 olga
// tuning
//
// Revision 1.55 2010/03/19 14:46:49 olga
// tuning
//
// Revision 1.54 2010/03/18 18:17:28 olga
// tuning
//
// Revision 1.53 2010/03/17 21:38:36 olga
// tuning
//
// Revision 1.52 2010/03/10 14:44:49 olga
// make identical rule - bug fixed
//
// Revision 1.51 2010/03/08 15:40:04 olga
// code optimizing
//
// Revision 1.50 2010/02/22 15:07:44 olga
// code optimizing
//
// Revision 1.49 2010/01/31 16:42:35 olga
// tuning
//
// Revision 1.48 2009/10/14 07:52:29 olga
// GUI bug fixed
//
// Revision 1.47 2009/06/30 09:50:19 olga
// agg.xt_basis.GraphObject: added: setObjectName(String), getObjectName()
// agg.xt_basis.Node, Arc: changed: save, load the object name
// agg.editor.impl.EdGraphObject: changed: String getTypeString() - contains object name if set
//
// workaround of Applicability of Rule Sequences and Object Flow
//
// Revision 1.46 2009/03/30 13:50:49 olga
// some tests
//
// Revision 1.45 2009/03/25 15:19:15 olga
// code tuning
//
// Revision 1.44 2008/12/17 09:37:42 olga
// Import of TypeGraph from grammar (.ggx) - bug fixed
//
// Revision 1.43 2008/11/24 11:35:12 olga
// GUI tuning
//
// Revision 1.42 2008/11/06 08:45:36 olga
// Graph layout is extended by Zest Graph Layout ( eclipse zest plugin)
//
// Revision 1.41 2008/10/29 09:04:05 olga
// new sub packages of the package agg.gui: typeeditor, editor, trafo, cpa, options, treeview, popupmenu, saveload
//
// Revision 1.40 2008/09/11 15:10:53 olga
// Tests only
//
// Revision 1.39 2008/09/11 09:22:25 olga
// Some changes in CPA: new computing of conflicts after an option changed,
// Graph layout of overlapping graphs
//
// Revision 1.38 2008/09/04 07:48:42 olga
// GUI extension: hide nodes, edges
//
// Revision 1.37 2008/07/21 10:03:28 olga
// Code tuning
//
// Revision 1.36 2008/07/17 15:51:50 olga
// GraphEditor - graph scaling tuning
//
// Revision 1.35 2008/07/14 07:35:48 olga
// Applicability of RS - new option added, more tuning
// Node animation - new animation parameter added,
// Undo edit manager - possibility to disable it when graph transformation
// because it costs much more time and memory
//
// Revision 1.34 2008/07/02 17:14:36 olga
// Code tuning
//
// Revision 1.33 2008/06/26 14:18:47 olga
// Graph visualization tuning
//
// Revision 1.32 2008/04/21 09:32:19 olga
// Visualization of inheritance edge - bugs fixed
// Graph layout tuning
//
// Revision 1.31 2008/04/17 10:11:07 olga
// Undo, redo edit and graph layout tuning,
//
// Revision 1.30 2008/04/11 13:29:05 olga
// Memory usage - tuning
//
// Revision 1.29 2008/04/10 10:53:14 olga
// Draw graphics tuning
//
// Revision 1.28 2008/04/07 09:36:50 olga
// Code tuning: refactoring + profiling
// Extension: CPA - two new options added
//
// Revision 1.27 2008/01/23 15:03:18 olga
// Tuning of usability of the gragra editor.
//
// Revision 1.26 2007/11/19 08:48:39 olga
// Some GUI usability mistakes fixed.
// Default values in node/edge of a type graph implemented.
// Code tuning.
//
// Revision 1.25 2007/11/05 09:18:16 olga
// code tuning
//
// Revision 1.24 2007/11/01 09:58:11 olga
// Code refactoring: generic types- done
//
// Revision 1.23 2007/10/11 08:05:04 olga
// Enumeration typing
//
// Revision 1.22 2007/09/24 09:42:33 olga
// AGG transformation engine tuning
//
// Revision 1.21 2007/09/10 13:05:16 olga
// In this update:
// - package xerces2.5.0 is not used anymore;
// - class com.objectspace.jgl.Pair is replaced by the agg own generic class agg.util.Pair;
// - bugs fixed in: usage of PACs in rules; match completion;
// usage of static method calls in attr. conditions
// - graph editing: added some new features
//
// Revision 1.20 2007/06/18 08:15:59 olga
// New extentions by drawing edge.
//
// Revision 1.19 2007/06/13 08:32:44 olga
// Update: V161
//
// Revision 1.18 2007/04/19 07:52:35 olga
// Tuning of: Undo/Redo, Graph layouter, loading grammars
//
// Revision 1.17 2007/04/11 10:03:35 olga
// Undo, Redo tuning,
// Simple Parser- bug fixed
//
// Revision 1.16 2007/03/28 10:00:24 olga
// - extensive changes of Node/Edge Type Editor,
// - first Undo implementation for graphs and Node/edge Type editing and
// transformation,
// - new / reimplemented options for layered transformation, for graph layouter
// - enable / disable for NACs, attr conditions, formula
// - GUI tuning
//
// Revision 1.15 2007/02/19 09:11:00 olga
// Bug during loading file fixed.
// Type editor tuning
//
// Revision 1.14 2007/01/22 08:28:29 olga
// GUI bugs fixed
//
// Revision 1.13 2006/11/01 11:17:29 olga
// Optimized agg sources of CSP algorithm, match usability,
// graph isomorphic copy,
// node/edge type multiplicity check for injective rule and match
//
// Revision 1.12 2006/08/09 16:09:09 olga
// Tuning evolutionary layouter
// API docu
//
// Revision 1.11 2006/08/09 07:42:18 olga
// API docu
//
// Revision 1.10 2006/08/02 09:00:57 olga
// Preliminary version 1.5.0 with
// - multiple node type inheritance,
// - new implemented evolutionary graph layouter for
// graph transformation sequences
//
// Revision 1.9 2006/05/29 07:59:41 olga
// GUI, undo delete - tuning.
//
// Revision 1.8 2006/05/17 06:57:16 olga
// CPA graph: set conflict/dependency edge style
//
// Revision 1.7 2006/04/03 08:57:50 olga
// New: Import Type Graph
// and some bugs fixed
//
// Revision 1.6 2005/12/21 14:49:20 olga
// GUI tuning
//
// Revision 1.5 2005/11/07 09:38:08 olga
// Null pointer during retype attr. member fixed.
//
// Revision 1.4 2005/10/10 08:05:16 olga
// Critical Pair GUI and CPA graph
//
// Revision 1.3 2005/09/26 16:41:20 olga
// CPA graph, CPs - visualization
//
// Revision 1.2 2005/09/19 09:12:14 olga
// CPA GUI tuning
//
// Revision 1.1 2005/08/25 11:56:56 enrico
// *** empty log message ***
//
// Revision 1.3 2005/07/11 09:30:20 olga
// This is test version AGG V1.2.8alfa .
// What is new:
// - saving rule option <disabled>
// - setting trigger rule for layer
// - display attr. conditions in gragra tree view
// - CPA algorithm <dependencies>
// - creating and display CPA graph with conflicts and/or dependencies
// based on (.cpx) file
//
// Revision 1.2.2.1 2005/07/04 11:41:37 enrico
// basic support for inheritance
//
// Revision 1.2 2005/06/20 13:37:04 olga
// Up to now the version 1.2.8 will be prepared.
//
// Revision 1.1 2005/05/30 12:58:02 olga
// Version with Eclipse
//
// Revision 1.38 2005/03/03 13:48:42 olga
// - Match with NACs and attr. conditions with mixed variables - error corrected
// - save/load class packages written by user
// - PACs : creating T-equivalents - improved
// - save/load matches of the rules (only one match of a rule)
// - more friendly graph/rule editor GUI
// - more syntactical checks in attr. editor
//
// Revision 1.37 2005/02/14 09:27:01 olga
// -PAC;
// -GUI, layered graph transformation anzeigen;
// -CPs.
//
// Revision 1.36 2005/01/28 14:02:32 olga
// -Fehlerbehandlung beim Typgraph check
// -Erweiterung CP GUI / CP Menu
// -Fehlerbehandlung mit identification option
// -Fehlerbehandlung bei Rule PAC
//
// Revision 1.35 2004/12/20 14:53:48 olga
// Changes because of matching optimisation.
//
// Revision 1.34 2004/11/15 11:24:45 olga
// Neue Optionen fuer Transformation;
// verbesserter default Graphlayout;
// Close GraGra mit Abfrage wenn was geaendert wurde statt Delete GraGra
//
// Revision 1.33 2004/10/25 14:24:37 olga
// Fehlerbehandlung bei CPs und Aenderungen im zusammenhang mit
// termination-Modul
// in AGG
//
// Revision 1.32 2004/07/16 13:02:02 olga
// TypeGraph OK
//
// Revision 1.31 2004/07/15 11:13:10 olga
// CPs letzter Schliff
//
// Revision 1.30 2004/06/14 12:34:19 olga
// CP Analyse and Transformation
//
// Revision 1.29 2004/06/09 11:32:54 olga
// Attribute-Eingebe/Bedingungen : NAC kann jetzt eigene Variablen und
// Bedingungen
// haben.
// CP Berechnung korregiert.
//
// Revision 1.28 2004/05/26 16:17:40 olga
// Observer / observable
//
// Revision 1.27 2004/05/13 17:54:09 olga
// Fehlerbehandlung
//
// Revision 1.26 2004/04/28 12:46:38 olga
// test CSP
//
// Revision 1.25 2004/04/15 10:49:47 olga
// Kommentare
//
// Revision 1.24 2004/02/25 11:45:04 olga
// Rule Post Appl Conditions getestet.
//
// Revision 1.23 2004/01/29 13:38:18 olga
// Layout und Types
//
// Revision 1.22 2003/10/16 08:25:12 olga
// Copy rule implementiert
//
// Revision 1.21 2003/08/04 14:40:43 olga
// Loop- behandlung
//
// Revision 1.20 2003/06/12 16:03:50 olga
// Layout
//
// Revision 1.19 2003/04/10 09:05:23 olga
// Aenderungen wegen serializable Ausgabe
//
// Revision 1.18 2003/04/10 08:50:33 olga
// Tests mit serializable Ausgabe
//
// Revision 1.17 2003/03/27 09:28:53 olga
// Layout- anpassung
//
// Revision 1.16 2003/03/17 15:32:59 olga
// Kleine Korrektur von Xread, Xwrite
//
// Revision 1.15 2003/03/05 18:24:23 komm
// sorted/optimized import statements
//
// Revision 1.14 2002/12/18 14:15:14 olga
//
// Layout
//
// Revision 1.13 2002/12/18 09:15:54 olga
// Layout - Anpassung
//
// Revision 1.12 2002/12/12 09:22:05 olga
// Kantengraphik verbessert (Loops)
//
// Revision 1.11 2002/12/09 14:32:32 olga
// Loop-Anzeige verbessert.
//
// Revision 1.10 2002/12/05 14:31:19 olga
// Speichern von Multiplicity offset
//
// Revision 1.9 2002/12/05 13:34:50 olga
// Speichern / Lesen und Anzeigen von Multiplicity.
//
// Revision 1.8 2002/12/02 09:59:44 komm
// each source/target combination has now its own multiplicity constraints
//
// Revision 1.7 2002/11/25 15:03:51 olga
// Arbeit an den Typen.
//
// Revision 1.6 2002/11/14 14:29:39 olga
// Anzeige von Multiplicity -- ein Versuch.
//
// Revision 1.5 2002/11/07 15:58:26 olga
// Fehlerbehandlung
//
// Revision 1.4 2002/10/02 18:30:42 olga
// XXX
//
// Revision 1.3 2002/09/30 10:06:01 komm
// ErrorMode moved to EdGraphObject
//
// Revision 1.2 2002/09/23 12:24:05 komm
// added type graph in xt_basis, editor and GUI
//
// Revision 1.1.1.1 2002/07/11 12:17:07 olga
// Imported sources
//
// Revision 1.26 2001/07/04 10:44:16 olga
// Neue Methoden in EdGraph um eine Selektion als EdGraph kopieren
// und zu einem EdGraph addieren zu koennen.
//
// Revision 1.25 2001/05/14 15:45:15 olga
// Anzeige von Loop am Kreis oder Oval verbessert.
//
// Revision 1.24 2001/05/14 12:00:39 olga
// Graph Layout und Graphobject Layout optimiert.
//
// Revision 1.23 2001/04/11 14:57:36 olga
// Arbeit an dem Layout.
//
// Revision 1.22 2001/03/15 17:52:31 olga
// *** empty log message ***
//
// Revision 1.21 2001/03/15 17:03:19 olga
// Layout korrektur.
//
// Revision 1.20 2001/03/08 10:53:18 olga
// Das ist Stand nach der AGG GUI Reimplementierung.
//
// Revision 1.19 2000/12/21 09:48:50 olga
// In dieser Version wurden XML und GUI Reimplementierung zusammen gefuehrt.
//
// Revision 1.18 2000/12/07 14:23:35 matzmich
// XML-Kram
// Man beachte: xerces (/home/tfs/gragra/AGG/LIB/Xerces/xerces.jar) wird
// jetzt im CLASSPATH benoetigt.
//
// Revision 1.17.6.3 2000/12/06 10:13:20 olga
// Rendering hints in Graphics2D gesetzt.
//
// Revision 1.17.6.2 2000/11/09 17:54:41 olga
// Fehlerbeseitigt im TypeEditor und bei den Kanten.
//
// Revision 1.17.6.1 2000/11/06 09:32:31 olga
// Erste Version fuer neue GUI (Branch reimpl)
//
// Revision 1.17 2000/03/03 11:41:16 shultzke
// *** empty log message ***
//
// Revision 1.14 1999/10/07 14:20:19 olga
// *** empty log message ***
//
// Revision 1.13 1999/10/06 14:28:29 olga
// *** empty log message ***
//
// Revision 1.12 1999/09/23 13:58:37 olga
// *** empty log message ***
//
// Revision 1.11 1999/09/23 09:18:04 olga
// Angepasst auf eifarbige Line/Loop.
//
// Revision 1.10 1999/09/20 10:58:45 olga
// *** empty log message ***
//
// Revision 1.9 1999/09/20 10:43:20 olga
// *** empty log message ***
//
// Revision 1.8 1999/09/16 13:56:16 olga
// *** empty log message ***
//
// Revision 1.7 1999/09/15 12:34:43 olga
// *** empty log message ***
//
// Revision 1.6 1999/08/03 13:22:44 shultzke
// das Laden und Speichern der Views der Attribute
// wurde in read- und writeObject von EdNode
// und EdArc gelegt. Es ist im Moment noch etwas
// unsauber. Aber es funktioniert.
//
// Revision 1.5 1999/07/28 11:23:26 shultzke
// Events werden richtig benutzt
// Konstruktoren verschoenert
//
// Revision 1.4 1999/07/26 10:24:55 shultzke
// Views koennen zwar benutzt werden. Sie werden
// aber noch nicht nach dem Laden rekonstruiert.
//