// 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 */