package thaw.plugins.webOfTrust; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.Point2D; import java.util.Hashtable; import java.util.Iterator; import javax.swing.JComponent; import javax.swing.JScrollPane; import thaw.plugins.Hsqldb; import thaw.plugins.signatures.Identity; public class WebOfTrustGraph extends JComponent implements MouseListener { public final static int BORDER = 40; private static final long serialVersionUID = 7654372155349615901L; private JScrollPane myScrollPane; private boolean visible; private Hashtable nodes; private WotGraphNode center; private WotGraphNode selectedNode; private float zoom = 1; private int minX = 0; private int maxX = 1; private int minY = 0; private int maxY = 1; private int zeroX = 200; private int zeroY = 200; public WebOfTrustGraph(Hsqldb db) { nodes = new Hashtable(); visible = false; addMouseListener(this); } public void setScrollPane(JScrollPane pane) { this.myScrollPane = pane; } public void redraw(Identity c) { this.center = new WotGraphNode(this, new WotIdentity(c)); if (!visible) return; nodes = new Hashtable(); this.center.setPosition(0, 0); this.center.generateNeighbours(); this.center.optimizePositions(); addNode(this.center); if (myScrollPane != null) myScrollPane.revalidate(); computeMinMax(); computeOptimalZoom(); recomputeSize(); repaint(); } private void computeMinMax() { minX = 0; minY = 0; maxX = 1; maxY = 1; synchronized(nodes) { for (Iterator it = nodes.values().iterator() ; it.hasNext() ; ) { WotGraphNode n = (WotGraphNode)it.next(); if (n.getX() < minX) minX = n.getX(); if (n.getX() > maxX) maxX = n.getX(); if (n.getY() < minY) minY = n.getY(); if (n.getY() > maxY) maxY = n.getY(); } } } private void recomputeSize() { Dimension dim = new Dimension((int)((maxX - minX) * zoom) + (2*BORDER), (int)((maxY - minY) * zoom) + (2*BORDER)); this.setPreferredSize(dim); this.setSize((int)((maxX - minX) * zoom) + (2*BORDER), (int)((maxY - minY) * zoom) + (2*BORDER)); myScrollPane.revalidate(); } public void computeOptimalZoom() { Dimension size = myScrollPane.getSize(); double zoomX = (size.getWidth()-(2*BORDER)) / (maxX - minX); double zoomY = (size.getHeight()-(2*BORDER)) / (maxY - minY); zoom = (float)(((zoomX > zoomY) ? zoomY : zoomX)); if (zoom == 0) zoom = 1; recomputeZero(); } private void recomputeZero() { zeroX = (-1 * (int)(minX * zoom)) + BORDER; zeroY = (-1 * (int)(minY * zoom)) + BORDER; } public float getZoom() { return zoom; } public void setZoom(float z) { this.zoom = z; recomputeSize(); recomputeZero(); repaint(); } public WotGraphNode getNode(String publicKey) { synchronized(nodes) { return (WotGraphNode)nodes.get(publicKey); } } public WotGraphNode getNearestNode(int x, int y) { WotGraphNode selected = null; float lastDist = 999999999; synchronized(nodes) { for (Iterator it = nodes.values().iterator() ; it.hasNext() ; ) { WotGraphNode n = (WotGraphNode)it.next(); float dist = (float)new Point2D.Float(n.getX(), n.getY()).distance(x, y); if (dist < lastDist) { selected = n; lastDist = dist; } } } return selected; } public void addNode(WotGraphNode node) { synchronized(nodes) { nodes.put(node.getIdentity().getPublicKey(), node); } } public void paintComponent(Graphics g) { /* background */ Dimension d = getSize(); g.setColor(java.awt.Color.WHITE); g.fillRect(0, 0, (int)d.getWidth(), (int)d.getHeight()); synchronized(nodes) { for (Iterator it = nodes.values().iterator() ; it.hasNext() ; ) { ((WotGraphNode)it.next()).paintLinks(g, zoom, zeroX, zeroY); } for (Iterator it = nodes.values().iterator() ; it.hasNext() ; ) { ((WotGraphNode)it.next()).paintNode(g, zoom, zeroX, zeroY); } } } public void mouseClicked(MouseEvent e) { int x = (int)((e.getX() - zeroX) / zoom); int y = (int)((e.getY() - zeroY) / zoom); WotGraphNode node = getNearestNode(x, y); synchronized(nodes) { for (Iterator it = nodes.values().iterator() ; it.hasNext() ; ) { WotGraphNode n = (WotGraphNode)it.next(); n.setSelected(n == node); } } selectedNode = node; repaint(); } public void mouseEntered(MouseEvent arg0) { } public void mouseExited(MouseEvent arg0) { } public void mousePressed(MouseEvent arg0) { mouseClicked(arg0); } public void mouseReleased(MouseEvent e) { int x = (int)((e.getX() - zeroX) / zoom); int y = (int)((e.getY() - zeroY) / zoom); selectedNode.setPosition(x, y); repaint(); } public void setVisible(boolean v) { visible = v; if (v && center != null) { myScrollPane.revalidate(); redraw(center.getIdentity()); } } }