package agg.editor.impl; import java.awt.Font; import java.awt.BasicStroke; import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.geom.Rectangle2D; import java.net.URL; import java.util.Iterator; import java.util.List; import java.util.Vector; import java.util.Hashtable; import javax.swing.ImageIcon; import javax.swing.undo.*; import agg.attribute.AttrEvent; import agg.attribute.AttrInstance; import agg.attribute.impl.AttrTupleManager; import agg.attribute.impl.DeclMember; 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.attribute.view.AttrViewEvent; import agg.attribute.view.AttrViewObserver; import agg.attribute.view.AttrViewSetting; import agg.util.XMLHelper; import agg.util.XMLObject; import agg.xt_basis.Graph; import agg.xt_basis.GraphObject; import agg.xt_basis.Node; import agg.xt_basis.Arc; import agg.xt_basis.TypeException; import agg.gui.editor.EditorConstants; import agg.gui.editor.GraphPanel; import agg.layout.evolutionary.LayoutNode; /** * EdNode specifies a node layout of an agg.xt_basis.Node object * * @author $Author: olga $ * @version $Id: EdNode.java,v 1.61 2010/11/14 12:59:11 olga Exp $ */ public class EdNode extends EdGraphObject implements AttrViewObserver, XMLObject, StateEditable { private Node bNode; private LayoutNode lNode; private int nodeid; private Vector<Integer> cluster, oldcluster; private Color ownColor = null; /** * Creates a node layout specified by the EdType eType for an used object * specified by the Node bNode. */ public EdNode(Node bNode, EdType eType) { super(eType); this.bNode = bNode; if (this.bNode != null) { this.contextUsage = String.valueOf(this.hashCode()); // this as AttrViewObserver register if (this.bNode.getAttribute() != null) { addToAttributeViewObserver(); } } this.lNode = new LayoutNode(this); this.nodeid = -1; this.x = 100; this.y = 100; this.w = 20; this.h = 20; } /** * Creates a node layout specified by the EdType eType for an used object of * the class agg.xt_basis.Node that would be created from the graph * specified by the Graph bGraph */ public EdNode(Graph bGraph, EdType eType) throws TypeException { this((bGraph != null) ? bGraph.createNode(eType.bType) : null, eType); } /** Disposes myself */ public void dispose() { if (this.attrObserver) { removeFromAttributeViewObserver(); } this.view = null; if (this.lNode != null) this.lNode.dispose(); this.lNode = null; this.eGraph = null; this.eType = null; this.bNode = null; this.myGraphPanel = null; // System.out.println("EdNode.dispose:: DONE "+this); } public void finalize() { // System.out.println("EdNode.finalize() called "+this); } public void storeState(Hashtable<Object, Object> state) { NodeReprData data = new NodeReprData(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("EdNode.restoreState:: "+state.get(Integer.valueOf(this.hashCode()))+" "+state.get(this.itsUndoReprDataHC)); NodeReprData data = (NodeReprData) state.get(Integer.valueOf(this.hashCode())); if (data == null) { data = (NodeReprData) state.get(this.itsUndoReprDataHC); } if (data != null) { data.restoreNodeFromNodeRepr(this); this.attrChanged = false; } } public void restoreState(Hashtable<?, ?> state, String hashCode) { // System.out.println("### EdNode.restoreState:: "+state.get(Integer.valueOf(hashCode))+" "+state.get(this.itsUndoReprDataHC)); NodeReprData data = (NodeReprData) state.get(Integer.valueOf(hashCode)); if (data == null) { data = (NodeReprData) state.get(this.itsUndoReprDataHC); } if (data == null) { data = (NodeReprData) state.get(Integer.valueOf(this.hashCode())); } if (data != null) { data.restoreNodeFromNodeRepr(this); this.attrChanged = false; } } public void restoreState(NodeReprData data) { data.restoreNodeFromNodeRepr(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.bNode.getAttribute(), true); this.view.setVisible(this.bNode.getAttribute()); this.init = true; } return this.view; } public void setAttrViewSetting(AttrViewSetting aView) { this.view = aView; if (!this.attrObserver) { this.view.addObserver(this, this.bNode.getAttribute()); this.attrObserver = true; } this.init = true; } public void addToAttributeViewObserver() { getView().addObserver(this, this.bNode.getAttribute()); this.attrObserver = true; } public void removeFromAttributeViewObserver() { if (this.view != null && this.bNode != null && this.bNode.getAttribute() != null) { this.view.removeObserver(this, this.bNode.getAttribute()); this.view.getMaskedView() .removeObserver(this, this.bNode.getAttribute()); } } public void createAttributeInstance() { if (this.bNode != null && this.bNode.getAttribute() == null) { this.bNode.createAttributeInstance(); addToAttributeViewObserver(); } } public void refreshAttributeInstance() { if (this.bNode != null && this.bNode.getAttribute() != null) { ((ValueTuple) this.bNode.getAttribute()).getTupleType().refreshParents(); addToAttributeViewObserver(); } } /** * Returns the layout node of this node. */ public LayoutNode getLNode() { return this.lNode; } /** Returns the used object */ public Node getBasisNode() { return this.bNode; } /** Returns the used object */ public GraphObject getBasisObject() { return this.bNode; } /** Returns TRUE */ public boolean isNode() { return true; } /** Returns FALSE */ public boolean isArc() { return false; } public void setCritical(boolean b) { this.bNode.setCritical(b); } public boolean isCritical() { return this.bNode.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; } public boolean isVisible() { if (this.bNode != null) { this.visible = this.bNode.isVisible(); if (this.getContext().getBasisGraph().isCompleteGraph()) { this.visible = this.visible && this.getType().getBasisType().isObjectOfTypeGraphNodeVisible(); } return this.visible; } return this.visible; } /** Returns this */ public EdNode getNode() { return this; } /** Returns NULL */ public EdArc getArc() { return null; } /** * @return count of all incoming edges (also loops) */ public int getInArcsCount() { return this.bNode.getIncomingArcsSet().size(); } /** * @return count of all outgoing edges (also loops) */ public int getOutArcsCount() { return this.bNode.getOutgoingArcsSet().size(); } /** * @return count of all incoming and outgoing edges (without loops!) */ public int getInOutArcsCount() { return this.bNode.getOutgoingArcsSet().size() +this.bNode.getIncomingArcsSet().size(); } /** * @return count of all loop edges */ public int getLoopArcsCount() { int c = 0; Iterator<Arc> e = this.bNode.getOutgoingArcsSet().iterator(); while (e.hasNext()) { if (e.next().isLoop()) c++; } return c; } /** * Returns the attributes which are shown */ public Vector<Vector<String>> getAttributes() { Vector<Vector<String>> attrs = new Vector<Vector<String>>(); if (this.bNode != null) { AttrInstance attributes = this.bNode.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>(3); int index = mvs.convertSlotToIndex(attributes, i); DeclMember currentMember = (DeclMember) attributes .getType().getMemberAt(index); if (this.elemOfTG && (currentMember != null) && (currentMember.getHoldingTuple() != attributes .getType())) { // if (!((ValueMember)attributes.getMemberAt(index)).isSet()) continue; } if ("".equals(attributes.getTypeAsString(index)) || "".equals(attributes.getNameAsString(index))) { continue; } tmpAttrVector.addElement(attributes.getTypeAsString(index)); tmpAttrVector.addElement(attributes.getNameAsString(index)); tmpAttrVector .addElement(attributes.getValueAsString(index)); attrs.addElement(tmpAttrVector); } } else { attrs = setAttributes(this.bNode); } } return attrs; } /** Sets my attribute value to the attributes specified by the Node. * Returns a list of lists with type, name, value of attribute members. */ public Vector<Vector<String>> setAttributes(Node bNode) { Vector<Vector<String>> attrs = new Vector<Vector<String>>(); if (bNode == null) return attrs; if (bNode.getAttribute() == null) return attrs; int nattrs = bNode.getAttribute().getNumberOfEntries(); if (nattrs != 0) { for (int i = 0; i < nattrs; i++) { Vector<String> attr = new Vector<String>(); attr.addElement(bNode.getAttribute().getTypeAsString(i)); attr.addElement(bNode.getAttribute().getNameAsString(i)); attr.addElement(bNode.getAttribute().getValueAsString(i)); attrs.addElement(attr); } } return attrs; } /** Sets my attributes to the attributes specified by the GraphObject*/ public Vector<Vector<String>> setAttributes(GraphObject obj) { return setAttributes((Node) obj); } /** Sets my used object specified by the Node bNode */ public void setBasisNode(Node bNode) { this.bNode = bNode; } /** Sets a new basis node */ public void changeBasisNode(Node newNode) { this.bNode = newNode; /* * der alte basis knoten darf nicht zerstoert werden, da er vielleicht * noch in einem anderen graphen existiert. */ } /** Sets my position, visibility, selection */ public void setReps(int nX, int nY, boolean nVisible, boolean nSelect) { setXY(nX, nY); setVisible(nVisible); setSelected(nSelect); } /** * Makes a copy based on the same basis node. */ public EdNode copy() { EdNode newNode = new EdNode(this.bNode, this.eType); newNode.myGraphPanel = this.myGraphPanel; newNode.x = this.x; newNode.y = this.y; newNode.w = this.w; newNode.h = this.h; return newNode; } /** * Returns TRUE if the specified point (X, Y) is inside of my shape. */ public boolean inside(int X, int Y) { Rectangle r = new Rectangle(this.x - this.w/2, this.y - this.h/2, this.w, this.h); if (r.contains(X, Y)) return true; return false; } public void applyScale(double scale) { // System.out.println("EdNode.applyScale:: "+this.itsScale+" to "+scale); if (scale != this.itsScale) { setX((int) ((this.x/this.itsScale) * scale)); setY((int) ((this.y/this.itsScale) * scale)); this.itsScale = scale; } // System.out.println("EdNode.applyScale:: "+this.itsScale); } 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); g.draw(new Rectangle2D.Double(this.x-10, this.y-10, 20, 20)); // reset font style, color g.setFont(EditorConstants.defaultFont); g.setPaint(lastColor); } } /** Draws myself in the graphics specified by the Graphics g */ public void drawGraphic(Graphics grs) { // synchronized (this) { if (!this.visible || this.bNode == null || this.bNode.getType() == null) { return; } this.criticalStyle = this.eGraph.criticalStyle; Graphics2D g = (Graphics2D) grs; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setStroke(EditorConstants.defaultStroke); // save the old color Color lastColor = g.getColor(); myUpdate(g.getFontMetrics()); if (getType().isIconable()) { String fname = getType().imageFileName; URL url = ClassLoader.getSystemClassLoader().getResource(fname); if (url != null) { ImageIcon icon = new ImageIcon(url); if (selected) { g.setPaint(EditorConstants.selectColor); g.fill(new Rectangle2D.Double(this.x - this.w/2 - 2, this.y - this.h/2 - 2, this.w + 4, this.h + 4)); } else if (isCritical()) { if (this.criticalStyle == 0) { g.setPaint(EditorConstants.criticalColor); g.setStroke(EditorConstants.criticalStroke); g.draw(new Rectangle2D.Double(this.x - this.w/2 - 2, this.y - this.h/2 - 2, this.w + 4, this.h + 4)); } else { //if (this.criticalStyle == 1) { g.setPaint(Color.BLACK); g.setStroke(EditorConstants.criticalStroke); g.draw(new Rectangle2D.Double(this.x - this.w/2 - 2, this.y - this.h/2 - 2, this.w+4, this.h+4 )); } } g.setPaint(this.getColor()); g.drawImage(icon.getImage(), this.x - this.w/2, this.y - this.h/2, null); return; } } if (this.backgroundColor != null && this.backgroundColor != Color.white) { g.setPaint(this.backgroundColor); g.fill(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w + 6, this.h + 6)); } int sh = getShape(); boolean hiddenObjOfType = this.eGraph.isTypeGraph() && !this.eType.getBasisType().isObjectOfTypeGraphNodeVisible(); switch (sh) { case EditorConstants.RECT: if (selected) { g.setPaint(EditorConstants.selectColor); g.fill(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); g.setPaint(this.getColor()); g.draw(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); } else if (weakselected) { g.setPaint(Color.white); g.fill(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); g.setPaint(EditorConstants.weakselectColor); g.draw(new Rectangle2D.Double(this.x - this.w/2-1, this.y - this.h/2-1, this.w+2, this.h+2)); g.draw(new Rectangle2D.Double(this.x - this.w/2+1, this.y - this.h/2+1, this.w-2, this.h-2)); g.setPaint(this.getColor()); g.draw(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); } else if (hiddenObjOfType) { g.setPaint(EditorConstants.hideColor); g.fill(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); g.setPaint(this.getColor()); g.draw(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); } else if (isCritical()) { if (this.criticalStyle == 0) { if (this.eType.filled) g.setPaint(this.getColor()); else g.setPaint(Color.white); g.fill(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); g.setPaint(EditorConstants.criticalColor); // g.fill(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); // g.setPaint(this.getColor()); // g.draw(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); g.setStroke(EditorConstants.criticalStroke); g.setFont(EditorConstants.criticalFont); g.draw(new Rectangle2D.Double(this.x - this.w/2 - 4, this.y - this.h/2 - 4, this.w + 8, this.h + 8)); if (this.eType.filled) g.setPaint(Color.white); } else {//if (this.criticalStyle == 1) { g.setPaint(Color.BLACK); g.setStroke(EditorConstants.criticalStroke); g.draw(new Rectangle2D.Double(this.x - this.w/2 -2, this.y - this.h/2 -2, this.w+4, this.h+4)); } } else if (this.ownColor != null) { g.setPaint(this.ownColor); g.fill(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); g.setPaint(Color.white); } else if (this.eType.filled) { g.setPaint(this.getColor()); g.fill(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); g.setPaint(Color.white); } else { g.setPaint(Color.white); g.fill(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); g.setPaint(this.getColor()); g.draw(new Rectangle2D.Double(this.x - this.w/2, this.y - this.h/2, this.w, this.h)); } break; case EditorConstants.ROUNDRECT: if (selected) { g.setPaint(EditorConstants.selectColor); g.fillRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); g.setPaint(this.getColor()); g.drawRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); } else if (weakselected) { g.setPaint(Color.white); g.fillRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); g.setPaint(EditorConstants.weakselectColor); g.drawRoundRect(this.x - this.w/2-1, this.y - this.h/2-1, this.w+2, this.h+2, 10, 10); g.drawRoundRect(this.x - this.w/2+1, this.y - this.h/2+1, this.w-2, this.h-2, 10, 10); g.setPaint(this.getColor()); g.drawRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); } else if (hiddenObjOfType) { g.setPaint(EditorConstants.hideColor); g.fillRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); g.setPaint(this.getColor()); g.drawRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); } else if (isCritical()) { if (this.criticalStyle == 0) { if (this.eType.filled) g.setPaint(this.getColor()); else g.setPaint(Color.white); g.fillRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); g.setPaint(EditorConstants.criticalColor); // g.fillRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); // g.setPaint(this.getColor()); // g.drawRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); g.setStroke(EditorConstants.criticalStroke); g.setFont(EditorConstants.criticalFont); g.drawRoundRect(this.x - this.w/2 -4, this.y - this.h/2 -4, this.w+8, this.h+8, 10, 10); if (this.eType.filled) g.setPaint(Color.white); } else { //if (this.criticalStyle == 1) { g.setStroke(EditorConstants.criticalStroke); g.setPaint(Color.BLACK); g.drawRoundRect(this.x - this.w/2 -2, this.y - this.h/2 -2, this.w+4, this.h+4, 10, 10); } } else if (this.ownColor != null) { g.setPaint(this.ownColor); g.fillRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); g.setPaint(Color.white); } else if (this.eType.filled) { g.setPaint(this.getColor()); g.fillRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); g.setPaint(Color.white); } else { g.setPaint(Color.white); g.fillRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); g.setPaint(this.getColor()); g.drawRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); } break; case EditorConstants.CIRCLE: int d = this.w-2; if (selected) { g.setPaint(EditorConstants.selectColor); g.fillOval(this.x - d/2, this.y - d/2, d, d); g.setPaint(this.getColor()); g.drawOval(this.x - d/2, this.y - d/2, d, d); } else if (weakselected) { g.setPaint(Color.white); g.fillOval(this.x - d/2, this.y - d/2, d, d); g.setPaint(EditorConstants.weakselectColor); g.drawOval(this.x - d/2-1, this.y - d/2-1, d+2, d+2); g.drawOval(this.x - d/2+1, this.y - d/2+1, d-2, d-2); g.setPaint(this.getColor()); g.drawOval(this.x - d/2, this.y - d/2, d, d); } else if (hiddenObjOfType) { g.setPaint(EditorConstants.hideColor); g.fillOval(this.x - d/2, this.y - d/2, d, d); g.setPaint(this.getColor()); g.drawOval(this.x - d/2, this.y - d/2, d, d); } else if (isCritical()) { if (this.criticalStyle == 0) { if (this.eType.filled) g.setPaint(this.getColor()); else g.setPaint(Color.white); g.fillOval(this.x - d/2, this.y - d/2, d, d); g.setPaint(EditorConstants.criticalColor); // g.fillOval(this.x - d/2, this.y - d/2, d, d); // g.setPaint(this.getColor()); // g.drawOval(this.x - d/2, this.y - d/2, d, d); g.setStroke(EditorConstants.criticalStroke); g.setFont(EditorConstants.criticalFont); g.drawOval(this.x - d/2 -4, this.y - d/2 -4, d+8, d+8); if (this.eType.filled) g.setPaint(Color.white); } else { //if (this.criticalStyle == 1) { g.setStroke(EditorConstants.criticalStroke); g.setPaint(Color.BLACK); g.drawOval(this.x - d/2 -2, this.y - d/2 -2, d+4, d+4); } } else if (this.ownColor != null) { g.setPaint(this.ownColor); g.fillOval(this.x - d/2, this.y - d/2, d, d); g.setPaint(Color.white); } else if (this.eType.filled) { g.setPaint(this.getColor()); g.fillOval(this.x - d/2, this.y - d/2, d, d); g.setPaint(Color.white); } else { g.setPaint(Color.white); g.fillOval(this.x - d/2, this.y - d/2, d, d); g.setPaint(this.getColor()); g.drawOval(this.x - d/2, this.y - d/2, d, d); } break; case EditorConstants.OVAL: d = this.w-2; if (selected) { g.setPaint(EditorConstants.selectColor); g.fillOval(this.x - d/2, this.y - this.h/2, d, this.h); g.setPaint(this.getColor()); g.drawOval(this.x - d/2, this.y - this.h/2, d, this.h); } else if (weakselected) { g.setPaint(Color.white); g.fillOval(this.x - d/2, this.y - this.h/2, d, this.h); g.setPaint(EditorConstants.weakselectColor); g.drawOval(this.x - d/2-1, this.y - this.h/2-1, d+2, this.h+2); g.drawOval(this.x - d/2+1, this.y - this.h/2+1, d-2, this.h-2); g.setPaint(this.getColor()); g.drawOval(this.x - d/2, this.y - this.h/2, d, this.h); } else if (hiddenObjOfType) { g.setPaint(EditorConstants.hideColor); g.fillOval(this.x - d/2, this.y - this.h/2, d, this.h); g.setPaint(this.getColor()); g.drawOval(this.x - d/2, this.y - this.h/2, d, this.h); } else if (isCritical()) { if (this.criticalStyle == 0) { if (this.eType.filled) g.setPaint(this.getColor()); else g.setPaint(Color.white); g.fillOval(this.x - d/2, this.y - this.h/2, d, this.h); g.setPaint(EditorConstants.criticalColor); // g.fillOval(this.x - d/2, this.y - this.h/2, d, this.h); // g.setPaint(this.getColor()); // g.drawOval(this.x - d/2, this.y - this.h/2, d, this.h); g.setStroke(EditorConstants.criticalStroke); g.setFont(EditorConstants.criticalFont); g.drawOval(this.x - d/2 -4, this.y - this.h/2 -4, d+8, this.h+8); if (this.eType.filled) g.setPaint(Color.white); } else if (this.criticalStyle == 1) { g.setStroke(EditorConstants.criticalStroke); g.setPaint(Color.BLACK); g.drawOval(this.x - d/2 -2, this.y - this.h/2 -2, d+4, this.h+4); } } else if (this.ownColor != null) { g.setPaint(this.ownColor); g.fillOval(this.x - d/2, this.y - this.h/2, d, this.h); g.setPaint(Color.white); } else if (this.eType.filled) { g.setPaint(this.getColor()); g.fillOval(this.x - d/2, this.y - this.h/2, d, this.h); g.setPaint(Color.white); } else { g.setPaint(Color.white); g.fillOval(this.x - d/2, this.y - this.h/2, d, this.h); g.setPaint(this.getColor()); g.drawOval(this.x - d/2, this.y - this.h/2, d, this.h); } break; default: break; } if (this.errorMode) { // if there was an error print in green g.setPaint(Color.green); } // Text if (this.bNode.getType().isAbstract()) g.setFont(new Font("Dialog", Font.ITALIC, g.getFont().getSize())); g.setStroke(EditorConstants.defaultStroke); drawText(g, this.x, this.y); g.setFont(EditorConstants.defaultFont); g.setPaint(lastColor); } } /** Updates my width and height */ public void myUpdate(FontMetrics fm) { prepareGraphics(fm); } /** Erases my graphic */ public void eraseGraphic(Graphics grs) { Color c = grs.getColor(); grs.setColor(Color.white); grs.fillRect(this.x - this.w/2 - 1, this.y - this.h/2 - 1, this.w + 2, this.h + 2); grs.setColor(c); } /** * Implements the AttrViewObserver. Makes update graphics if the attributes * of my used object are changed. */ public void attributeChanged(AttrViewEvent ev) { // System.out.println("EdNode.attributeChanged: "+ev.getID()); // ((ValueTuple)this.bNode.getAttribute()).showValue(); if (ev.getID() == AttrEvent.GENERAL_CHANGE // 0 ||ev.getID() == AttrEvent.MEMBER_RETYPED || ev.getID() == AttrEvent.MEMBER_RENAMED || ev.getID() == AttrEvent.MEMBER_DELETED || ev.getID() == AttrViewEvent.MEMBER_VISIBILITY || ev.getID() == AttrViewEvent.MEMBER_MOVED) { 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.bNode.getContext().getAttrContext() != null) { ValueMember val = ((ValueTuple) this.bNode .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.bNode.getContext().isNacGraph()) var.setMark(VarMember.NAC); else if (this.bNode.getContext().isPacGraph()) var.setMark(VarMember.PAC); else if (viewContext .doesAllowComplexExpressions()) var.setMark(VarMember.RHS); else var.setMark(VarMember.LHS); } } } } } else { ValueTuple attr = (ValueTuple) this.bNode.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; } /** Gets the bounding rectangle around myself */ public Rectangle toRectangle() { return new Rectangle(getX() - getWidth()/2, getY() - getHeight()/2, getWidth(), getHeight()); } /** Prepares my graphics */ private void prepareGraphics(FontMetrics fm) { int h1 = getTextHeight(fm) + 4; if (h1 < 20) h1 = 20; // min height = 20 int w1 = getTextWidth(fm) + 6; if (w1 < 20) w1 = h1; // min width 20 setWidth(w1); setHeight(h1); if (getType().isIconable()) { // String fname = getType().resourcesPath+getType().imageFileName; // URL url = ClassLoader.getSystemClassLoader().getResource(fname); String fname = getType().imageFileName; URL url = ClassLoader.getSystemClassLoader().getResource(fname); // System.out.println("URL: "+url); if (url != null) { ImageIcon icon = new ImageIcon(url); h1 = icon.getIconHeight(); w1 = icon.getIconWidth(); setWidth(w1); setHeight(h1); return; } } int sh = getShape(); switch (sh) { case EditorConstants.RECT: break; case EditorConstants.ROUNDRECT: break; case EditorConstants.CIRCLE: int d1 = (int) Math.sqrt((double) (this.w * this.w) + (double) (this.h * this.h)); int d2 = this.w; if (this.h > this.w) d2 = this.h; int d = (d1 + d2)/2; setWidth(d); setHeight(d); break; case EditorConstants.OVAL: int hor = 0, ver = 0; hor = (int) Math.sqrt((double) (this.w * this.w) + (double) (this.h * this.h)); if (this.w == this.h) { ver = hor - hor/4; } else if (this.h > this.w) { ver = hor; hor = ver + ver/4; } else if (this.w > this.h) { ver = hor - hor/4; } setWidth(hor); setHeight(ver); break; default: break; } } protected String getMultiplicityString() { String s = ""; int min = this.bNode.getType().getSourceMin(); int max = this.bNode.getType().getSourceMax(); // System.out.println("EdNode.getMultiplicityString:: "+min+" "+max); 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); } return s; } private void drawText(Graphics grs, int centerX, int centerY) { // System.out.println("EdNode.showText "); Graphics2D g = (Graphics2D) grs; boolean underlined = false; int tx1, ty1; FontMetrics fm = g.getFontMetrics(); // System.out.println("FontWidth (m): "+ fm.stringWidth("m")); // System.out.println("FontHeight: "+ fm.getHeight()); // System.out.println("FontDescent: "+ fm.getDescent()); // System.out.println("FontAscent: "+ fm.getAscent()); int tw = getTextWidth(fm); int th = getTextHeight(fm); int tx = centerX - tw/2; int ty = centerY - th/2; // System.out.println("h: "+th); // type name string String typeStr = getTypeString(); if (this.elemOfTG) { if (this.bNode.getType().isAbstract()) { if (!typeStr.equals("")) typeStr = "{" + typeStr + "}"; else typeStr = "{ }"; } String multiplicityStr = getMultiplicityString(); if (!multiplicityStr.equals("")) { tx1 = centerX + tw/2 - fm.stringWidth(multiplicityStr); ty1 = ty + fm.getHeight()/2 + fm.getDescent()/2; g.drawString(multiplicityStr, tx1, ty1); } } if (!typeStr.equals("")) { tx1 = tx; ty1 = ty + (fm.getHeight() - fm.getDescent()); g.drawString(typeStr, tx1, ty1); ty = ty + fm.getHeight(); } else ty = ty + fm.getHeight() + fm.getDescent()/4; 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) { g.drawLine(tx, ty, tx + tw, ty); underlined = true; } ty1 = ty + (fm.getHeight() - fm.getDescent()); 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) { g.drawLine(tx, ty, tx + tw, ty); underlined = true; } ty1 = ty + (fm.getHeight() - fm.getDescent()); g.drawString(attrStr, tx, ty1); ty = ty + fm.getHeight(); } } } } public void drawNameAttrOnly(Graphics grs) { // if (!this.isVisible()) { if (!this.visible) { return; } this.criticalStyle = this.eGraph.criticalStyle; Graphics2D g = (Graphics2D) grs; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // g.setStroke(stroke); g.setStroke(new BasicStroke(2.0f)); updateNameAttrOnly(g.getFontMetrics()); g.setPaint(Color.white); g.fillRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); g.setPaint(this.getColor()); g.drawRoundRect(this.x - this.w/2, this.y - this.h/2, this.w, this.h, 10, 10); showNameAttrOnly(g, this.x, this.y); g.setStroke(EditorConstants.defaultStroke); } public void updateNameAttrOnly(FontMetrics fm) { Vector<Vector<String>> attrs = getAttributes(); int nn = 1; // attrs number always 1 int h1 = 0; // die Hoehe einer Zeile if (fm == null) h1 = 17; // default else h1 = fm.getHeight(); // gesamte Hoehe if (h1 < 20) h1 = 30; nn = 6; // default char width int w1 = 0; if (attrs != null) { for (int i = 0; i < attrs.size(); i++) { Vector<String> attr = attrs.elementAt(i); if (attr.elementAt(1).equals("name")) { if (attr.elementAt(2).length() != 0) { String tstStr = attr.elementAt(2); if (fm == null) w1 = nn * tstStr.length() + 6; else w1 = fm.stringWidth(tstStr) + 6; } } } } if (w1 < 20) w1 = h1; // min width 20 setWidth(w1); setHeight(h1); } private void showNameAttrOnly(Graphics grs, int centerX, int centerY) { // System.out.println("EdNode.showAttrNameOnly "); Graphics2D g = (Graphics2D) grs; g.setStroke(new BasicStroke(2.0f)); FontMetrics fm = g.getFontMetrics(); Vector<Vector<String>> attrs = getAttributes(); int th = getHeight(); int tw = getWidth(); int tx = centerX - tw/2 + 9; int ty = centerY - th/2 + 5; ty = ty + fm.getHeight(); // + fm.getDescent()/4; // Attribute anzeigen if (attrs != null && !attrs.isEmpty()) { for (int i = 0; i < attrs.size(); i++) { Vector<String> attr = attrs.elementAt(i); if (attr.elementAt(1).equals("name")) { if (attr.elementAt(2).length() != 0) { String attrStr = attr.elementAt(2); // ty1 = ty+(fm.getHeight()-fm.getDescent()); g.drawString( attrStr.substring(1, attrStr.length() - 1), tx, ty); return; } } } } } public void XwriteObject(XMLHelper xmlh) { if (xmlh.openObject(this.bNode, this)) { xmlh.openSubTag("NodeLayout"); int outX = (int) (this.x/this.itsScale); int outY = (int) (this.y/this.itsScale); xmlh.addAttr("X", outX); xmlh.addAttr("Y", outY); // System.out.println("EdNode.XwriteObject:: X,Y: "+outX+" , "+outY); xmlh.close(); // LayoutNode speichern: if (this.lNode != null) { xmlh.addObject("", this.lNode, true); } xmlh.close(); } } public void XreadObject(XMLHelper xmlh) { xmlh.peekObject(this.bNode, this); if (xmlh.readSubTag("NodeLayout")) { this.hasDefaultLayout = true; String s = xmlh.readAttr("X"); if (s.length() == 0) { this.x = 20; } else { this.x = (new Integer(s)).intValue(); } s = xmlh.readAttr("Y"); if (s.length() == 0) { this.y = 20; } else { this.y = (new Integer(s)).intValue(); } xmlh.close(); } else { this.x = 20; this.y = 20; } // layoutNode einlesen: xmlh.enrichObject(this.lNode); xmlh.close(); if (this.bNode.xyAttr && this.getContext().getBasisGraph().isCompleteGraph()) { ValueMember xattr = ((ValueTuple)this.bNode.getAttribute()).getValueMemberAt("thisX"); if (!xattr.isSet()) ((ValueTuple)this.bNode.getAttribute()).getValueMemberAt("thisX").setExprAsObject(this.x); ValueMember yattr = ((ValueTuple)this.bNode.getAttribute()).getValueMemberAt("thisY"); if (!yattr.isSet()) ((ValueTuple)this.bNode.getAttribute()).getValueMemberAt("thisY").setExprAsObject(this.y); } this.attrVisible = true; this.attrChanged = false; } /** * Checks whether the basis Nodes of this EdNode and the specified EdNode * <code>enode</code> are equal. * * @param enode * @return true, if the basis nodes are equal, otherwise - false */ public boolean equalByBasisNode(EdNode enode) { if (this.getBasisNode().equals(enode.getBasisNode())) { return true; } return false; } /** * Searchs through the specified vector for an EdNode with the same ID * number. Such ID is set by the method <code>setNodeID(int)</code>. * * @param enodes * nodes to search * @return index of a node with the same ID, if found, otherwise returns -1. */ public int isInVectorByBasisNode(List<EdNode> enodes) { int ret = -1; EdNode node; for (int i = 0; i < enodes.size(); i++) { node = enodes.get(i); if (this.getNodeID() == node.getNodeID()) { ret = i; break; } } return ret; } public void setNodeID(int id) { this.nodeid = id; } public void setOwnColor(final Color c) { this.ownColor = c; } public Color getOwnColor() { return this.ownColor; } public int getNodeID() { return this.nodeid; } public void setCluster(Vector<Integer> clus) { this.cluster = new Vector<Integer>(clus); } public Vector<Integer> getCluster() { return this.cluster; } public void calculateCluster(int epsilon, List<EdNode> nodes) { EdNode node; int xdist, ydist, dist; this.oldcluster = this.cluster; this.cluster = new Vector<Integer>(); for (int i = 0; i < nodes.size(); i++) { node = nodes.get(i); if (!this.equals(node)) { xdist = Math.abs(node.getX() - this.getX()); ydist = Math.abs(node.getY() - this.getY()); // if(xdist > 0 || ydist > 0) { dist = (int) Math.round(Math.sqrt((xdist * xdist) + (ydist * ydist))); if (dist <= epsilon) this.cluster.addElement(new Integer(node.getNodeID())); } } } } public Vector<Integer> getOldCluster() { return this.oldcluster; } } // $Log: EdNode.java,v $ // Revision 1.61 2010/11/14 12:59:11 olga // tuning // // Revision 1.60 2010/11/12 15:14:53 olga // tuning // // Revision 1.59 2010/11/10 01:14:49 olga // tuning // // Revision 1.58 2010/11/09 16:41:25 olga // tuning // // Revision 1.57 2010/08/25 00:33:06 olga // tuning // // Revision 1.56 2010/03/19 14:46:49 olga // tuning // // Revision 1.55 2010/03/18 18:17:27 olga // tuning // // Revision 1.54 2010/03/17 21:38:36 olga // tuning // // Revision 1.53 2010/03/08 15:40:04 olga // code optimizing // // Revision 1.52 2010/03/04 14:08:22 olga // code optimizing // // Revision 1.51 2010/02/22 15:08:11 olga // code optimizing // // Revision 1.50 2010/01/31 16:42:58 olga // tuning // // Revision 1.49 2009/10/14 07:53:05 olga // GUI bug fixed // // Revision 1.48 2009/09/07 08:59:42 olga // RuleSequence.copyObjectFlow - improved // // Revision 1.47 2009/07/30 14:52:11 olga // new method - setOwnColor(Color) // to unset own color use - setOwnColor(null) // // Revision 1.46 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.45 2009/04/14 09:18:34 olga // Edge Type Multiplicity check - bug fixed // // Revision 1.44 2009/03/30 13:50:49 olga // some tests // // Revision 1.43 2009/03/25 15:19:14 olga // code tuning // // Revision 1.42 2009/02/04 10:11:29 olga // Termination check and GUI tuning // // Revision 1.41 2008/12/04 14:30:02 olga // Node Type Inheritance: init of parent attributes - bug fixed // // Revision 1.40 2008/11/06 08:45:36 olga // Graph layout is extended by Zest Graph Layout ( eclipse zest plugin) // // Revision 1.39 2008/10/29 09:04:04 olga // new sub packages of the package agg.gui: typeeditor, editor, trafo, cpa, options, treeview, popupmenu, saveload // // Revision 1.38 2008/10/15 07:51:22 olga // Delete attr. member of parent type : error message dialog to warn the user // // Revision 1.37 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.36 2008/09/04 07:48:42 olga // GUI extension: hide nodes, edges // // Revision 1.35 2008/07/21 10:03:28 olga // Code tuning // // Revision 1.34 2008/07/17 15:51:50 olga // GraphEditor - graph scaling tuning // // Revision 1.33 2008/07/16 15:52:49 olga // Import GXL file - bug fixed // // Revision 1.32 2008/07/14 07:35:47 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.31 2008/07/02 17:14:36 olga // Code tuning // // Revision 1.30 2008/06/30 10:47:40 olga // Applicability of Rule Sequence - tuning // Node animation - first steps // // Revision 1.29 2008/06/26 14:18:47 olga // Graph visualization tuning // // Revision 1.28 2008/04/17 10:11:07 olga // Undo, redo edit and graph layout tuning, // // Revision 1.27 2008/04/11 13:29:05 olga // Memory usage - tuning // // Revision 1.26 2008/04/10 10:53:14 olga // Draw graphics tuning // // Revision 1.25 2008/04/07 09:36:50 olga // Code tuning: refactoring + profiling // Extension: CPA - two new options added // // Revision 1.24 2008/01/23 15:03:18 olga // Tuning of usability of the gragra editor. // // Revision 1.23 2007/12/17 08:33:30 olga // Editing inheritance relations - bug fixed; // CPA: dependency of rules - bug fixed // // Revision 1.22 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.21 2007/11/05 09:18:17 olga // code tuning // // Revision 1.20 2007/11/01 09:58:11 olga // Code refactoring: generic types- done // // Revision 1.19 2007/10/11 08:05:04 olga // Enumeration typing // // Revision 1.18 2007/09/24 09:42:33 olga // AGG transformation engine tuning // // Revision 1.17 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.16 2007/07/02 08:27:33 olga // Help docu update, // Source tuning // // Revision 1.15 2007/06/13 08:32:47 olga // Update: V161 // // Revision 1.14 2007/04/19 07:52:34 olga // Tuning of: Undo/Redo, Graph layouter, loading grammars // // Revision 1.13 2007/04/11 10:03:35 olga // Undo, Redo tuning, // Simple Parser- bug fixed // // Revision 1.12 2007/03/28 10:00:27 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.11 2007/01/22 08:28:29 olga // GUI bugs fixed // // Revision 1.10 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.9 2006/08/09 07:42:18 olga // API docu // // Revision 1.8 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.7 2006/05/29 07:59:41 olga // GUI, undo delete - tuning. // // Revision 1.6 2006/03/01 09:55:46 olga // - new CPA algorithm, new CPA GUI // // Revision 1.5 2005/12/21 14:49:20 olga // GUI tuning // // Revision 1.4 2005/11/07 09:38:07 olga // Null pointer during retype attr. member fixed. // // Revision 1.3 2005/10/10 08:05:16 olga // Critical Pair GUI and CPA graph // // 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.4 2005/07/13 08:13:37 olga // Some code optimization only // // 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/08/16 09:52:55 enrico // Masking of attributes inherited from parent // // 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.29 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.28 2005/02/14 09:27:01 olga // -PAC; // -GUI, layered graph transformation anzeigen; // -CPs. // // Revision 1.27 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.26 2004/12/20 14:53:48 olga // Changes because of matching optimisation. // // Revision 1.25 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.24 2004/10/25 14:24:37 olga // Fehlerbehandlung bei CPs und Aenderungen im zusammenhang mit // termination-Modul // in AGG // // Revision 1.23 2004/09/13 10:21:14 olga // Einige Erweiterungen und Fehlerbeseitigung bei CPs und // Graph Grammar Transformation // // Revision 1.22 2004/07/16 14:25:16 olga // ::: // // Revision 1.21 2004/07/16 13:02:02 olga // TypeGraph OK // // Revision 1.20 2004/07/15 11:13:10 olga // CPs letzter Schliff // // Revision 1.19 2004/06/14 12:34:19 olga // CP Analyse and Transformation // // Revision 1.18 2004/06/09 11:32:54 olga // Attribute-Eingebe/Bedingungen : NAC kann jetzt eigene Variablen und // Bedingungen // haben. // CP Berechnung korregiert. // // Revision 1.17 2004/05/26 16:17:40 olga // Observer / observable // // Revision 1.16 2004/04/28 12:46:38 olga // test CSP // // Revision 1.15 2003/12/18 16:26:23 olga // Copy method and Layout // // Revision 1.14 2003/04/10 09:05:24 olga // Aenderungen wegen serializable Ausgabe // // Revision 1.13 2003/04/10 08:50:33 olga // Tests mit serializable Ausgabe // // Revision 1.12 2003/03/20 13:34:11 olga // Delete TypeGraph eingefuegt // // Revision 1.11 2003/03/17 15:33:00 olga // Kleine Korrektur von Xread, Xwrite // // Revision 1.10 2003/03/05 18:24:24 komm // sorted/optimized import statements // // Revision 1.9 2002/11/25 15:03:51 olga // Arbeit an den Typen. // // Revision 1.8 2002/11/14 14:29:39 olga // Anzeige von Multiplicity -- ein Versuch. // // Revision 1.7 2002/11/11 09:42:53 olga // Nur Testausgaben // // Revision 1.6 2002/11/11 09:20:56 olga // Tests // // Revision 1.5 2002/10/02 18:30:42 olga // XXX // // Revision 1.4 2002/09/30 10:08:27 komm // insert TypeException and type error marks // // Revision 1.3 2002/09/30 10:02:29 olga // Layout // // Revision 1.2 2002/09/19 16:21:23 olga // Layout von Knoten geaendert. // // Revision 1.1.1.1 2002/07/11 12:17:08 olga // Imported sources // // Revision 1.21 2001/05/14 12:00:41 olga // Graph Layout und Graphobject Layout optimiert. // // Revision 1.20 2001/03/08 10:53:20 olga // Das ist Stand nach der AGG GUI Reimplementierung. // // Revision 1.19 2000/12/21 09:48:52 olga // In dieser Version wurden XML und GUI Reimplementierung zusammen gefuehrt. // // Revision 1.18 2000/12/07 14:23:36 matzmich // XML-Kram // Man beachte: xerces (/home/tfs/gragra/AGG/LIB/Xerces/xerces.jar) wird // jetzt im CLASSPATH benoetigt. // // Revision 1.17.8.5 2000/12/13 13:21:18 olga // Neu: removeRules() // // Revision 1.17.8.4 2000/12/07 14:31:36 olga // Korrektur der Pfeile. // // Revision 1.17.8.3 2000/12/06 16:30:49 olga // *** empty log message *** // // Revision 1.17.8.2 2000/12/06 10:13:21 olga // Rendering hints in Graphics2D gesetzt. // // Revision 1.17.8.1 2000/11/06 09:32:32 olga // Erste Version fuer neue GUI (Branch reimpl) // // Revision 1.17 1999/10/06 14:25:51 olga // *** empty log message *** // // Revision 1.16 1999/09/30 08:58:46 olga // *** empty log message *** // // Revision 1.15 1999/09/27 16:17:27 olga // *** empty log message *** // // Revision 1.14 1999/09/23 14:00:59 olga // *** empty log message *** // // Revision 1.13 1999/09/20 10:58:24 olga // *** empty log message *** // // Revision 1.12 1999/09/20 10:43:55 olga // *** empty log message *** // // Revision 1.11 1999/09/16 13:57:20 olga // *** empty log message *** // // Revision 1.10 1999/09/15 12:54:03 olga // *** empty log message *** // // Revision 1.9 1999/08/03 13:23:08 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.8 1999/07/28 11:23:41 shultzke // Events werden richtig benutzt // Konstruktoren verschoenert // // Revision 1.7 1999/07/26 10:25:09 shultzke // Views koennen zwar benutzt werden. Sie werden // aber noch nicht nach dem Laden rekonstruiert. //