Source Code Cross Referenced for GraphLayout.java in  » Web-Crawler » WebSPHINX » websphinx » workbench » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Crawler » WebSPHINX » websphinx.workbench 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * WebSphinx web-crawling toolkit
0003:         *
0004:         * Copyright (c) 1998-2002 Carnegie Mellon University.  All rights
0005:         * reserved.
0006:         *
0007:         * Redistribution and use in source and binary forms, with or without
0008:         * modification, are permitted provided that the following conditions
0009:         * are met:
0010:         *
0011:         * 1. Redistributions of source code must retain the above copyright
0012:         *    notice, this list of conditions and the following disclaimer.
0013:         *
0014:         * 2. Redistributions in binary form must reproduce the above copyright
0015:         *    notice, this list of conditions and the following disclaimer in
0016:         *    the documentation and/or other materials provided with the
0017:         *    distribution.
0018:         *
0019:         * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
0020:         * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0021:         * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0022:         * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
0023:         * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0024:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0025:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0026:         * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0027:         * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0028:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0029:         * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0030:         *
0031:         */
0032:
0033:        package websphinx.workbench;
0034:
0035:        // Daniel Tunkelang's graph-drawing packages
0036:        import graph.*;
0037:        import gd.*;
0038:
0039:        import rcm.awt.*;
0040:
0041:        import java.util.*;
0042:        import java.awt.*;
0043:        import java.awt.image.ImageObserver;
0044:
0045:        public class GraphLayout extends Canvas implements  Runnable,
0046:                ImageObserver {
0047:
0048:            Graph graph; // graph to display
0049:
0050:            double restLength = 50; // default rest length of an edge
0051:            double springConstant = 100; // attraction between connected nodes
0052:            double nodeCharge = 10000; // repulsion between any pair of nodes
0053:
0054:            GDAlgorithm algorithm; // algorithm used for automatic graph layout
0055:
0056:            boolean running = false; // is repaint thread running?
0057:            boolean automaticLayout = true; // is automatic graph layout enabled?
0058:            double threshold = 100; // if an iteration shows less "improvement" than
0059:            // this threshold, stop iterating
0060:            boolean quiescent = true; // is the graph stable?
0061:            boolean dirty = true; // do we need to repaint?
0062:
0063:            int interval = 100; // milliseconds between repaints
0064:            int iterations = 3; // number of layout iterations per repaint
0065:
0066:            Color nodeColor = Color.pink; // default background color for a node
0067:            // (node label text is in Foreground color)
0068:            Color edgeColor = Color.black; // default color of an edge line 
0069:            Color tipColor = Color.yellow; // background color of a popup tip
0070:
0071:            //RenderedNode selectedNode = null;   // currently selected node, or null
0072:            //RenderedEdge selectedEdge = null;   // currently selected edge, or null
0073:            // invariant: selectedNode==null || selectedEdge == null
0074:
0075:            Object tipObject = null; // node or edge currently under mouse, or null
0076:            MultiLineString tip = null; // tip string displayed for tipObject, or null
0077:            int tipX, tipY, tipWidth, tipHeight; // bounding box of tip
0078:
0079:            GraphLayoutControlPanel controlPanel;
0080:
0081:            /**
0082:             * Make a GraphLayout.
0083:             */
0084:            public GraphLayout() {
0085:                graph = new Graph();
0086:                resetAlgorithm();
0087:                start();
0088:            }
0089:
0090:            /**
0091:             * Erase the graph.
0092:             */
0093:            public synchronized void clear() {
0094:                graph = new Graph();
0095:                changedGraph();
0096:            }
0097:
0098:            /**
0099:             * Get the graph.
0100:             */
0101:            public synchronized Graph getGraph() {
0102:                return graph;
0103:            }
0104:
0105:            /**
0106:             * Set the graph.
0107:             */
0108:            public synchronized void setGraph(Graph graph) {
0109:                this .graph = graph;
0110:                //selectedNode = null;
0111:                //selectedEdge = null;
0112:                tipObject = null;
0113:                tip = null;
0114:                changedGraph();
0115:            }
0116:
0117:            /**
0118:             * Get the graph-drawing algorithm in use.
0119:             */
0120:            public synchronized GDAlgorithm getAlgorithm() {
0121:                return algorithm;
0122:            }
0123:
0124:            /**
0125:             * Set the graph-drawing algorithm.
0126:             */
0127:            public synchronized void setAlgorithm(GDAlgorithm algorithm) {
0128:                this .algorithm = algorithm;
0129:                changedGraph();
0130:            }
0131:
0132:            synchronized void resetAlgorithm() {
0133:                algorithm = new AllPairsAlgorithm(springConstant, nodeCharge);
0134:                changedGraph();
0135:            }
0136:
0137:            /**
0138:             * Get the default rest length for new edges.
0139:             */
0140:            public synchronized double getRestLength() {
0141:                return restLength;
0142:            }
0143:
0144:            /**
0145:             * Set the default rest length for new edges.
0146:             */
0147:            public synchronized void setRestLength(double restLength) {
0148:                this .restLength = restLength;
0149:                changedGraph();
0150:            }
0151:
0152:            /**
0153:             * Get the spring constant.
0154:             */
0155:            public synchronized double getSpringConstant() {
0156:                return springConstant;
0157:            }
0158:
0159:            /**
0160:             * Set the spring constant.
0161:             */
0162:            public synchronized void setSpringConstant(double springConstant) {
0163:                this .springConstant = springConstant;
0164:                resetAlgorithm();
0165:            }
0166:
0167:            /**
0168:             * Get the node charge.
0169:             */
0170:            public synchronized double getNodeCharge() {
0171:                return nodeCharge;
0172:            }
0173:
0174:            /**
0175:             * Set the node charge.
0176:             */
0177:            public synchronized void setNodeCharge(double nodeCharge) {
0178:                this .nodeCharge = nodeCharge;
0179:                resetAlgorithm();
0180:            }
0181:
0182:            /**
0183:             * Get the refresh interval (measured in seconds).
0184:             */
0185:            public synchronized int getInterval() {
0186:                return interval;
0187:            }
0188:
0189:            /**
0190:             * Set the refresh interval (in seconds).
0191:             */
0192:            public synchronized void setInterval(int interval) {
0193:                this .interval = interval;
0194:            }
0195:
0196:            /**
0197:             * Get the layout algorithm iterations per refresh.
0198:             */
0199:            public synchronized int getIterations() {
0200:                return iterations;
0201:            }
0202:
0203:            /**
0204:             * Set the layout algorithm iterations per refresh.
0205:             */
0206:            public synchronized void setIterations(int iterations) {
0207:                this .iterations = iterations;
0208:            }
0209:
0210:            /**
0211:             * Test whether the graph is laid out automatically.
0212:             */
0213:            public synchronized boolean getAutomaticLayout() {
0214:                return automaticLayout;
0215:            }
0216:
0217:            /**
0218:             * Set whether the graph is laid out automatically.
0219:             */
0220:            public synchronized void setAutomaticLayout(boolean f) {
0221:                automaticLayout = f;
0222:                quiescent = !automaticLayout;
0223:                if (controlPanel != null)
0224:                    controlPanel.automatic.setState(automaticLayout);
0225:            }
0226:
0227:            /**
0228:             * Test whether the graph is quiescent (not changing in the background).
0229:             */
0230:            public synchronized boolean getQuiescent() {
0231:                return quiescent;
0232:            }
0233:
0234:            /**
0235:             * Test whether the graph layout thread is running in the background
0236:             */
0237:            public synchronized boolean getRunning() {
0238:                return running;
0239:            }
0240:
0241:            /**
0242:             * Get the threshold.
0243:             */
0244:            public synchronized double getThreshold() {
0245:                return threshold;
0246:            }
0247:
0248:            /**
0249:             * Set the threshold.
0250:             */
0251:            public synchronized void setThreshold(double threshold) {
0252:                this .threshold = threshold;
0253:                changedGraph();
0254:            }
0255:
0256:            /**
0257:             * Get the node background color.
0258:             */
0259:            public synchronized Color getNodeColor() {
0260:                return nodeColor;
0261:            }
0262:
0263:            /**
0264:             * Set the node background color.
0265:             */
0266:            public synchronized void setNodeColor(Color nodeColor) {
0267:                this .nodeColor = nodeColor;
0268:            }
0269:
0270:            /**
0271:             * Get the edge color.
0272:             */
0273:            public synchronized Color getEdgeColor() {
0274:                return edgeColor;
0275:            }
0276:
0277:            /**
0278:             * Set the edge color.
0279:             */
0280:            public synchronized void setEdgeColor(Color edgeColor) {
0281:                this .edgeColor = edgeColor;
0282:            }
0283:
0284:            /**
0285:             * Get the popup tip color.
0286:             */
0287:            public synchronized Color getTipColor() {
0288:                return tipColor;
0289:            }
0290:
0291:            /**
0292:             * Set the popup tip color.
0293:             */
0294:            public synchronized void setTipColor(Color tipColor) {
0295:                this .tipColor = tipColor;
0296:            }
0297:
0298:            /**
0299:             * Get node currently under the mouse pointer, or null if no node is under the mouse.
0300:             */
0301:            public synchronized RenderedNode getSelectedNode() {
0302:                return tipObject instanceof  RenderedNode ? (RenderedNode) tipObject
0303:                        : null;
0304:            }
0305:
0306:            /**
0307:             * Get edge currently under the mouse pointer, or null if no edge is under the mouse.
0308:             */
0309:            public synchronized RenderedEdge getSelectedEdge() {
0310:                return tipObject instanceof  RenderedEdge ? (RenderedEdge) tipObject
0311:                        : null;
0312:            }
0313:
0314:            /**
0315:             * Add a node.
0316:             */
0317:            public synchronized void addNode(RenderedNode node) {
0318:                graph.addNode(node);
0319:                graph.placeNode(node, node.x, node.y);
0320:                changedGraph();
0321:            }
0322:
0323:            /**
0324:             * Add an edge.
0325:             */
0326:            public synchronized void addEdge(RenderedEdge edge) {
0327:                if (edge.restLength == 0)
0328:                    edge.restLength = restLength;
0329:                graph.addEdge(edge);
0330:                changedGraph();
0331:            }
0332:
0333:            /**
0334:             * Remove a node.
0335:             */
0336:            public synchronized void removeNode(RenderedNode node) {
0337:                graph.removeNode(node);
0338:                changedGraph();
0339:            }
0340:
0341:            /**
0342:             * Remove an edge.
0343:             */
0344:            public synchronized void removeEdge(RenderedEdge edge) {
0345:                graph.removeEdge(edge);
0346:                changedGraph();
0347:            }
0348:
0349:            /**
0350:             * Handle a loaded image.
0351:             */
0352:            public synchronized boolean imageUpdate(Image img, int infoflags,
0353:                    int x, int y, int width, int height) {
0354:                if ((infoflags & (ImageObserver.WIDTH | ImageObserver.HEIGHT)) != 0) {
0355:                    for (int i = 0; i < graph.sizeNodes; ++i) {
0356:                        RenderedNode n = (RenderedNode) graph.nodes[i];
0357:                        if (n.icon == img) {
0358:                            n.width = width;
0359:                            n.height = height;
0360:                            changedGraph();
0361:                        }
0362:                    }
0363:                }
0364:                return super .imageUpdate(img, infoflags, x, y, width, height);
0365:            }
0366:
0367:            /*
0368:             * Background thread
0369:             *
0370:             */
0371:
0372:            Thread iterator;
0373:
0374:            /**
0375:             * Start automatic graph layout (in the background).
0376:             */
0377:            public synchronized void start() {
0378:                if (!running) {
0379:                    running = true;
0380:                    iterator = new Thread(this , "GraphListener");
0381:                    iterator.setDaemon(true);
0382:                    iterator.setPriority(Thread.MIN_PRIORITY);
0383:                    iterator.start();
0384:                }
0385:            }
0386:
0387:            /**
0388:             * Stop automatic graph layout.
0389:             */
0390:            public synchronized void stop() {
0391:                if (running) {
0392:                    running = false;
0393:                    notify();
0394:                    iterator = null;
0395:                }
0396:            }
0397:
0398:            /**
0399:             * The body of the background thread.  Clients should not call this
0400:             * method.
0401:             */
0402:            final static int MULTIPLIER = 2;
0403:
0404:            public synchronized void run() {
0405:                quiescent = false;
0406:                while (running) {
0407:                    long start = System.currentTimeMillis();
0408:
0409:                    if (automaticLayout && !quiescent) {
0410:                        for (int i = 0; i < iterations; ++i) {
0411:                            double improvement = algorithm.improveGraph(graph);
0412:                            dirty = true;
0413:                            if (improvement <= threshold * graph.sizeNodes) {
0414:                                quiescent = true;
0415:                                break;
0416:                            }
0417:                        }
0418:                    }
0419:
0420:                    if (dirty)
0421:                        super .repaint();
0422:
0423:                    /*int r = (int) (System.currentTimeMillis() - start);
0424:                    int w = Math.max (interval, r * MULTIPLIER);
0425:                    System.out.println ("ran " + r + " msec, now waiting " + w + " msec");
0426:                     */
0427:
0428:                    try {
0429:                        wait(interval);
0430:                    } catch (InterruptedException e) {
0431:                    }
0432:                }
0433:                quiescent = true;
0434:            }
0435:
0436:            /**
0437:             * Notify background thread that the graph has changed.
0438:             */
0439:            public synchronized void changedGraph() {
0440:                if (automaticLayout)
0441:                    quiescent = false;
0442:                repaint();
0443:            }
0444:
0445:            /**
0446:             * Notify background thread that the view has changed.
0447:             */
0448:            public synchronized void repaint() {
0449:                if (!running)
0450:                    super .repaint();
0451:                else
0452:                    dirty = true;
0453:            }
0454:
0455:            /**
0456:             * Show control panel for changing graph layout parameters.
0457:             */
0458:            public void showControlPanel() {
0459:                if (controlPanel == null)
0460:                    controlPanel = new GraphLayoutControlPanel(this );
0461:                controlPanel.show();
0462:            }
0463:
0464:            protected void finalize() throws Throwable {
0465:                super .finalize();
0466:                if (controlPanel != null) {
0467:                    controlPanel.dispose();
0468:                    controlPanel = null;
0469:                }
0470:            }
0471:
0472:            /*
0473:             * Scale coordinates from graph to screen.
0474:             */
0475:            double originX = 0.0, originY = 0.0;
0476:            double scaleX = 1.0, scaleY = 1.0;
0477:
0478:            private void scaleGraph() {
0479:                Dimension d = size();
0480:                double halfScreenWidth = d.width / 2.0;
0481:                double halfScreenHeight = d.height / 2.0;
0482:
0483:                double sX = 1.0, sY = 1.0;
0484:                for (int i = 0; i < graph.sizeNodes; ++i) {
0485:                    RenderedNode n = (RenderedNode) graph.nodes[i];
0486:                    sX = Math.min(sX, (halfScreenWidth - n.width / 2.0)
0487:                            / (Math.abs(n.x) + 1));
0488:                    sY = Math.min(sY, (halfScreenHeight - n.height / 2.0)
0489:                            / (Math.abs(n.y) + 1));
0490:                }
0491:
0492:                double oX = halfScreenWidth;
0493:                double oY = halfScreenHeight;
0494:
0495:                for (int i = 0; i < graph.sizeNodes; ++i) {
0496:                    RenderedNode n = (RenderedNode) graph.nodes[i];
0497:                    n.screenX = (int) (n.x * sX + oX);
0498:                    n.screenY = (int) (n.y * sY + oY);
0499:                }
0500:
0501:                // save the translation for use in placeNodeOnScreen
0502:                originX = oX;
0503:                originY = oY;
0504:                scaleX = sX;
0505:                scaleY = sY;
0506:            }
0507:
0508:            public synchronized void placeNodeOnScreen(RenderedNode n, int x,
0509:                    int y) {
0510:                graph.placeNode(n, (x - originX) / scaleX, (y - originY)
0511:                        / scaleY);
0512:                n.screenX = x;
0513:                n.screenY = y;
0514:            }
0515:
0516:            public synchronized void placeNodeOnGraph(RenderedNode n, double x,
0517:                    double y) {
0518:                graph.placeNode(n, x, y);
0519:                n.screenX = (int) (x * scaleX + originX);
0520:                n.screenY = (int) (y * scaleY + originY);
0521:            }
0522:
0523:            /*
0524:             * Painting methods
0525:             *
0526:             */
0527:
0528:            Image offscreen; // offscreen drawing area
0529:            Dimension offSize; // size of offscreen buffer
0530:            Graphics offg; // drawonable associated with offscreen buffer
0531:            FontMetrics fm; // font metrics for offscreen buffer
0532:
0533:            public void update(Graphics g) {
0534:                // don't clear window with background color first
0535:                //long before = System.currentTimeMillis ();
0536:                paint(g);
0537:                //long after = System.currentTimeMillis ();
0538:                //System.out.println ("repaint: " + (after - before) + " msec");
0539:            }
0540:
0541:            void createOffscreenArea(Dimension d) {
0542:                offSize = new Dimension(d.width > 0 ? d.width : 1,
0543:                        d.height > 0 ? d.height : 1);
0544:                offscreen = createImage(offSize.width, offSize.height);
0545:                offg = offscreen.getGraphics();
0546:                offg.setFont(getFont());
0547:                fm = offg.getFontMetrics();
0548:            }
0549:
0550:            public synchronized void paint(Graphics g) {
0551:                Dimension d = size();
0552:
0553:                if (offscreen == null || d.width != offSize.width
0554:                        || d.height != offSize.height)
0555:                    createOffscreenArea(d);
0556:
0557:                offg.setColor(getBackground());
0558:                offg.fillRect(0, 0, d.width, d.height);
0559:
0560:                scaleGraph();
0561:
0562:                // paint the edges first
0563:                for (int i = 0; i < graph.sizeEdges; ++i) {
0564:                    RenderedEdge e = (RenderedEdge) graph.edges[i];
0565:                    if (e == null)
0566:                        continue;
0567:                    RenderedNode from = (RenderedNode) e.from;
0568:                    RenderedNode to = (RenderedNode) e.to;
0569:                    if (from == null || to == null)
0570:                        continue;
0571:
0572:                    Color c = e.color;
0573:                    if (c == null)
0574:                        c = edgeColor;
0575:
0576:                    offg.setColor(c);
0577:                    drawArrowToBox(offg, (int) from.screenX,
0578:                            (int) from.screenY, (int) to.screenX,
0579:                            (int) to.screenY, (int) (to.width / 2),
0580:                            (int) (to.height / 2), 6, 3, e.thick);
0581:                }
0582:
0583:                // paint the nodes on top
0584:                for (int i = 0; i < graph.sizeNodes; ++i) {
0585:                    RenderedNode n = (RenderedNode) graph.nodes[i];
0586:                    if (n == null)
0587:                        continue;
0588:
0589:                    int width = (int) n.width;
0590:                    int height = (int) n.height;
0591:                    int x = (int) n.screenX - width / 2;
0592:                    int y = (int) n.screenY - height / 2;
0593:                    Color c = n.color;
0594:
0595:                    if (n.icon == null) {
0596:                        if (c == null)
0597:                            c = nodeColor;
0598:
0599:                        offg.setColor(c);
0600:                        offg.fillRect(x, y, width, height);
0601:                        offg.setColor(getForeground());
0602:                        offg.drawRect(x, y, width - 1, height - 1);
0603:                        offg.drawString(n.name, x + 5, y + 2 + fm.getAscent());
0604:                    } else {
0605:                        // NIY: scaling
0606:                        if (c == null)
0607:                            offg.drawImage(n.icon, x, y, this );
0608:                        else
0609:                            offg.drawImage(n.icon, x, y, c, this );
0610:                    }
0611:                }
0612:
0613:                // paint the tip on top
0614:                if (tip != null) {
0615:                    offg.setColor(tipColor);
0616:                    offg.fillRect(tipX, tipY, tipWidth, tipHeight);
0617:                    offg.setColor(Color.black);
0618:                    offg.drawRect(tipX, tipY, tipWidth - 1, tipHeight - 1);
0619:                    tip.draw(offg, tipX + 5, tipY + 2, Label.LEFT);
0620:                }
0621:
0622:                // draw border
0623:                offg.setColor(quiescent ? getForeground() : Color.red);
0624:                offg.drawRect(0, 0, d.width - 1, d.height - 1);
0625:
0626:                // copy to screen
0627:                g.drawImage(offscreen, 0, 0, null);
0628:
0629:                dirty = false;
0630:            }
0631:
0632:            void drawArrowToBox(Graphics g, int x1, int y1, int x2, int y2,
0633:                    int wHalfBox, int hHalfBox, int head_length,
0634:                    int head_width, boolean thick) {
0635:                if (thick) {
0636:                    drawArrowToBox(g, x1, y1, x2, y2, wHalfBox, hHalfBox,
0637:                            head_length, head_width, false);
0638:                    drawArrowToBox(g, x1 - 1, y1, x2 - 1, y2, wHalfBox,
0639:                            hHalfBox, head_length, head_width, false);
0640:                    drawArrowToBox(g, x1, y1 - 1, x2, y2 - 1, wHalfBox,
0641:                            hHalfBox, head_length, head_width, false);
0642:                    drawArrowToBox(g, x1 - 1, y1 - 1, x2 - 1, y2 - 1, wHalfBox,
0643:                            hHalfBox, head_length, head_width, false);
0644:                } else {
0645:                    double dx = x2 - x1;
0646:                    double dy = y2 - y1;
0647:                    double d = Math.sqrt(dx * dx + dy * dy);
0648:                    if (d < 1.0) {
0649:                        d = 1.0;
0650:                        dx = 1;
0651:                    }
0652:                    dx /= d;
0653:                    dy /= d;
0654:
0655:                    double lx = head_length * dx;
0656:                    double ly = head_length * dy;
0657:                    double wx = head_width * dx;
0658:                    double wy = head_width * dy;
0659:
0660:                    double cp1 = dx * hHalfBox - dy * wHalfBox;
0661:                    double cp2 = dx * hHalfBox + dy * wHalfBox;
0662:
0663:                    if (cp1 < 0) {
0664:                        if (cp2 < 0) {
0665:                            // region I
0666:                            x2 += wHalfBox;
0667:                            y2 += wHalfBox * dy / dx;
0668:                        } else {
0669:                            // region II
0670:                            y2 -= hHalfBox;
0671:                            x2 -= hHalfBox * dx / dy;
0672:                        }
0673:                    } else {
0674:                        if (cp2 > 0) {
0675:                            // region III
0676:                            x2 -= wHalfBox;
0677:                            y2 -= wHalfBox * dy / dx;
0678:                        } else {
0679:                            // region IV
0680:                            y2 += hHalfBox;
0681:                            x2 += hHalfBox * dx / dy;
0682:                        }
0683:                    }
0684:
0685:                    g.drawLine(x1, y1, x2, y2);
0686:                    g.drawLine(x2, y2, (int) (x2 - lx + wy + 0.5), (int) (y2
0687:                            - ly - wx + .5));
0688:                    g.drawLine(x2, y2, (int) (x2 - lx - wy + 0.5), (int) (y2
0689:                            - ly + wx + .5));
0690:                }
0691:            }
0692:
0693:            public synchronized FontMetrics getFontMetrics() {
0694:                if (fm == null) {
0695:                    Dimension d = size();
0696:                    createOffscreenArea(d);
0697:                }
0698:                return fm;
0699:            }
0700:
0701:            // intercept font settings and transfer to offscreen buffer
0702:            public synchronized void setFont(Font f) {
0703:                super .setFont(f);
0704:                if (offg != null) {
0705:                    offg.setFont(f);
0706:                    fm = offg.getFontMetrics();
0707:                }
0708:            }
0709:
0710:            /*
0711:            public Dimension preferredSize () {
0712:                return new Dimension (400, 400);
0713:            }
0714:             */
0715:
0716:            /*
0717:             * Selecting and dragging nodes
0718:             *
0719:             */
0720:
0721:            RenderedNode dragNode = null; // node being dragged, or null
0722:            int dragOffsetX, dragOffsetY;
0723:
0724:            // initial displacement of mouse cursor from dragged object's origin;
0725:            // the object remains at this displacement throughout the drag
0726:
0727:            void point(int x, int y) {
0728:                Object over = pick(x, y);
0729:                if (over == null) {
0730:                    if (tipObject != null || tip != null) {
0731:                        tipObject = null;
0732:                        tip = null;
0733:                        super .repaint();
0734:                    }
0735:                } else if (over != tipObject) {
0736:                    String[] tipLines = ((Tipped) over).getTip();
0737:
0738:                    if (tipLines == null) {
0739:                        tipObject = null;
0740:                        tip = null;
0741:                        super .repaint();
0742:                    } else {
0743:                        tipObject = over;
0744:                        tip = new MultiLineString(tipLines);
0745:                        tipWidth = tip.getWidth(fm) + 10;
0746:                        tipHeight = tip.getHeight(fm) + 4;
0747:                        tipX = Math.max(x - tipWidth / 2, 0);
0748:                        tipY = Math.min(y + 25, offSize.height - tipHeight);
0749:                        super .repaint();
0750:                    }
0751:                }
0752:            }
0753:
0754:            void leave() {
0755:                if (tipObject != null || tip != null) {
0756:                    tip = null;
0757:                    tipObject = null;
0758:                    super .repaint();
0759:                }
0760:            }
0761:
0762:            void click(int x, int y, boolean rightClick) {
0763:                requestFocus();
0764:
0765:                Object over = pick(x, y);
0766:                if (over != null) {
0767:                    if (over instanceof  RenderedNode) {
0768:                        RenderedNode n = (RenderedNode) over;
0769:                        //selectedNode = (RenderedNode)over;
0770:                        //selectedEdge = null;
0771:
0772:                        // start dragging the node
0773:                        if (!n.fixed) {
0774:                            dragNode = n;
0775:                            dragNode.fixed = true;
0776:                            dragOffsetX = (int) dragNode.screenX - x;
0777:                            dragOffsetY = (int) dragNode.screenY - y;
0778:                        }
0779:                    }
0780:                    //else {
0781:                    //    // over instanceof RenderedEdge
0782:                    //    selectedNode = null;
0783:                    //    selectedEdge = (RenderedEdge)over;
0784:                    //}
0785:                } else if (rightClick) {
0786:                    // right-click over background
0787:                    showControlPanel();
0788:                }
0789:            }
0790:
0791:            void drag(int x, int y) {
0792:                if (dragNode != null) {
0793:                    placeNodeOnScreen(dragNode, x + dragOffsetX, y
0794:                            + dragOffsetY);
0795:                    changedGraph();
0796:                }
0797:            }
0798:
0799:            void drop(int x, int y) {
0800:                if (dragNode != null) {
0801:                    placeNodeOnScreen(dragNode, x + dragOffsetX, y
0802:                            + dragOffsetY);
0803:                    changedGraph();
0804:                    dragNode.fixed = false;
0805:                    dragNode = null;
0806:                }
0807:            }
0808:
0809:            public boolean handleEvent(Event event) {
0810:                switch (event.id) {
0811:                case Event.MOUSE_DOWN:
0812:                    click(event.x, event.y, event.metaDown());
0813:                    return true;
0814:                case Event.MOUSE_UP:
0815:                    drop(event.x, event.y);
0816:                    return true;
0817:                case Event.MOUSE_MOVE:
0818:                    point(event.x, event.y);
0819:                    return true;
0820:                case Event.MOUSE_EXIT:
0821:                    leave();
0822:                    return true;
0823:                case Event.MOUSE_DRAG:
0824:                    if (dragNode != null) {
0825:                        drag(event.x, event.y);
0826:                        return true;
0827:                    } else
0828:                        super .handleEvent(event);
0829:                default:
0830:                    return super .handleEvent(event);
0831:                }
0832:            }
0833:
0834:            /**
0835:             * Find the object (Node or Edge) at position (x,y) relative to the window.
0836:             * @param x X position
0837:             * @param y Y position
0838:             * @return topmost object under (x,y), or null if none
0839:             */
0840:            public Object pick(int x, int y) {
0841:                // proceed in reverse display order: nodes first, then edges
0842:                for (int i = graph.sizeNodes - 1; i >= 0; --i) {
0843:                    RenderedNode n = (RenderedNode) graph.nodes[i];
0844:                    if (Math.abs(n.screenX - x) < n.width / 2
0845:                            && Math.abs(n.screenY - y) < n.height / 2)
0846:                        return n;
0847:                }
0848:
0849:                for (int i = graph.sizeEdges - 1; i >= 0; --i) {
0850:                    RenderedEdge e = (RenderedEdge) graph.edges[i];
0851:                    RenderedNode to = (RenderedNode) e.to;
0852:                    RenderedNode from = (RenderedNode) e.from;
0853:                    if (inLineSegment(x, y, (int) to.screenX, (int) to.screenY,
0854:                            (int) from.screenX, (int) from.screenY, 4))
0855:                        return e;
0856:                }
0857:
0858:                return null;
0859:            }
0860:
0861:            boolean inLineSegment(int x, int y, int x1, int y1, int x2, int y2,
0862:                    int threshold) {
0863:                int left, right, top, bottom;
0864:                if (x1 < x2) {
0865:                    left = x1;
0866:                    right = x2;
0867:                } else {
0868:                    left = x2;
0869:                    right = x1;
0870:                }
0871:                if (y1 < y2) {
0872:                    top = y1;
0873:                    bottom = y2;
0874:                } else {
0875:                    top = y2;
0876:                    bottom = y1;
0877:                }
0878:
0879:                // check bounding box first
0880:                if (x < left - threshold || x > right + threshold
0881:                        || y < top - threshold || y > bottom + threshold) {
0882:                    return false;
0883:                }
0884:
0885:                // equation for line is ax + by + c = 0
0886:                // d/sqrt(a^2+b^2) is the distance between line and point <x,y>
0887:                int a = y1 - y2;
0888:                int b = x2 - x1;
0889:                int c = x1 * y2 - x2 * y1;
0890:                int d = a * x + b * y + c;
0891:
0892:                return (d * d <= threshold * threshold * (a * a + b * b));
0893:            }
0894:
0895:            /*
0896:             * Testing
0897:             *
0898:            public static void main (String[] args) {
0899:                Frame f = new Frame ();
0900:                f.addWindowListener (new WindowAdapter () {
0901:                    public void windowClosing (WindowEvent event) {
0902:                        ((Frame)event.getSource()).dispose();
0903:                    }
0904:                });
0905:                f.setSize (100,100);
0906:                f.setLayout (new BorderLayout ());
0907:                
0908:                GraphLayout g = new GraphLayout ();
0909:                f.add ("Center", g);
0910:                f.show ();
0911:                
0912:                Node last = null;
0913:                for (int i=0; i<args.length; ++i) {
0914:                    try {
0915:                        Thread.sleep (200);
0916:                    } catch (InterruptedException e) {}
0917:                    RenderedNode n = new RenderedNode();
0918:                    n.name = args[i];
0919:                    g.addNode (n);
0920:                    g.graph.placeNode (n, 0, 0);
0921:                    
0922:                    if (last != null) {
0923:                        RenderedEdge e = new RenderedEdge (last, n);
0924:                        g.addEdge (e);
0925:                    }
0926:                        
0927:                }
0928:            }
0929:             */
0930:        }
0931:
0932:        class GraphLayoutControlPanel extends ClosableFrame {
0933:            GraphLayout gl;
0934:
0935:            Checkbox automatic;
0936:
0937:            Scrollbar threshold;
0938:            Scrollbar restLength;
0939:            Scrollbar springConstant;
0940:            Scrollbar nodeCharge;
0941:
0942:            TextField thresholdText;
0943:            TextField restLengthText;
0944:            TextField springConstantText;
0945:            TextField nodeChargeText;
0946:
0947:            public GraphLayoutControlPanel(GraphLayout graphLayout) {
0948:                super ("Graph Layout Control Panel", true);
0949:                gl = graphLayout;
0950:
0951:                setLayout(new GridBagLayout());
0952:                Constrain.add(this ,
0953:                        automatic = new Checkbox("Automatic layout"), Constrain
0954:                                .labelLike(0, 0, 2));
0955:                automatic.setState(true);
0956:                Constrain.add(this , new Label("Threshold:", Label.LEFT),
0957:                        Constrain.labelLike(0, 1));
0958:                Constrain
0959:                        .add(this , thresholdText = new TextField(String
0960:                                .valueOf(gl.getThreshold())), Constrain
0961:                                .fieldLike(1, 1));
0962:                Constrain.add(this , threshold = new Scrollbar(
0963:                        Scrollbar.HORIZONTAL, (int) gl.getThreshold(), 50, 0,
0964:                        1000), Constrain.fieldLike(0, 2, 2));
0965:                Constrain.add(this , new Label("Rest length:", Label.LEFT),
0966:                        Constrain.labelLike(0, 3));
0967:                Constrain.add(this , restLengthText = new TextField(String
0968:                        .valueOf(gl.getRestLength())), Constrain
0969:                        .fieldLike(1, 3));
0970:                Constrain.add(this , restLength = new Scrollbar(
0971:                        Scrollbar.HORIZONTAL, (int) gl.getRestLength(), 50, 0,
0972:                        1000), Constrain.fieldLike(0, 4, 2));
0973:                Constrain.add(this , new Label("Spring constant:", Label.LEFT),
0974:                        Constrain.labelLike(0, 5));
0975:                Constrain.add(this , springConstantText = new TextField(String
0976:                        .valueOf(gl.getSpringConstant())), Constrain.fieldLike(
0977:                        1, 5));
0978:                Constrain.add(this , springConstant = new Scrollbar(
0979:                        Scrollbar.HORIZONTAL, (int) gl.getSpringConstant(), 50,
0980:                        0, 1000), Constrain.fieldLike(0, 6, 2));
0981:                Constrain.add(this , new Label("Node charge:", Label.LEFT),
0982:                        Constrain.labelLike(0, 7));
0983:                Constrain.add(this , nodeChargeText = new TextField(String
0984:                        .valueOf(Math.sqrt(gl.getNodeCharge()))), Constrain
0985:                        .fieldLike(1, 7));
0986:                Constrain.add(this , nodeCharge = new Scrollbar(
0987:                        Scrollbar.HORIZONTAL, (int) (Math.sqrt(gl
0988:                                .getNodeCharge())), 50, 0, 1000), Constrain
0989:                        .fieldLike(0, 8, 2));
0990:                pack();
0991:            }
0992:
0993:            public boolean handleEvent(Event event) {
0994:                // FIX: doesn't support text entry
0995:                if (event.target == automatic)
0996:                    gl.setAutomaticLayout(automatic.getState());
0997:                else if (event.target == threshold)
0998:                    gl.setThreshold(((Integer) event.arg).intValue());
0999:                else if (event.target == restLength)
1000:                    gl.setRestLength(((Integer) event.arg).intValue());
1001:                else if (event.target == springConstant)
1002:                    gl.setSpringConstant(((Integer) event.arg).intValue());
1003:                else if (event.target == restLength) {
1004:                    int v = ((Integer) event.arg).intValue();
1005:                    gl.setNodeCharge(v * v);
1006:                } else
1007:                    return super .handleEvent(event);
1008:                return true;
1009:            }
1010:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.