ontologyvisualizationviewer.java

来自「Semantic Web Ontology Editor」· Java 代码 · 共 1,510 行 · 第 1/3 页

JAVA
1,510
字号
/*
 * Created on Jul 27, 2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

/**
 * @author Dave Wang
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package org.mindswap.swoop.utils.graph.hierarchy;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.mindswap.swoop.SwoopModel;

import edu.uci.ics.jung.exceptions.FatalException;
import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.impl.DirectedSparseGraph;
import edu.uci.ics.jung.graph.impl.DirectedSparseVertex;
import edu.uci.ics.jung.utils.PickEventListener;
import edu.uci.ics.jung.visualization.GraphMouseListener;
import edu.uci.ics.jung.visualization.Layout;
import edu.uci.ics.jung.visualization.MultiPickedState;
import edu.uci.ics.jung.visualization.PickSupport;
import edu.uci.ics.jung.visualization.PickedState;
import edu.uci.ics.jung.visualization.Renderer;
import edu.uci.ics.jung.visualization.StatusCallback;
import edu.uci.ics.jung.visualization.VisualizationViewer;

/**
 * A class that maintains many of the details necessary for creating
 * visualizations of graphs.
 * 
 * @author Joshua O'Madadhain
 * @author Tom Nelson
 * @author Danyel Fisher
 */
public class OntologyVisualizationViewer extends VisualizationViewer
{
	//protected StatusCallback statusCallback;
	Thread relaxer;

	boolean suspended;

	boolean manualSuspend;

	private SwoopModel myModel = null;

	private OntologyWithClassHierarchyGraph myGraph = null;

	protected Set previousSelectedNodes = null; // selected nodes (by
												// mouse/selection list)

	protected Set previousHighlightedNodes = null; // highlighted nodes (by
												   // search box)

	protected SwoopOntologyVertex previousSelectedVertex = null; // selected
																 // vertex by
																 // mouse

	protected ClassTreeNode listBrowsedNode = null; // viewed/browsed in the class list

	protected ClassTreeNode rightSelectedNode = null; // right clicked node
	
	protected ClassTreeNode currentSelectedNode = null;  // the node that's selected by user

	//protected Renderer renderer;
	//protected Layout layout;

	//protected ToolTipListener toolTipListener;

	/**
	 * holds the values for zoom/pan of the display
	 */
	//protected AffineTransform transform;
	/**
	 * the inverse of transform. Used to map window points to graph points.
	 * Lazily created in transform method and reset to null any time transform
	 * is changed.
	 */
	//protected AffineTransform inverse;
	//protected Map renderingHints = new HashMap();
	/**
	 * pluggable support for picking graph elements by finding them based on
	 * their coordinates. Typically used in mouse events.
	 */
	//protected PickSupport pickSupport;
	/**
	 * pluggable support for handling the picked/not-picked state of graph
	 * elements.
	 */
	//protected PickedState pickedState;
	/**
	 * an offscreen image to render the graph
	 */
	//protected BufferedImage offscreen;
	/**
	 * graphics context for the offscreen image
	 */
	//protected Graphics2D offscreenG2d;
	/**
	 * a collection of user-implementable functions to render under the topology
	 * (before the graph is rendered)
	 */
	//protected List preRenderers = new ArrayList();
	/**
	 * a collection of user-implementable functions to render over the topology
	 * (after the graph is rendered)
	 */
	//protected List postRenderers = new ArrayList();
	//protected long relaxerThreadSleepTime = 20L;
	/**
	 * The <code>changeListener</code>.
	 */
	//protected ChangeListener changeListener;
	/**
	 * Only one <code>ChangeEvent</code> is needed instance since the event's
	 * only state is the source property. The source of events generated is
	 * always "this".
	 */
	//protected transient ChangeEvent changeEvent;
	//public Object pauseObject = new String("PAUSE OBJECT");
	
