import java.util.*; import java.awt.*; import java.applet.*; import java.net.*; public class GraphPanel extends ScrollingPanel implements Runnable { protected Blackboard _bb; public GraphPanel(Blackboard black) { super( (int)black.lx(), (int)black.ly(), (int)black.ux(), (int)black.uy() ); _bb = black; } // Thread stuff // protected boolean _painted = true; protected synchronized void setPainted() { _painted = true; notifyAll(); } protected synchronized void waitPainted() { while (!_painted) try { wait(); } catch (InterruptedException e) { } _painted = false; } protected Thread _updater; public void run() { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); while (true) { waitPainted(); if( _bb.catchEmbedderChange() ) super.focusScrollbars(); _bb.embedder().Embed(); repaint(); setPainted(); try { Thread.sleep(100); } catch (InterruptedException e) { break; } } } public void start() { _updater = new Thread(this); _updater.start(); } public void stop() { if( _updater != null ) _updater.stop(); _updater = null; } // the drawing routine // protected Node _pick; // Picked node protected boolean _pickfixed = false; // Is the picked node fixed? protected boolean _extending = false; // Extending edges of the picked node? protected Image _offscreen; protected Dimension _offscreensize; protected Graphics _offgraphics; protected final void sortByZ( Vector nodes ) { // Do insertionsort on the Z depth of the nodes int len = nodes.size(); for( int P = 1; P < len; ++P ) { Node tmp = (Node) nodes.elementAt( P ); double Z = tmp.Z(); int j; for( j = P; j > 0; --j ) { Node tmp2 = (Node) nodes.elementAt( j-1 ); if( Z >= tmp2.Z() ) break; nodes.setElementAt( tmp2, j ); } nodes.setElementAt( tmp, j ); } } public void update(Graphics g) { Dimension d = size(); adjustScrollbars( d.width, d.height ); if ((_offscreen == null) || (d.width != _offscreensize.width) || (d.height != _offscreensize.height)) { _offscreen = createImage(d.width, d.height); _offscreensize = d; _offgraphics = _offscreen.getGraphics(); _offgraphics.setFont(getFont()); } _offgraphics.setColor(getBackground()); _offgraphics.clipRect(0, 0, d.width, d.height); _offgraphics.fillRect(0, 0, d.width, d.height); _offgraphics.translate( -_sbh.getValue(), -_sbv.getValue() ); Vector edges = _bb.edges(); int edgecnt = edges.size(); for( int i = 0; i < edgecnt; ++i ) { Edge e = (Edge) edges.elementAt(i); Node to = e.to(); Node from = e.from(); if( to != from && to.showing() && from.showing() ) e.paint( _offgraphics ); } Vector nodes = _bb.nodes(); sortByZ( nodes ); int nodecnt = nodes.size(); for( int i = 0; i < nodecnt; ++i ) { Node n = (Node) nodes.elementAt(i); if( n.showing() ) n.paint( _offgraphics ); } g.drawImage( _offscreen, 0, 0, null ); _offgraphics.translate( _sbh.getValue(), _sbv.getValue() ); } // The event handler // public synchronized boolean mouseDown(Event evt, int x, int y) { x = x + _sbh.getValue(); y = y + _sbv.getValue(); int bestdist = Integer.MAX_VALUE; Vector nodes = _bb.nodes(); int nodecnt = nodes.size(); for( int i = 0; i < nodecnt; ++i ) { Node n = (Node) nodes.elementAt(i); int dx = n.X()-x; int dy = n.Y()-y; int dist = dx*dx + dy*dy; if (dist < bestdist) { _pick = n; bestdist = dist; } } _pick.pick( true ); _pickfixed = _pick.fixed(); _pick.XY( x, y ); if( evt.clickCount > 1 ) { boolean shift_on = ((evt.modifiers & Event.SHIFT_MASK) != 0); if (shift_on) { _pickfixed = !_pickfixed; _bb.group( _pick ); } else _bb.localize( _pick ); } else { boolean shift_on = ((evt.modifiers & Event.SHIFT_MASK) != 0); if (shift_on) { // Toggle the fix of the picked node _pickfixed = !_pickfixed; } boolean ctrl_on = ((evt.modifiers & Event.CTRL_MASK) != 0); if (ctrl_on) { // Now extending the picked node _extending = true; } boolean alt_on = ((evt.modifiers & Event.ALT_MASK) != 0); if( alt_on ) { // Now trying to open the URL of the picked node try { URL doc = _bb.applet().getDocumentBase(); AppletContext page = _bb.applet().getAppletContext(); page.showDocument( new URL(doc, _bb.globals.basedir() + _pick.label()) ); } catch( MalformedURLException mal ) { _bb.applet().showStatus("Couldn't display " + _pick.label()); } } } waitPainted(); repaint(); setPainted(); return true; } public synchronized boolean mouseDrag(Event evt, int x, int y) { x = x + _sbh.getValue(); y = y + _sbv.getValue(); _pick.XY( x, y ); waitPainted(); repaint(); setPainted(); return true; } public synchronized boolean mouseUp(Event evt, int x, int y) { x = x + _sbh.getValue(); y = y + _sbv.getValue(); _pick.XY( x, y ); _pick.fix( _pickfixed ); _pick.pick( false ); if( _extending ) { for (Enumeration i = _pick.edges() ; i.hasMoreElements() ;) { Edge e = (Edge) i.nextElement(); e.updateLength(); } } _extending = false; _pick = null; waitPainted(); repaint(); setPainted(); return true; } private final int margin = 200; protected void addBoundingBoxPoint( int x, int y) { if( x > _maxx ) _maxx = x; else if( x < _minx ) _minx = x; if( y > _maxy ) _maxy = y; else if( y < _miny ) _miny = y; } protected void adjustScrollbars(int width, int height) { int oldminx = _minx; int oldmaxx = _maxx; int oldminy = _miny; int oldmaxy = _maxy; _minx = _maxx = _miny = _maxy = 0; Vector nodes = _bb.nodes(); int nodecnt = nodes.size(); for( int i = 0; i < nodecnt; ++i ) { Node n = (Node) nodes.elementAt(i); addBoundingBoxPoint( n.X(), n.Y() ); } _iminx = _minx; _iminy = _miny; int newwidth = _maxx-_minx; int newheight = _maxy-_miny; _minx -= newwidth; _maxx += newwidth; _miny -= newheight; _maxy += newheight; if( _minx-margin > oldminx ) _minx = oldminx+margin; else _minx = (_minxoldmaxx)?_maxx:oldmaxx; // Max if( _miny-margin > oldminy ) _miny = oldminy+margin; else _minx = (_minyoldmaxy)?_maxy:oldmaxy; // Max super.adjustScrollbars( width, height ); } } // class GraphPanel