/*
* #!
* Ontopia Vizigator
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* !#
*/
/*
* NOTE! ExtendedTGPanel is a version of TGPanel that supports using an image
* background in the VizPanel. This class contains Java 1.4 code for reading in
* and image, but this code has been commented out, since we go for being 1.3
* compatible. If this class should be used in the distribution, a 1.3 way must
* be found for reading in the image.
*
*
*
*
* TouchGraph LLC. Apache-Style Software License
*
*
* Copyright (c) 2001-2002 Alexander Shapiro. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* TouchGraph LLC (http://www.touchgraph.com/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "TouchGraph" or "TouchGraph LLC" must not be used to endorse
* or promote products derived from this software without prior written
* permission. For written permission, please contact
* alex@touchgraph.com
*
* 5. Products derived from this software may not be called "TouchGraph",
* nor may "TouchGraph" appear in their name, without prior written
* permission of alex@touchgraph.com.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
*/
package net.ontopia.topicmaps.viz;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.JFrame;
import net.ontopia.utils.OntopiaRuntimeException;
import com.touchgraph.graphlayout.Edge;
import com.touchgraph.graphlayout.GraphListener;
import com.touchgraph.graphlayout.LocalityUtils;
import com.touchgraph.graphlayout.Node;
import com.touchgraph.graphlayout.TGAbstractLens;
import com.touchgraph.graphlayout.TGException;
import com.touchgraph.graphlayout.TGLayout;
import com.touchgraph.graphlayout.TGLensSet;
import com.touchgraph.graphlayout.TGPaintListener;
import com.touchgraph.graphlayout.TGPanel;
import com.touchgraph.graphlayout.TGPoint2D;
import com.touchgraph.graphlayout.graphelements.GraphEltSet;
import com.touchgraph.graphlayout.graphelements.ImmutableGraphEltSet;
import com.touchgraph.graphlayout.graphelements.TGForEachEdge;
import com.touchgraph.graphlayout.graphelements.TGForEachNode;
import com.touchgraph.graphlayout.graphelements.VisibleLocality;
import com.touchgraph.graphlayout.interaction.GLEditUI;
import com.touchgraph.graphlayout.interaction.TGAbstractClickUI;
/**
* TGPanel contains code for drawing the graph, and storing which nodes are
* selected, and which ones the mouse is over.
*
* It houses methods to activate TGLayout, which performs dynamic layout.
* Whenever the graph is moved, or repainted, TGPanel fires listner methods on
* associated objects.
*
* <p>
* <b> Parts of this code build upon Sun's Graph Layout example.
* http://java.sun.com/applets/jdk/1.1/demo/GraphLayout/Graph.java </b>
* </p>
*
* @author Alexander Shapiro
* @author Murray Altheim (2001-11-06; 2002-01-14 cleanup)
*/
public class ExtendedTGPanel extends TGPanel {
// static variables for use within the package
public static Color BACK_COLOR = Color.white;
// ....
private GraphEltSet completeEltSet;
private VisibleLocality visibleLocality;
private LocalityUtils localityUtils;
protected BasicMouseMotionListener basicMML;
protected Edge mouseOverE; // mouseOverE is the edge the mouse is over
protected Node mouseOverN; // mouseOverN is the node the mouse is over
// If true, then don't change mouseOverN or mouseOverE
protected boolean maintainMouseOver = false;
protected Node select;
Node dragNode; // Node currently being dragged
protected Point mousePos; // Mouse location, updated in the
// mouseMotionListener
Image offscreen;
Dimension offscreensize;
Graphics offgraphics;
private Vector graphListeners;
private Vector paintListeners;
// Converts between a nodes visual position (drawx, drawy), and its absolute
// position (x,y).
TGLensSet tgLensSet;
TGPanel.AdjustOriginLens adjustOriginLens;
TGPanel.SwitchSelectUI switchSelectUI;
public Image image;
// ............
/**
* Default constructor.
*/
public ExtendedTGPanel(String imageSource) {
super();
this.image = getImage(imageSource);
setLayout(null);
setGraphEltSet(new GraphEltSet());
addMouseListener(new BasicMouseListener());
basicMML = new BasicMouseMotionListener();
addMouseMotionListener(basicMML);
graphListeners = new Vector();
paintListeners = new Vector();
adjustOriginLens = super.getAdjustOriginLens();
switchSelectUI = super.getSwitchSelectUI();
TGLayout tgLayout = new TGLayout(this);
setTGLayout(tgLayout);
tgLayout.start();
setGraphEltSet(new GraphEltSet());
}
public void setLensSet(TGLensSet lensSet) {
tgLensSet = lensSet;
}
public void setTGLayout(TGLayout tgl) {
tgLayout = tgl;
}
public void setGraphEltSet(GraphEltSet ges) {
completeEltSet = ges;
visibleLocality = new VisibleLocality(completeEltSet);
localityUtils = new LocalityUtils(visibleLocality, this);
}
public TGPanel.AdjustOriginLens getAdjustOriginLens() {
return adjustOriginLens;
}
public TGPanel.SwitchSelectUI getSwitchSelectUI() {
return switchSelectUI;
}
// color and font setters ......................
public void setBackColor(Color color) {
BACK_COLOR = color;
}
// Node manipulation ...........................
/**
* Returns an Iterator over all nodes in the complete graph.
*/
public Iterator getAllNodes() {
return completeEltSet.getNodes();
}
/**
* Return the current visible locality.
*/
public ImmutableGraphEltSet getGES() {
return visibleLocality;
}
/**
* Returns the current node count.
*/
public int getNodeCount() {
return completeEltSet.nodeCount();
}
/**
* Returns the current node count within the VisibleLocality.
* @deprecated this method has been replaced by the
* <tt>visibleNodeCount()</tt> method.
*/
public int nodeNum() {
return visibleLocality.nodeCount();
}
/**
* Returns the current node count within the VisibleLocality.
*/
public int visibleNodeCount() {
return visibleLocality.nodeCount();
}
/**
* Return the Node whose ID matches the String <tt>id</tt>, null if no
* match is found.
*
* @param id
* The ID identifier used as a query.
* @return The Node whose ID matches the provided 'id', null if no match is
* found.
*/
public Node findNode(String id) {
if (id == null)
return null; // ignore
return completeEltSet.findNode(id);
}
/**
* Return a Collection of all Nodes whose label matches the String
* <tt>label</tt>, null if no match is found.
*/
public Collection findNodesByLabel(String label) {
if (label == null)
return null; // ignore
return completeEltSet.findNodesByLabel(label);
}
/**
* Return the first Nodes whose label contains the String <tt>substring</tt>,
* null if no match is found.
* @param substring
* The Substring used as a query.
*/
public Node findNodeLabelContaining(String substring) {
if (substring == null)
return null; // ignore
return completeEltSet.findNodeLabelContaining(substring);
}
/**
* Adds a Node, with its ID and label being the current node count plus 1.
* @see com.touchgraph.graphlayout.Node
*/
public Node addNode() throws TGException {
String id = String.valueOf(getNodeCount() + 1);
return addNode(id, null);
}
/**
* Adds a Node, provided its label. The node is assigned a unique ID.
* @see com.touchgraph.graphlayout.graphelements.GraphEltSet
*/
public Node addNode(String label) throws TGException {
return addNode(null, label);
}
/**
* Adds a Node, provided its ID and label.
* @see com.touchgraph.graphlayout.Node
*/
public Node addNode(String id, String label) throws TGException {
Node node;
if (label == null)
node = new Node(id);
else
node = new Node(id, label);
// The addNode() call should probably take a position, this just sets it
// at 0,0
updateDrawPos(node);
addNode(node);
return node;
}
/**
* Add the Node <tt>node</tt> to the visibleLocality, checking for ID
* uniqueness.
*/
public void addNode(final Node node) throws TGException {
synchronized (localityUtils) {
visibleLocality.addNode(node);
resetDamper();
}
}
/**
* Remove the Node object matching the ID <code>id</code>, returning true
* if the deletion occurred, false if a Node matching the ID does not exist
* (or if the ID value was null).
* @param id The ID identifier used as a query.
* @return true if the deletion occurred.
*/
public boolean deleteNodeById(String id) {
if (id == null)
return false; // ignore
Node node = findNode(id);
if (node == null)
return false;
else
return deleteNode(node);
}
public boolean deleteNode(Node node) {
synchronized (localityUtils) {
if (visibleLocality.deleteNode(node)) {
// delete from visibleLocality, *AND completeEltSet
if (node == select)
clearSelect();
resetDamper();
return true;
}
return false;
}
}
public void clearAll() {
synchronized (localityUtils) {
visibleLocality.clearAll();
}
}
public Node getSelect() {
return select;
}
public Node getMouseOverN() {
return mouseOverN;
}
public synchronized void setMouseOverN(Node node) {
if (dragNode != null || maintainMouseOver)
return; // So you don't accidentally switch nodes while dragging
if (mouseOverN != node) {
mouseOverN = node;
}
}
// Edge manipulation ...........................
/** Returns an Iterator over all edges in the complete graph. */
public Iterator getAllEdges() {
return completeEltSet.getEdges();
}
public void deleteEdge(Edge edge) {
synchronized (localityUtils) {
visibleLocality.deleteEdge(edge);
resetDamper();
}
}
public void deleteEdge(Node from, Node to) {
synchronized (localityUtils) {
visibleLocality.deleteEdge(from, to);
}
}
/**
* Returns the current edge count in the complete graph.
*/
public int getEdgeCount() {
return completeEltSet.edgeCount();
}
/**
* Return the number of Edges in the Locality.
*
* @deprecated this method has been replaced by the
* <tt>visibleEdgeCount()</tt> method.
*/
public int edgeNum() {
return visibleLocality.edgeCount();
}
/**
* Return the number of Edges in the Locality.
*/
public int visibleEdgeCount() {
return visibleLocality.edgeCount();
}
public Edge findEdge(Node f, Node t) {
return visibleLocality.findEdge(f, t);
}
public void addEdge(Edge e) {
synchronized (localityUtils) {
visibleLocality.addEdge(e);
resetDamper();
}
}
public Edge addEdge(Node f, Node t, int tens) {
synchronized (localityUtils) {
return visibleLocality.addEdge(f, t, tens);
}
}
public Edge getMouseOverE() {
return mouseOverE;
}
public synchronized void setMouseOverE(Edge edge) {
if (dragNode != null || maintainMouseOver)
return; // No funny business while dragging
if (mouseOverE != edge) {
mouseOverE = edge;
}
}
// miscellany ..................................
protected class AdjustOriginLens extends TGAbstractLens {
protected void applyLens(TGPoint2D p) {
p.x = p.x + ExtendedTGPanel.this.getSize().width / 2;
p.y = p.y + ExtendedTGPanel.this.getSize().height / 2;
}
protected void undoLens(TGPoint2D p) {
p.x = p.x - ExtendedTGPanel.this.getSize().width / 2;
p.y = p.y - ExtendedTGPanel.this.getSize().height / 2;
}
}
public class SwitchSelectUI extends TGAbstractClickUI {
public void mouseClicked(MouseEvent e) {
if (mouseOverN != null) {
if (mouseOverN != select)
setSelect(mouseOverN);
else
clearSelect();
}
}
}
void fireMovedEvent() {
Vector listeners;
// The following condition was added because the synchronized line below
// would sometimes cause a NullPointerException stack trace to be printed
// in the console.
if (graphListeners != null) {
synchronized (this) {
listeners = (Vector) graphListeners.clone();
}
for (int i = 0; i < listeners.size(); i++) {
GraphListener gl = (GraphListener) listeners.elementAt(i);
gl.graphMoved();
}
}
}
public void fireResetEvent() {
Vector listeners;
synchronized (this) {
listeners = (Vector) graphListeners.clone();
}
for (int i = 0; i < listeners.size(); i++) {
GraphListener gl = (GraphListener) listeners.elementAt(i);
gl.graphReset();
}
}
public synchronized void addGraphListener(GraphListener gl) {
graphListeners.addElement(gl);
}
public synchronized void removeGraphListener(GraphListener gl) {
graphListeners.removeElement(gl);
}
public synchronized void addPaintListener(TGPaintListener pl) {
paintListeners.addElement(pl);
}
public synchronized void removePaintListener(TGPaintListener pl) {
paintListeners.removeElement(pl);
}
private void redraw() {
resetDamper();
}
public void setMaintainMouseOver(boolean maintain) {
maintainMouseOver = maintain;
}
public void clearSelect() {
if (select != null) {
select = null;
repaint();
}
}
/**
* A convenience method that selects the first node of a graph, so that hiding
* works.
*/
public void selectFirstNode() {
setSelect(getGES().getFirstNode());
}
public void setSelect(Node node) {
if (node != null) {
select = node;
repaint();
} else if (node == null)
clearSelect();
}
public void multiSelect(TGPoint2D from, TGPoint2D to) {
final double minX, minY, maxX, maxY;
if (from.x > to.x) {
maxX = from.x;
minX = to.x;
} else {
minX = from.x;
maxX = to.x;
}
if (from.y > to.y) {
maxY = from.y;
minY = to.y;
} else {
minY = from.y;
maxY = to.y;
}
final Vector selectedNodes = new Vector();
TGForEachNode fen = new TGForEachNode() {
public void forEachNode(Node node) {
double x = node.drawx;
double y = node.drawy;
if (x > minX && x < maxX && y > minY && y < maxY) {
selectedNodes.addElement(node);
}
}
};
visibleLocality.forAllNodes(fen);
if (selectedNodes.size() > 0) {
int r = (int) (Math.random() * selectedNodes.size());
setSelect((Node) selectedNodes.elementAt(r));
} else {
clearSelect();
}
}
public void updateLocalityFromVisibility() throws TGException {
visibleLocality.updateLocalityFromVisibility();
}
public void setLocale(Node node, int radius, int maxAddEdgeCount,
int maxExpandEdgeCount, boolean unidirectional) throws TGException {
localityUtils.setLocale(node, radius, maxAddEdgeCount, maxExpandEdgeCount,
unidirectional);
}
public void fastFinishAnimation() {
// Quickly wraps up the add node animation
localityUtils.fastFinishAnimation();
}
public void setLocale(Node node, int radius) throws TGException {
localityUtils.setLocale(node, radius);
}
public void expandNode(Node node) {
localityUtils.expandNode(node);
}
public void hideNode(Node hideNode) {
localityUtils.hideNode(hideNode);
}
public void collapseNode(Node collapseNode) {
localityUtils.collapseNode(collapseNode);
}
public void hideEdge(Edge hideEdge) {
visibleLocality.removeEdge(hideEdge);
if (mouseOverE == hideEdge)
setMouseOverE(null);
resetDamper();
}
public void setDragNode(Node node) {
dragNode = node;
super.setDragNode(node);
}
public Node getDragNode() {
return dragNode;
}
void setMousePos(Point p) {
mousePos = p;
}
public Point getMousePos() {
return mousePos;
}
/** Start and stop the damper. Should be placed in the TGPanel too. */
public void startDamper() {
if (tgLayout != null)
tgLayout.startDamper();
}
public void stopDamper() {
if (tgLayout != null)
tgLayout.stopDamper();
}
/** Makes the graph mobile, and slowly slows it down. */
public void resetDamper() {
if (tgLayout != null)
tgLayout.resetDamper();
}
/** Gently stops the graph from moving */
public void stopMotion() {
if (tgLayout != null)
tgLayout.stopMotion();
}
class BasicMouseListener extends MouseAdapter {
public void mouseEntered(MouseEvent e) {
addMouseMotionListener(basicMML);
}
public void mouseExited(MouseEvent e) {
removeMouseMotionListener(basicMML);
mousePos = null;
setMouseOverN(null);
setMouseOverE(null);
repaint();
}
}
class BasicMouseMotionListener implements MouseMotionListener {
public void mouseDragged(MouseEvent e) {
mousePos = e.getPoint();
findMouseOver();
try {
// An attempt to make the cursor flicker less
Thread.currentThread().sleep(6);
} catch (InterruptedException ex) {
}
}
public void mouseMoved(MouseEvent e) {
mousePos = e.getPoint();
synchronized (this) {
Edge oldMouseOverE = mouseOverE;
Node oldMouseOverN = mouseOverN;
findMouseOver();
if (oldMouseOverE != mouseOverE || oldMouseOverN != mouseOverN) {
repaint();
}
}
}
}
protected synchronized void findMouseOver() {
if (mousePos == null) {
setMouseOverN(null);
setMouseOverE(null);
return;
}
final int mpx = mousePos.x;
final int mpy = mousePos.y;
final Node[] monA = new Node[1];
final Edge[] moeA = new Edge[1];
TGForEachNode fen = new TGForEachNode() {
double minoverdist = 100; // Kind of a hack (see second if statement)
// Nodes can be as wide as 200 (=2*100)
public void forEachNode(Node node) {
double x = node.drawx;
double y = node.drawy;
double dist = Math.sqrt((mpx - x) * (mpx - x) + (mpy - y) * (mpy - y));
if ((dist < minoverdist) && node.containsPoint(mpx, mpy)) {
minoverdist = dist;
monA[0] = node;
}
}
};
visibleLocality.forAllNodes(fen);
TGForEachEdge fee = new TGForEachEdge() {
double minDist = 8; // Tangential distance to the edge
double minFromDist = 1000; // Distance to the edge's "from" node
public void forEachEdge(Edge edge) {
double x = edge.from.drawx;
double y = edge.from.drawy;
double dist = edge.distFromPoint(mpx, mpy);
if (dist < minDist) {
// Set the over edge to the edge with the minimun tangential
// distance
minDist = dist;
minFromDist = Math
.sqrt((mpx - x) * (mpx - x) + (mpy - y) * (mpy - y));
moeA[0] = edge;
} else if (dist == minDist) {
// If tangential distances are identical, chose
// the edge whose "from" node is closest.
double fromDist = Math.sqrt((mpx - x) * (mpx - x) + (mpy - y)
* (mpy - y));
if (fromDist < minFromDist) {
minFromDist = fromDist;
moeA[0] = edge;
}
}
}
};
visibleLocality.forAllEdges(fee);
setMouseOverN(monA[0]);
if (monA[0] == null)
setMouseOverE(moeA[0]);
else
setMouseOverE(null);
}
TGPoint2D topLeftDraw = null;
TGPoint2D bottomRightDraw = null;
public TGPoint2D getTopLeftDraw() {
return new TGPoint2D(topLeftDraw);
}
public TGPoint2D getBottomRightDraw() {
return new TGPoint2D(bottomRightDraw);
}
public TGPoint2D getCenter() {
return tgLensSet.convDrawToReal(getSize().width / 2, getSize().height / 2);
}
public TGPoint2D getDrawCenter() {
return new TGPoint2D(getSize().width / 2, getSize().height / 2);
}
public void updateGraphSize() {
if (topLeftDraw == null)
topLeftDraw = new TGPoint2D(0, 0);
if (bottomRightDraw == null)
bottomRightDraw = new TGPoint2D(0, 0);
TGForEachNode fen = new TGForEachNode() {
boolean firstNode = true;
public void forEachNode(Node node) {
if (firstNode) { // initialize topRight + bottomLeft
topLeftDraw.setLocation(node.drawx, node.drawy);
bottomRightDraw.setLocation(node.drawx, node.drawy);
firstNode = false;
} else { // Standard max and min finding
topLeftDraw.setLocation(Math.min(node.drawx, topLeftDraw.x), Math
.min(node.drawy, topLeftDraw.y));
bottomRightDraw.setLocation(Math.max(node.drawx, bottomRightDraw.x),
Math.max(node.drawy, bottomRightDraw.y));
}
}
};
visibleLocality.forAllNodes(fen);
}
public synchronized void processGraphMove() {
updateDrawPositions();
updateGraphSize();
}
public synchronized void repaintAfterMove() {
// Called by TGLayout + others to indicate that graph has moved
processGraphMove();
findMouseOver();
fireMovedEvent();
repaint();
}
public void updateDrawPos(Node node) {
// sets the visual position from the real position
TGPoint2D p = tgLensSet.convRealToDraw(node.x, node.y);
node.drawx = p.x;
node.drawy = p.y;
}
public void updatePosFromDraw(Node node) {
// sets the real position from the visual position
TGPoint2D p = tgLensSet.convDrawToReal(node.drawx, node.drawy);
node.x = p.x;
node.y = p.y;
}
public void updateDrawPositions() {
TGForEachNode fen = new TGForEachNode() {
public void forEachNode(Node node) {
updateDrawPos(node);
}
};
visibleLocality.forAllNodes(fen);
}
Color myBrighter(Color c) {
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
r = Math.min(r + 96, 255);
g = Math.min(g + 96, 255);
b = Math.min(b + 96, 255);
return new Color(r, g, b);
}
public synchronized void paint(Graphics g) {
update(g);
}
public Image getImage(String imageSource) {
try {
URL sourceURL = new URL(imageSource);
if (sourceURL.getProtocol().equals("file") &&
!(new File(sourceURL.getPath())).exists()) {
ErrorDialog.showError(this, "File not found: " + imageSource);
return null;
}
Image other = Toolkit.getDefaultToolkit().createImage(sourceURL);
MediaTracker tracker = new MediaTracker(this);
int imageId = 0;
tracker.addImage(other, imageId);
tracker.waitForID(0);
boolean isError = tracker.isErrorID(imageId);
if (isError) {
ErrorDialog.showError(this,
"There were problems reading the background image: " +
imageSource);
return null;
}
return other;
} catch (IOException e) {
throw new OntopiaRuntimeException(e);
} catch (InterruptedException ie) {
throw new OntopiaRuntimeException("InterruptedException caused during" +
" wallpaper_image error check.", ie);
}
}
public synchronized void update(Graphics g) {
Dimension d = getSize();
if ((offscreen == null) || (d.width != offscreensize.width)
|| (d.height != offscreensize.height)) {
offscreen = createImage(d.width, d.height);
offscreensize = d;
offgraphics = offscreen.getGraphics();
processGraphMove();
findMouseOver();
fireMovedEvent();
}
offgraphics.setColor(BACK_COLOR);
offgraphics.fillRect(0, 0, d.width, d.height);
offgraphics.drawImage(image, 0, 0, null);
synchronized (this) {
paintListeners = (Vector) paintListeners.clone();
}
for (int i = 0; i < paintListeners.size(); i++) {
TGPaintListener pl = (TGPaintListener) paintListeners.elementAt(i);
pl.paintFirst(offgraphics);
}
TGForEachEdge fee = new TGForEachEdge() {
public void forEachEdge(Edge edge) {
edge.paint(offgraphics, ExtendedTGPanel.this);
}
};
visibleLocality.forAllEdges(fee);
for (int i = 0; i < paintListeners.size(); i++) {
TGPaintListener pl = (TGPaintListener) paintListeners.elementAt(i);
pl.paintAfterEdges(offgraphics);
}
TGForEachNode fen = new TGForEachNode() {
public void forEachNode(Node node) {
node.paint(offgraphics, ExtendedTGPanel.this);
}
};
visibleLocality.forAllNodes(fen);
if (mouseOverE != null) {
// Make the edge the mouse is over appear on top.
mouseOverE.paint(offgraphics, this);
mouseOverE.from.paint(offgraphics, this);
mouseOverE.to.paint(offgraphics, this);
}
if (select != null) { // Make the selected node appear on top.
select.paint(offgraphics, this);
}
if (mouseOverN != null) {
// Make the node the mouse is over appear on top.
mouseOverN.paint(offgraphics, this);
}
for (int i = 0; i < paintListeners.size(); i++) {
TGPaintListener pl = (TGPaintListener) paintListeners.elementAt(i);
pl.paintLast(offgraphics);
}
// Paint any components that have been added to this panel
paintComponents(offgraphics);
g.drawImage(offscreen, 0, 0, null);
}
public static void main(String[] args) {
JFrame frame;
frame = new JFrame("TGPanel");
TGPanel tgPanel = new TGPanel();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
TGLensSet tgls = new TGLensSet();
tgls.addLens(tgPanel.getAdjustOriginLens());
tgPanel.setLensSet(tgls);
try {
tgPanel.addNode(); // Add a starting node.
} catch (TGException tge) {
System.err.println(tge.getMessage());
}
tgPanel.setVisible(true);
new GLEditUI(tgPanel).activate();
frame.getContentPane().add("Center", tgPanel);
frame.setSize(500, 500);
frame.setVisible(true);
}
} // end com.touchgraph.graphlayout.TGPanel