// Copyright (c) 1996-98 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation for educational, research and non-profit // purposes, without fee, and without a written agreement is hereby granted, // provided that the above copyright notice and this paragraph appear in all // copies. Permission to incorporate this software into commercial products may // be obtained by contacting the University of California. David F. Redmiles // Department of Information and Computer Science (ICS) University of // California Irvine, California 92697-3425 Phone: 714-824-3823. This software // program and documentation are copyrighted by The Regents of the University // of California. The software program and documentation are supplied "as is", // without any accompanying services from The Regents. The Regents do not // warrant that the operation of the program will be uninterrupted or // error-free. The end-user understands that the program was developed for // research purposes and is advised not to rely exclusively on the program for // any reason. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY // PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS // DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY // DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE // SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, // ENHANCEMENTS, OR MODIFICATIONS. // File: LayerPerspective.java // Classes: LayerPerspective // Original Author: jrobbins@ics.uci.edu // $Id: LayerPerspective.java,v 1.9 1997/06/10 23:43:00 jrobbins Exp $ package uci.graphedit; import java.util.*; import java.awt.*; /** A Layer like found in many drawing applications. It contains a * collection of DiagramElement's, ordered from back to front. Each * LayerPerspective contains part of the overall picture that the user is * drawing. * * FEATURE: graph_visualization * * FEATURE: multiple_perspectives */ public class LayerPerspective extends LayerDiagram { //////////////////////////////////////////////////////////////// // constants /** The space between node perspectives that are automatically places. */ public static final int GAP = 16; //////////////////////////////////////////////////////////////// // instance variables /** The underlying connected graph to be visualized. */ protected NetList _net; /** Classes of NetNodes and NetArcs that are to be visualized in * this perspective. * * FEATURE: multiple_perspectives */ protected Vector _allowedNetClasses = new Vector(); /** Rectangles of where to place nodes that are automatically added. */ protected Hashtable _nodeTypeRegions = new Hashtable(); /** True if the second column of automattically placed node * perspectives should be moved down by half the a node height. */ protected boolean _stagger = true; //////////////////////////////////////////////////////////////// // constructors /** Construct a new LayerPerspective with a default name and do not put * it on the Layer's menu. */ public LayerPerspective(NetList net) { this("LayerPerspective" + numberWordFor(_nextLayerNumbered++), net); } /** Construct a new LayerPerspective with the given name, and add it to * the menu of layers. Needs-More-Work: I have not implemented a * menu of layers yet. I don't know if that is really the right user * interface */ public LayerPerspective(String name, NetList net) { super(name); _net = net; _net.addPersistantObserver(this); } //////////////////////////////////////////////////////////////// // accessors /** Reply the NetList of the underlying connected graph. */ public NetList net() { return _net; } /** Add a node class of NetNodes or NetArcs to what will be shown in * this perspective. * * FEATURE: multiple_perspectives */ public void allowNetClass(Class c) { _allowedNetClasses.addElement(c); } //////////////////////////////////////////////////////////////// // Layer API /** Add a DiagramElement to the contents of this layer. Items are * added on top of all other items. */ public void add(DiagramElement de) { super.add(de); if (de instanceof Perspective) _net.addNode((NetNode)de.owner()); else if (de instanceof ArcPerspective) _net.addArc((NetArc)de.owner()); // if a node is explicitly added to me then accept it regardless // of my predicate, and add it to the net } /** Remove the given DiagramElement from this layer. */ public void remove(DiagramElement de) { super.remove(de); if (de instanceof Perspective) _net.removeNode((NetNode)de.owner()); if (de instanceof ArcPerspective) _net.removeArc((NetArc)de.owner()); } /** Find the DiagramElement that is being used to visualize the * given NetPort, or null if there is none in this layer. */ public Perspective getPortPerspective(NetPort prt) { Enumeration prims = elements(); while (prims.hasMoreElements()) { DiagramElement de = (DiagramElement) prims.nextElement(); if (de instanceof Perspective) { Perspective cur_pers = (Perspective) de; Fig find_fig = cur_pers.getPortFig(prt); if (find_fig!=null) return cur_pers; } } return null; } //////////////////////////////////////////////////////////////// // node placement public void addNodeTypeRegion(Class nodeClass, Rectangle region) { _nodeTypeRegions.put(nodeClass, region); } public void putInPosition(DiagramElement de) { Class nodeClass = de.owner().getClass(); Rectangle placementRegion = (Rectangle) _nodeTypeRegions.get(nodeClass); if (placementRegion != null) { de.position(placementRegion.x, placementRegion.y); bumpOffOtherNodesIn(de, placementRegion); } } public void bumpOffOtherNodesIn(DiagramElement newDE, Rectangle bounds) { Rectangle bbox = newDE.getBoundingBox(); int col = 0; while (bounds.intersects(bbox)) { Enumeration overlappers = elementsIn(bbox); if (!overlappers.hasMoreElements()) return; newDE.translate(0, bbox.height + GAP); bbox.y += bbox.height + GAP; if (!(bounds.intersects(bbox))) { col++; int x = bbox.x + bbox.width + GAP; int y = bounds.y; if (_stagger) y += (col%2)*(bbox.height+GAP)/2; newDE.position(x, y); bbox.move(x, y); } } } //////////////////////////////////////////////////////////////// // nofitications and updates public void update(Observable o, Object arg) { if (arg instanceof Vector) { Vector varg = (Vector)arg; String s = (String) varg.elementAt(0); Object obj = varg.elementAt(1); if (obj instanceof NetNode) { NetNode node = (NetNode) obj; if (s.equals("add") && shouldShow(node)) { //System.out.println("NetNode added to net: " + node); DiagramElement oldDE = perspectiveFor(obj); if (null == oldDE) { DiagramElement newDE = node.perspectiveFor(this); if (newDE != null) { putInPosition(newDE); add(newDE); } else System.out.println("added node de is null"); } } } if (obj instanceof NetArc) { NetArc arc = (NetArc) obj; if (s.equals("add") && shouldShow(arc)) { DiagramElement oldDE = perspectiveFor(obj); if (null == oldDE) { DiagramElement newDE = arc.perspectiveFor(this); if (newDE != null) { add(newDE); ((ArcPerspective)newDE).computeRoute(); newDE.reorder(ActionReorder.SEND_TO_BACK, this); newDE.endTrans(); } else System.out.println("added arc de is null!!!!!!!!!!!!!!!!"); } } } } super.update(o, arg); } /* end update */ /** Test to determine if a given NetNode should have a Perspective * in this layer. Normally checks NetNode class against a list of * allowable classes. For more sophisticated rules, override this * method. * * FEATURE: multiple_perspectives */ public boolean shouldShow(NetNode n) { if (_allowedNetClasses.size() > 0 && !_allowedNetClasses.contains(n.getClass())) return false; return true; } /** Test to determine if a given NetArc should have an ArcPerspective * in this layer. Normally checks NetNode class against a list of * allowable classes. For more sophisticated rules, override this * method. * * FEATURE: multiple_perspectives */ public boolean shouldShow(NetArc a) { if (_allowedNetClasses.size() > 0 && !_allowedNetClasses.contains(a.getClass())) return false; if (getPortPerspective(a.sourcePort()) == null || getPortPerspective(a.destPort()) == null) return false; return true; } } /* end class LayerPerspective */