	// keeps track of where the current view port is centered at
	protected double currentX = 0;
	protected double currentY = 0;

	// debugging values
	private boolean DEBUG = false;
	
	private double DEBUGX = 0;
	private double DEBUGY = 0;
	private double DEBUGW = 0;
	private double DEBUGH = 0;
	
	private double DX = 0;
	private double DY = 0;

	/**
	 * The VisualizationViewer constructor creates a JPanel based a given Layout
	 * and Renderer. While GraphDraw places reasonable defaults on these, this
	 * gives more precise control.
	 * 
	 * @param layout
	 *            The Layout to apply, with its associated Graph
	 * @param renderer
	 *            The Renderer to draw it with
	 */
	public OntologyVisualizationViewer(SwoopModel model,
			OntologyWithClassHierarchyGraph graph, Layout layout, Renderer r) {
		super(layout, r);
		myModel = model;
		myGraph = graph;
		
		// adding postrenderer (overlaygraph)
		//postRenderers.add(myGraph.getOverlayGraph());

		// code copied from the constructor.
		setDoubleBuffered( true );
		this.transform = new AffineTransform();
		this.addComponentListener(new VisualizationListener(this));
		this.renderer = r;
		pickedState = new MultiPickedState();

		if (layout instanceof PickEventListener)
			pickedState.addListener((PickEventListener) layout);
		r.setPickedKey(pickedState);
		this.layout = layout;
		//setPreferredSize(new Dimension(640, 600));
		//setSize(640, 600);
		Dimension d = getPreferredSize();
		Dimension ld = layout.getCurrentSize();
		
		// if the layout has NOT been intialized yet, initialize it
		// now to be the same size as the VisualizationViewer window
		if (ld == null) {
			System.out.println("Ont VV constructor: layout not init" );
			layout.initialize(d);
		}
		ld = layout.getCurrentSize();
		
		if (DEBUG)
		{
			System.out.println( " vv preferred size: w=" + d.width + " h=" + d.height);
			System.out.println( " layout current:    w=" + ld.width + " lh=" + d.height);		
			System.out.println( " after init" );
			System.out.println( " layout current:    w=" + ld.width + " lh=" + d.height);
		}
		
		// set my scale to show the entire layout
		setScale((float) d.width / ld.width, (float) d.height / ld.height,
				new Point2D.Float());
		this.suspended = true;
		this.manualSuspend = false;
		renderingHints.put(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		
		init();
		initMouseClicker();
	}

	private Rectangle getViewRectangle()
	{
		DirectedSparseGraph graph = myGraph.getVisualGraph();
		Set vertices = graph.getVertices();
		double xmin = Integer.MAX_VALUE;
		double xmax = Integer.MIN_VALUE;
		double ymin = Integer.MAX_VALUE;
		double ymax = Integer.MIN_VALUE;

		for (Iterator it = vertices.iterator(); it.hasNext();) {
			Vertex v = (Vertex) it.next();
			//System.out.println("v x,y= " + layout.getX(v) + " " + layout.getY(v));
			OntologyGraphNode ontNode = ((OntologyGraphNode) v.getUserDatum(OntologyWithClassHierarchyGraph.DATA));
			int r = ontNode.getRadius();
			//System.out.println( "radius = " + r);
			double x = layout.getX(v);
			double y = layout.getY(v);
			if ((x - r) < xmin)
				xmin = x - r;
			if ((x + r) > xmax)
				xmax = x + r;
			if ((y - r) < ymin)
				ymin = y - r;
			if ((y + r) > ymax)
				ymax = y + r;
		}

		Rectangle rect = new Rectangle( (int)xmin, (int)ymin, (int)(xmax - xmin), (int)(ymax - ymin));
		return rect;
	}
	
	/*
	 *  Called by OntologyWithClassHierarchyGraph at init time to zoom in / center at the  
	 *   graph so every vertex on the graph is in the view port.
	 * 
	 */
	public void autoPanZoom() 
	{		
		Rectangle rect = getViewRectangle();
		
		int xfocus = (int) ( (rect.width/2 + rect.x) );
		int yfocus = (int) ( (rect.height/2 + rect.y) );
		
		// getting the size of the screen space
		int screenWidth = this.getWidth();
		int screenHeight = this.getHeight();
		double hw = screenWidth / 2;
		double hh = screenHeight / 2;

		Point2D point = transform( new Point2D.Double( screenWidth/2, screenHeight/2) );
		Point2D focus = this.transformGraph2Screen( new Point2D.Double( xfocus, yfocus));

		if (DEBUG)
		{
			System.out.println( " screenWidth = " + screenWidth + " screenHeight = "+ screenHeight );
			System.out.println( " xmin = " + rect.x + " ymin = " + rect.y + " xmax " + ( rect.width + rect.x ) + " ymax " + (rect.height + rect.y ));
			System.out.println( " xfocus = " + xfocus + " yfocus = " + yfocus );
			System.out.println( " center of screen: x=" + (screenWidth/2) + " y=" + (screenHeight/2) );
			System.out.println( " graphspace of centerscreen: " + point.getX() + " " + point.getY() );
			System.out.println( " screensapce: xfocus = " + focus.getX() + " yfocus " + focus.getY() );
			System.out.println( " scaling = " + this.getScaleX()); 
		}
		
		DX = focus.getX();
		DY = focus.getY();
		DEBUGX = rect.x;
		DEBUGY = rect.y;
		DEBUGW = rect.width ;
		DEBUGH = rect.height;
		
		// compute for the necessary translation offsets to center
		double translateOffsetX = (point.getX() - xfocus);
		double translateOffsetY = (point.getY() - yfocus);
		//double translateOffsetX = 0;
		//double translateOffsetY = 0;
		
		// compute for the appropriate scaling factor for zoom in
		double min = Math.min(screenHeight, screenWidth);
		double graphMaxLength = Math.max(( rect.width), (rect.height));
		double scaleX = min / (graphMaxLength) / this.getScaleX();
		if (scaleX > 1)
			scaleX = 1;
		double scaleY = scaleX;
		
		// apply translation and zooming
		this.translate(translateOffsetX, translateOffsetY);
		this.scale(scaleX, scaleY);

		// set initial position of where the viewer is viewing
		this.currentX = xfocus;
		this.currentY = yfocus;
	}

	public void autoPanZoomTest() 
	{

		Rectangle rect = getViewRectangle();
		int xfocus = (int) ( (rect.width/2 + rect.x) );
		int yfocus = (int) ( (rect.height/2 + rect.y) );

		int screenWidth = this.getWidth();
		int screenHeight = this.getHeight();
		double hw = screenWidth / 2;
		double hh = screenHeight / 2;

		double translateOffsetX = (currentX - xfocus);
		double translateOffsetY = (currentY - yfocus);

		double min = Math.min(screenHeight, screenWidth);
		double graphMaxLength = Math.max(( rect.width ), ( rect.height ));
		double scaleX = min / (graphMaxLength) / this.getScaleX();
		if (scaleX > 1)
			scaleX = 1;
		double scaleY = scaleX;

		this.translate(translateOffsetX, translateOffsetY);
		this.scale(scaleX, scaleY);
	}

	/**
	 * Returns the time between iterations of the Relaxer thread. The Relaxer
	 * thread sleeps for a moment before calling the Layout to update again.
	 * This tells how long the current delay is. The default, 20 milliseconds,
	 * essentially causes the system to run the next iteration with virtually no
	 * pause.
	 * 
	 * @return Returns the relaxerThreadSleepTime.
	 */
	public long getRelaxerThreadSleepTime() {
		return relaxerThreadSleepTime;
	}

	/**
	 * Sets the relaxerThreadSleepTime.
	 * 
	 * @see #getRelaxerThreadSleepTime()
	 * @param relaxerThreadSleepTime
	 *            The relaxerThreadSleepTime to set.
	 */
	public void setRelaxerThreadSleepTime(long relaxerThreadSleepTime) {
		this.relaxerThreadSleepTime = relaxerThreadSleepTime;
	}

	/**
	 * Creates a default mouseClicker behavior: a default
	 * 
	 * @link{GraphMouseImpl}
	 * @deprecated replaced by setGraphMouse()
	 */
	protected void initMouseClicker() {
		// GraphMouseImpl will give original behavior
		setGraphMouse(new GraphMouseImpl(this));
	}

	/**
	 * a setter for the GraphMouse. This will remove any previous GraphMouse
	 * (including the one that is added in the initMouseClicker method.
	 * 
	 * @param graphMouse
	 *            new value
	 */
	public void setGraphMouse(GraphMouse graphMouse) {
		MouseListener[] ml = getMouseListeners();
		for (int i = 0; i < ml.length; i++) {
			if (ml[i] instanceof GraphMouse) {
				removeMouseListener(ml[i]);
			}
		}
		MouseMotionListener[] mml = getMouseMotionListeners();
		for (int i = 0; i < mml.length; i++) {
			if (mml[i] instanceof GraphMouse) {
				removeMouseMotionListener(mml[i]);
			}
		}
		MouseWheelListener[] mwl = getMouseWheelListeners();
		for (int i = 0; i < mwl.length; i++) {
			if (mwl[i] instanceof GraphMouse) {
				removeMouseWheelListener(mwl[i]);
			}
		}
		addMouseListener(graphMouse);
		addMouseMotionListener(graphMouse);
		addMouseWheelListener(graphMouse);
	}

	/**
	 * Sets the showing Renderer to be the input Renderer. Also tells the
	 * Renderer to refer to this visualizationviewer as a PickedKey. (Because
	 * Renderers maintain a small amount of state, such as the PickedKey, it is
	 * important to create a separate instance for each VV instance.)
	 * 
	 * @param v
	 */
	public void setRenderer(Renderer r) {
		this.renderer = r;
		r.setPickedKey(pickedState);
		repaint();
	}

	/**
	 * Returns the renderer used by this instance.
	 * 
	 * @return
	 */
	public Renderer getRenderer() {
		return renderer;
	}

	/**
	 * Removes the current graph layout, and adds a new one.
	 */
	public void setGraphLayout(Layout layout) {
		if (this.layout instanceof PickEventListener)
			pickedState.removeListener((PickEventListener) this.layout);
		suspend();
		Dimension d = getPreferredSize();
		Dimension ld = layout.getCurrentSize();
		// if the layout has NOT been initialized yet, initialize it
		// now to the size of the VisualizationViewer window
		if (ld == null) {
			layout.initialize(d);
		}
		ld = layout.getCurrentSize();
		// set scale to show the entire graph layout
		setScale((float) d.width / ld.width, (float) d.height / ld.height,
				new Point2D.Float());

		this.layout = layout;
		layout.restart();
		prerelax();
		unsuspend();
		if (layout instanceof PickEventListener)
			pickedState.addListener((PickEventListener) layout);
		this.pickSupport.setLayout(layout);
	}

	public void setGraph(OntologyWithClassHierarchyGraph graph) {
		myGraph = graph;
	}

	public OntologyWithClassHierarchyGraph getGraph() {
		return myGraph;
	}

	/**
	 * Returns the current graph layout.
	 */
	public Layout getGraphLayout() {
		return layout;
	}

	/**
	 * This is the interface for adding a mouse listener. The GEL will be called
	 * back with mouse clicks on vertices.
	 * 
	 * @param gel
	 */
	public void addGraphMouseListener(GraphMouseListener gel) {
		addMouseListener(new SwoopMouseListenerTranslator(gel, this));
	}

	/**
	 * starts a visRunner thread without prerelaxing
	 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?