Source Code Cross Referenced for JGraphpadVertexRenderer.java in  » Graphic-Library » jgraphpad » com » jgraph » pad » graph » 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 » Graphic Library » jgraphpad » com.jgraph.pad.graph 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: JGraphpadVertexRenderer.java,v 1.17 2007/07/23 08:20:53 gaudenz Exp $
003:         * Copyright (c) 2001-2005, Gaudenz Alder
004:         * 
005:         * All rights reserved. 
006:         * 
007:         * This file is licensed under the JGraph software license, a copy of which
008:         * will have been provided to you in the file LICENSE at the root of your
009:         * installation directory. If you are unable to locate this file please
010:         * contact JGraph sales for another copy.
011:         */
012:        package com.jgraph.pad.graph;
013:
014:        import java.awt.BasicStroke;
015:        import java.awt.Color;
016:        import java.awt.Component;
017:        import java.awt.Dimension;
018:        import java.awt.GradientPaint;
019:        import java.awt.Graphics;
020:        import java.awt.Graphics2D;
021:        import java.awt.Image;
022:        import java.awt.Point;
023:        import java.awt.Polygon;
024:        import java.awt.Rectangle;
025:        import java.awt.Shape;
026:        import java.awt.Stroke;
027:        import java.awt.geom.Area;
028:        import java.awt.geom.Ellipse2D;
029:        import java.awt.geom.Point2D;
030:        import java.awt.geom.Rectangle2D;
031:        import java.util.Map;
032:
033:        import javax.swing.BorderFactory;
034:        import javax.swing.Icon;
035:        import javax.swing.ImageIcon;
036:        import javax.swing.JComponent;
037:        import javax.swing.JLabel;
038:        import javax.swing.JTextPane;
039:        import javax.swing.border.Border;
040:        import javax.swing.text.SimpleAttributeSet;
041:        import javax.swing.text.StyleConstants;
042:        import javax.swing.text.StyledDocument;
043:
044:        import org.jgraph.JGraph;
045:        import org.jgraph.graph.AbstractCellView;
046:        import org.jgraph.graph.CellView;
047:        import org.jgraph.graph.DefaultGraphModel;
048:        import org.jgraph.graph.GraphConstants;
049:        import org.jgraph.graph.VertexRenderer;
050:        import org.jgraph.graph.VertexView;
051:
052:        /**
053:         * Universal renderer for vertices and groups. This implementation supports
054:         * drawing rectangles, circles, diamonds and rounded rectangles and optionally
055:         * paints a gradient background, stretched background image and folding icon.
056:         */
057:        public class JGraphpadVertexRenderer extends VertexRenderer {
058:
059:            /**
060:             * Client property for JGraph to control the display of the folding icons.
061:             * Default is true, eg if the property is missing the icons are painted. To
062:             * switch this feature off, use the following code:
063:             * 
064:             * <PRE>
065:             * 
066:             * graph.putClientProperty(
067:             * JGraphpadVertexRenderer.CLIENTPROPERTY_SHOWFOLDINGICONS, new
068:             * Boolean(false));
069:             * 
070:             * </PRE>
071:             */
072:            public static String CLIENTPROPERTY_SHOWFOLDINGICONS = "showFoldingIcons";
073:
074:            /**
075:             * Defines a dimension of width and height 0.
076:             */
077:            public static Dimension ZERO_DIMENSION = new Dimension(0, 0);
078:
079:            /**
080:             * Defines the default inset to render rich text.
081:             */
082:            public static int INSET = 4;
083:
084:            /**
085:             * Defines the root handle size and location.
086:             */
087:            public static Rectangle handle = new Rectangle(0, 0, 7, 7);
088:
089:            /**
090:             * Holds a reference to fetch the correct cell value from the model in
091:             * paint. This should go into getComponentRenderer.
092:             */
093:            protected JGraph graph;
094:
095:            /**
096:             * Defines the shape constants to be used as values for the
097:             * {@link JGraphpadGraphConstants#VERTEXSHAPE} attributes.
098:             */
099:            public static final int SHAPE_RECTANGLE = 0, SHAPE_CIRCLE = 1,
100:                    SHAPE_DIAMOND = 2, SHAPE_ROUNDED = 3, SHAPE_CYLINDER = 4,
101:                    SHAPE_TRIANGLE = 5;
102:
103:            /**
104:             * Holds the text pane to be used for rich text rendering.
105:             */
106:            public static JTextPane textPane = new JTextPane();
107:
108:            /**
109:             * Holds the wrapper renderer used for heavyweights.
110:             */
111:            protected static JComponent wrapperRenderer;
112:
113:            /**
114:             * Holds the user object of the current cell.
115:             */
116:            protected Object userObject = null;
117:
118:            /**
119:             * Holds the shape of the current view.
120:             */
121:            protected int shape = 0;
122:
123:            /**
124:             * Specifies whether the current view is a rich text value, and if the image
125:             * should be stretched.
126:             */
127:            protected boolean isRichText = false, stretchImage = false,
128:                    isEditing = false, showFoldingIcons = true,
129:                    isGroup = false;
130:
131:            /**
132:             * Holds the background and foreground of the graph.
133:             */
134:            protected Color graphBackground = Color.white,
135:                    graphForeground = Color.black;
136:
137:            /**
138:             * References the value component of the user object if one exists.
139:             */
140:            protected Component valueComponent;
141:
142:            /**
143:             * Holds the area to be painted for the cylinder shape.
144:             */
145:            protected Area cylinderArea = null;
146:
147:            /**
148:             * Holds the shape to be painted for diamond cells.
149:             */
150:            protected Polygon diamond = null;
151:
152:            /**
153:             * Holds the round rect arc size for rounded rectangles.
154:             */
155:            protected int roundRectArc = 0;
156:
157:            /**
158:             * Specified if a heavyweight should be painted. Default is true.
159:             */
160:            protected transient boolean showHeavyweight = true;
161:
162:            /**
163:             * Constructs a new vertex renderer.
164:             */
165:            public JGraphpadVertexRenderer() {
166:                textPane.setOpaque(false);
167:                textPane.setBorder(BorderFactory.createEmptyBorder(INSET,
168:                        INSET, INSET, INSET));
169:
170:                // Makes sure the heavyweights is never returned directly,
171:                // so that the real component is never touched directly.
172:                wrapperRenderer = new JComponent() {
173:                    public void paint(Graphics g) {
174:                        if (showHeavyweight) {
175:                            valueComponent.setSize(getSize());
176:                            if (!isEditing)
177:                                valueComponent.paint(g);
178:                        } else {
179:                            g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
180:                            g.drawLine(0, 0, getWidth() - 1, getHeight() - 1);
181:                            g.drawLine(getWidth() - 1, 0, 0, getHeight() - 1);
182:                        }
183:                    }
184:                };
185:                wrapperRenderer.setDoubleBuffered(false);
186:            }
187:
188:            /**
189:             * Overrides the parent implementation to return the value component stored
190:             * in the user object instead of this renderer if a value component exists.
191:             * This applies some of the values installed to this renderer to the value
192:             * component (border, opaque) if the latter is a JComponent.
193:             * 
194:             * @return Returns a configured renderer for the specified view.
195:             */
196:            public Component getRendererComponent(JGraph graph, CellView view,
197:                    boolean sel, boolean focus, boolean preview) {
198:                this .graph = graph;
199:                Component c = super .getRendererComponent(graph, view, sel,
200:                        focus, preview);
201:                graphBackground = graph.getBackground();
202:                graphForeground = graph.getForeground();
203:                isEditing = graph.getEditingCell() == view.getCell();
204:                isGroup = DefaultGraphModel.isGroup(graph.getModel(), view
205:                        .getCell());
206:                Boolean bool = (Boolean) graph
207:                        .getClientProperty(CLIENTPROPERTY_SHOWFOLDINGICONS);
208:                if (bool != null)
209:                    showFoldingIcons = bool.booleanValue();
210:                else
211:                    showFoldingIcons = true;
212:                if (valueComponent != null) {
213:                    valueComponent.setSize(getSize());
214:                    valueComponent.setBackground(getBackground());
215:
216:                    // Shows a cross for all scaled heavyweight previews
217:                    // for faster preview performance
218:                    showHeavyweight = !preview || graph.getScale() == 1;
219:
220:                    // Applies the configured properties to the value component
221:                    if (valueComponent instanceof  JComponent) {
222:                        JComponent comp = (JComponent) valueComponent;
223:                        if (comp.getBorder() == null) {
224:                            comp.setBorder(getBorder());
225:                        }
226:                        comp.setOpaque(isOpaque());
227:
228:                        // Workaround for locking problem in windows
229:                        comp.setDoubleBuffered(false);
230:
231:                        // Do not wrap component hierachies
232:                        if (comp.getComponentCount() > 0 && !isEditing
233:                                && showHeavyweight) {
234:                            return comp;
235:                        }
236:                    }
237:                    // Do not return the component directly, return a wrapper
238:                    // so that the real component is never touched directly.
239:                    return wrapperRenderer;
240:                }
241:                return c;
242:            }
243:
244:            /**
245:             * Paints the renderer component for the configured view. This
246:             * implementation consists of three parts: painting the background, gradient
247:             * and stretched image, painting the content by doing a supercall and
248:             * calling the rich text renderer if required, and finally paint the border,
249:             * selection border and the folding handle.
250:             * 
251:             * @param g
252:             *            The graphics to paint the cell to.
253:             */
254:            public void paint(Graphics g) {
255:                Border previousBorder = getBorder();
256:                paintBackground(g);
257:
258:                // Limits all further painting to the clipping region of the actual
259:                // shape so that images and text are cropped at the shape bounds.
260:                // The clipping region is intersected with the "dirty" region.
261:                Dimension d = getSize();
262:                int b = borderWidth;
263:                Shape previousShape = cropToShape(g);
264:                if (shape == SHAPE_DIAMOND || shape == SHAPE_TRIANGLE) {
265:                    Area clip = new Area(diamond);
266:                    clip.intersect(new Area(previousShape));
267:                    g.setClip(clip);
268:                } else if (shape == SHAPE_CYLINDER) {
269:                    Area clip = new Area(cylinderArea);
270:                    cylinderArea.intersect(new Area(previousShape));
271:                    g.setClip(clip);
272:                } else if (shape == SHAPE_CIRCLE) {
273:                    Area clip = new Area(new java.awt.geom.Ellipse2D.Float(-b,
274:                            -b, d.width + b, d.height + b));
275:                    clip.intersect(new Area(previousShape));
276:                    g.setClip(clip);
277:                }
278:
279:                // Stretched images appear in the background of the cell. This sets
280:                // the icon to null after painting and takes over all image painting
281:                // in the case of stretched images as the superclass does not support
282:                // it. No images are drawn for previews to speedup the display.
283:                if (stretchImage) {
284:                    Image img = null;
285:                    Icon icon = getIcon();
286:                    if (icon != null)
287:                        img = ((ImageIcon) icon).getImage();
288:                    if (img != null && !preview)
289:                        g.drawImage(img, 0, 0, d.width - 1, d.height - 1, this );
290:                    setIcon(null);
291:                }
292:
293:                // Makes sure that no border, background or selection border is painted
294:                // by the superclass' paint in case we already did that or will do that
295:                // later. This makes sure the superclass' only paints the label and
296:                // image.
297:                boolean wasSelected = selected;
298:                boolean wasOpaque = isOpaque();
299:                if (shape != SHAPE_RECTANGLE) {
300:                    setBorder(null);
301:                    setOpaque(false);
302:                    selected = false;
303:                }
304:
305:                // Makes sure the superclass' paint method paints doesn't paint the
306:                // label in case we use a rich text box internally to paint the text.
307:                if (isRichText)
308:                    setText("");
309:
310:                // Calls the superclass paint method and restores the previous border
311:                // and selection state.
312:                super .paint(g);
313:                setBorder(previousBorder);
314:                setOpaque(wasOpaque);
315:                selected = wasSelected;
316:
317:                // Paints the rich text foreground which is not painted by the
318:                // superclass. The code below applies the vertical aligment of
319:                // this renderer to the painted rich text by translating the
320:                // graphics by the required amount. This is trick to implement
321:                // vertical alignment in rich text panes which is otherwise
322:                // not supported.
323:                if (isRichText)
324:                    paintRichText(g);
325:
326:                // Finished painting of all content within the shape clipping region so
327:                // restore the original clipping region.
328:                g.setClip(previousShape);
329:
330:                // Paints the border for all non-rectangular shapes using the geometry
331:                // defined for painting the background.
332:                Graphics2D g2 = (Graphics2D) g;
333:                Stroke previousStroke = g2.getStroke();
334:                if (shape != SHAPE_RECTANGLE && getBorder() != null) {
335:                    g.setColor(bordercolor);
336:                    g2.setStroke(new BasicStroke(b));
337:                    paintShapeBorder(g);
338:                }
339:
340:                // Paints the selection border for all non-rectangular shapes using the
341:                // geometry defined for painting the background.
342:                if (selected || childrenSelected) {
343:                    if (childrenSelected)
344:                        g.setColor(gridColor);
345:                    else
346:                        g.setColor(highlightColor);
347:                    g2.setStroke(GraphConstants.SELECTION_STROKE);
348:                    paintShapeBorder(g);
349:                }
350:
351:                // Restores the previous stroke and paints the folding icon
352:                g2.setStroke(previousStroke);
353:                if (showFoldingIcons)
354:                    paintFoldingIcon(g);
355:            }
356:
357:            /**
358:             * Limits all further painting to the clipping region of the actual
359:             * shape so that images and text are cropped at the shape bounds.
360:             * The clipping region is intersected with the "dirty" region.
361:             *
362:             * @param g
363:             *          The graphics to crop.
364:             * @return 	The shape before cropping
365:             */
366:            protected Shape cropToShape(Graphics g) {
367:                Shape previousShape = g.getClip();
368:                Dimension d = getSize();
369:                int b = borderWidth;
370:                if (shape == SHAPE_DIAMOND || shape == SHAPE_TRIANGLE) {
371:                    Area clip = new Area(diamond);
372:                    clip.intersect(new Area(previousShape));
373:                    g.setClip(clip);
374:                } else if (shape == SHAPE_CYLINDER) {
375:                    Area clip = new Area(cylinderArea);
376:                    cylinderArea.intersect(new Area(previousShape));
377:                    g.setClip(clip);
378:                } else if (shape == SHAPE_CIRCLE) {
379:                    Area clip = new Area(new java.awt.geom.Ellipse2D.Float(-b,
380:                            -b, d.width + b, d.height + b));
381:                    clip.intersect(new Area(previousShape));
382:                    g.setClip(clip);
383:                }
384:
385:                return previousShape;
386:            }
387:
388:            /**
389:             * Utility method to paint the background for all non-rectangular shapes.
390:             * 
391:             * @param g
392:             *            The graphics to paint the background to.
393:             */
394:            protected void paintBackground(Graphics g) {
395:                Dimension d = getSize();
396:                int b = borderWidth;
397:
398:                // Paints the background if the shape is not a rectangle.
399:                // Rectangles are handled by the superclass' paint method.
400:                if (shape != SHAPE_RECTANGLE) {
401:
402:                    // Prepares the shapes geometries for painting the background
403:                    // and border. This does not do any actual painting but
404:                    // constructs the mathematical diamond shape.
405:                    if (shape == SHAPE_DIAMOND) {
406:                        int width = d.width - b;
407:                        int height = d.height - b;
408:                        int halfWidth = (d.width - b) / 2;
409:                        int halfHeight = (d.height - b) / 2;
410:                        int[] xpoints = { halfWidth, width, halfWidth, 0 };
411:                        int[] ypoints = { 0, halfHeight, height, halfHeight };
412:                        diamond = new Polygon(xpoints, ypoints, 4);
413:                    }
414:
415:                    if (shape == SHAPE_TRIANGLE) {
416:                        int width = d.width - b;
417:                        int height = d.height - b;
418:                        int halfHeight = (d.height - b) / 2;
419:                        int[] xpoints = { 0, width, 0 };
420:                        int[] ypoints = { 0, halfHeight, height };
421:                        diamond = new Polygon(xpoints, ypoints, 3);
422:                    }
423:
424:                    // Computes the area for the cylinder (db-style)
425:                    else if (shape == SHAPE_CYLINDER) {
426:                        int h4 = (int) (d.getHeight() / 4);
427:                        int r = d.width - b - 1;
428:                        cylinderArea = new Area(new Rectangle(b, (h4 - b) / 2
429:                                + b, r, d.height - h4 - b));
430:                        cylinderArea.add(new Area(new Ellipse2D.Double(b, b, r,
431:                                h4 - b)));
432:                        cylinderArea.add(new Area(new Ellipse2D.Double(b,
433:                                d.height - h4 - b, r, h4)));
434:                    }
435:
436:                    // Computes the rounded rect arc for rounded rectangles. This
437:                    // is expensive sothe result is cached.
438:                    else if (shape == SHAPE_ROUNDED)
439:                        roundRectArc = getArcSize(d.width - b, d.height - b);
440:
441:                    // Paints the gradient background or filled background by
442:                    // using the shape geometries created above and the colors
443:                    // that were set in installAttributes.
444:                    if (isOpaque()) {
445:                        g.setColor(super .getBackground());
446:
447:                        // Paints the gradient background only if we're not in
448:                        // preview mode to speedup the previews.
449:                        if (gradientColor != null && !preview)
450:                            ((Graphics2D) g).setPaint(new GradientPaint(0, 0,
451:                                    getBackground(), getWidth(), getHeight(),
452:                                    gradientColor, true));
453:
454:                        // Paints the actual background using the proper shapes.
455:                        // Painting the rectangle background is handled by the
456:                        // superclass' paint method.
457:                        if (shape == SHAPE_CIRCLE)
458:                            g.fillOval(b - 1, b - 1, d.width - b, d.height - b);
459:                        else if (shape == SHAPE_CYLINDER)
460:                            ((Graphics2D) g).fill(cylinderArea);
461:                        else if (shape == SHAPE_DIAMOND
462:                                || shape == SHAPE_TRIANGLE)
463:                            g.fillPolygon(diamond);
464:                        else if (shape == SHAPE_ROUNDED)
465:                            g.fillRoundRect(b / 2, b / 2, d.width
466:                                    - (int) (b * 1.5), d.height
467:                                    - (int) (b * 1.5), roundRectArc,
468:                                    roundRectArc);
469:                    }
470:                }
471:            }
472:
473:            /**
474:             * Utility method to paint the rich text content for rich text values. This
475:             * implementation simulates rich text vertical alignment by translating the
476:             * graphics before painting the textPane.
477:             * 
478:             * @param g
479:             *            The graphics to paint the rich text content to.
480:             */
481:            protected void paintRichText(Graphics g) {
482:                textPane.setSize(getSize());
483:                int yoffset = 0;
484:
485:                // Computes the vertical offset to match the vertical alignment
486:                if (getVerticalAlignment() == CENTER)
487:                    yoffset = (int) ((getHeight() - textPane.getPreferredSize()
488:                            .getHeight()) / 2)
489:                            + 2 * INSET;
490:                else if (getVerticalAlignment() == BOTTOM)
491:                    yoffset = (int) (getHeight()
492:                            - textPane.getPreferredSize().getHeight() + 3 * INSET);
493:                g.translate(0, yoffset);
494:                textPane.paint(g);
495:                g.translate(0, -yoffset);
496:            }
497:
498:            /**
499:             * Utility method to paint the border for all non-rectangular shapes.
500:             * 
501:             * @param g
502:             *            The graphics to paint the border to.
503:             */
504:            protected void paintShapeBorder(Graphics g) {
505:                Dimension d = getSize();
506:                int b = borderWidth;
507:                if (shape == SHAPE_CIRCLE)
508:                    g.drawOval(b - 1, b - 1, d.width - b, d.height - b);
509:                else if (shape == SHAPE_CYLINDER) {
510:                    int h4 = (int) (d.getHeight() / 4);
511:                    int r = d.width - b - 1;
512:                    g.drawOval(b, b, r, h4 - b);
513:                    g.drawLine(b, (h4 - b) / 2 + 2 + b, b, d.height - (h4 - b)
514:                            / 2 - 2 - b);
515:                    g.drawLine(d.width - (b + 1) / 2, (h4 - b) / 2 + 2 + b,
516:                            d.width - (b + 1) / 2, d.height - (h4 - b) / 2 - 2
517:                                    - b);
518:                    g.drawArc(b, d.height - h4 - b, r, h4, 0,
519:                            (isOpaque()) ? -180 : 360);
520:                } else if (shape == SHAPE_DIAMOND || shape == SHAPE_TRIANGLE)
521:                    g.drawPolygon(diamond);
522:                else if (shape == SHAPE_ROUNDED)
523:                    g.drawRoundRect(b / 2, b / 2,
524:                            d.width - (int) (b * 1.5) - 1, d.height
525:                                    - (int) (b * 1.5), roundRectArc,
526:                            roundRectArc);
527:            }
528:
529:            /**
530:             * Utility method to paint the folding icon for groups.
531:             * 
532:             * @param g
533:             *            The graphics to paint the border to.
534:             */
535:            protected void paintFoldingIcon(Graphics g) {
536:                if (isGroup) {
537:                    g.setColor(graphBackground);
538:                    g.fill3DRect(handle.x, handle.y, handle.width,
539:                            handle.height, true);
540:                    g.setColor(graphForeground);
541:                    g.drawRect(handle.x, handle.y, handle.width, handle.height);
542:                    int h2 = handle.y + handle.height / 2;
543:                    g.drawLine(handle.x + 1, h2, handle.x + handle.width - 2,
544:                            h2);
545:                    if (view.isLeaf()) {
546:                        int w2 = handle.x + handle.width / 2;
547:                        g.drawLine(w2, handle.y + 1, w2, handle.y
548:                                + handle.height - 2);
549:                    }
550:                }
551:            }
552:
553:            /**
554:             * Returns an appropriate arc for the corners of the rectangle for boundary
555:             * size cases of width and height. The arc width of a rectangle is 1/5th of
556:             * the larger of the two of the dimensions passed in, but at most 1/2 of the
557:             * smaller of the two. 1/5 because it looks nice and 1/2 so the arc can
558:             * complete in the given dimension
559:             * 
560:             * @param width
561:             *            The width to compute the arc size for.
562:             * @param height
563:             *            The height to compute the arc size for.
564:             * @return Returns the arc size.
565:             */
566:            public static int getArcSize(int width, int height) {
567:                int arcSize;
568:                if (width <= height) {
569:                    arcSize = height / 5;
570:                    if (arcSize > (width / 2))
571:                        arcSize = width / 2;
572:                } else {
573:                    arcSize = width / 5;
574:                    if (arcSize > (height / 2))
575:                        arcSize = height / 2;
576:                }
577:                return arcSize;
578:            }
579:
580:            /**
581:             * Overrides the parent's implementation to return the perimeter points for
582:             * non-rectangular shapes, namely diamonds and circles. The source point is
583:             * typically ignored and the center point is used instead.
584:             * 
585:             * @param view
586:             *            The view to return the perimeter point for.
587:             * @param source
588:             *            The location of the start point of the line to be intersected
589:             *            with the boundaries.
590:             * @param p
591:             *            The location of the end point of the line to be intersected
592:             *            with the boundaries.
593:             */
594:            public Point2D getPerimeterPoint(VertexView view, Point2D source,
595:                    Point2D p) {
596:                int shape = JGraphpadGraphConstants.getVertexShape(view
597:                        .getAllAttributes());
598:                if (shape == SHAPE_DIAMOND) {
599:                    return getDiamondPerimeterPoint(view, source, p);
600:                } else if (shape == SHAPE_CIRCLE) {
601:                    return getCirclePerimeterPoint(view, source, p);
602:                } else if (shape == SHAPE_TRIANGLE) {
603:                    return getTrianglePerimeterPoint(view, source, p);
604:                }
605:                return super .getPerimeterPoint(view, source, p);
606:            }
607:
608:            /**
609:             * Utility method to return the perimeter point for a circle.
610:             * 
611:             * @param view
612:             *            The view that defines the bounds of the circle.
613:             * @param source
614:             *            The start point of theline to intersect with the circle.
615:             * @param p
616:             *            The end point of the line to intersect with the circle.
617:             * @return The interaction of the circle and the line between source and p.
618:             */
619:            public Point2D getCirclePerimeterPoint(VertexView view,
620:                    Point2D source, Point2D p) {
621:                Rectangle2D r = view.getBounds();
622:
623:                double x = r.getX();
624:                double y = r.getY();
625:                double a = (r.getWidth() + 1) / 2;
626:                double b = (r.getHeight() + 1) / 2;
627:
628:                // x0,y0 - center of ellipse
629:                double x0 = x + a;
630:                double y0 = y + b;
631:
632:                // x1, y1 - point
633:                double x1 = p.getX();
634:                double y1 = p.getY();
635:
636:                // Calculates straight line equation through point and ellipse center
637:                // y = d * x + h
638:                double dx = x1 - x0;
639:                double dy = y1 - y0;
640:
641:                if (dx == 0)
642:                    return new Point((int) x0, (int) (y0 + b * dy
643:                            / Math.abs(dy)));
644:
645:                double d = dy / dx;
646:                double h = y0 - d * x0;
647:
648:                // Calculates intersection
649:                double e = a * a * d * d + b * b;
650:                double f = -2 * x0 * e;
651:                double g = a * a * d * d * x0 * x0 + b * b * x0 * x0 - a * a
652:                        * b * b;
653:
654:                double det = Math.sqrt(f * f - 4 * e * g);
655:
656:                // Two solutions (perimeter points)
657:                double xout1 = (-f + det) / (2 * e);
658:                double xout2 = (-f - det) / (2 * e);
659:                double yout1 = d * xout1 + h;
660:                double yout2 = d * xout2 + h;
661:
662:                double dist1 = Math.sqrt(Math.pow((xout1 - x1), 2)
663:                        + Math.pow((yout1 - y1), 2));
664:                double dist2 = Math.sqrt(Math.pow((xout2 - x1), 2)
665:                        + Math.pow((yout2 - y1), 2));
666:
667:                // Correct solution
668:                double xout, yout;
669:
670:                if (dist1 < dist2) {
671:                    xout = xout1;
672:                    yout = yout1;
673:                } else {
674:                    xout = xout2;
675:                    yout = yout2;
676:                }
677:
678:                return new Point2D.Double(xout, yout);
679:            }
680:
681:            /**
682:             * Utility method to return the perimeter point for a diamond.
683:             * 
684:             * @param view
685:             *            The view that defines the bounds of the diamond.
686:             * @param source
687:             *            The start point of theline to intersect with the diamond.
688:             * @param p
689:             *            The end point of the line to intersect with the diamond.
690:             * @return The interaction of the diamond and the line between source and p.
691:             */
692:            public Point2D getDiamondPerimeterPoint(VertexView view,
693:                    Point2D source, Point2D p) {
694:                Rectangle2D bounds = view.getBounds();
695:                Point2D center = AbstractCellView.getCenterPoint(view);
696:                double halfwidth = bounds.getWidth() / 2;
697:                double halfheight = bounds.getHeight() / 2;
698:                Point2D top = new Point2D.Double(center.getX(), center.getY()
699:                        - halfheight);
700:                Point2D bottom = new Point2D.Double(center.getX(), center
701:                        .getY()
702:                        + halfheight);
703:                Point2D left = new Point2D.Double(center.getX() - halfwidth,
704:                        center.getY());
705:                Point2D right = new Point2D.Double(center.getX() + halfwidth,
706:                        center.getY());
707:
708:                // Special case for intersecting the diamond's points
709:                if (center.getX() == p.getX())
710:                    if (center.getY() > p.getY()) // top point
711:                        return (top);
712:                    else
713:                        return (bottom); // bottom point
714:                if (center.getY() == p.getY())
715:                    if (center.getX() > p.getX()) // left point
716:                        return (left);
717:                    else
718:                        return (right); // right point
719:
720:                // In which quadrant will the intersection be?
721:                // set the slope and offset of the border line accordingly
722:                Point2D i;
723:                if (p.getX() < center.getX())
724:                    if (p.getY() < center.getY())
725:                        i = intersection(p, center, top, left);
726:                    else
727:                        i = intersection(p, center, bottom, left);
728:                else if (p.getY() < center.getY())
729:                    i = intersection(p, center, top, right);
730:                else
731:                    i = intersection(p, center, bottom, right);
732:                return i;
733:            }
734:
735:            /**
736:             * Utility method to return the perimeter point for a triangle.
737:             * 
738:             * @param view
739:             *            The view that defines the bounds of the diamond.
740:             * @param source
741:             *            The start point of theline to intersect with the diamond.
742:             * @param p
743:             *            The end point of the line to intersect with the diamond.
744:             * @return The interaction of the diamond and the line between source and p.
745:             */
746:            public Point2D getTrianglePerimeterPoint(VertexView view,
747:                    Point2D source, Point2D p) {
748:                Rectangle2D bounds = view.getBounds();
749:
750:                double x = bounds.getX();
751:                double y = bounds.getY();
752:                double width = bounds.getWidth();
753:                double height = bounds.getHeight();
754:                double xCenter = x + width / 2;
755:                double yCenter = y + height / 2;
756:                Point2D center = AbstractCellView.getCenterPoint(view);
757:                Point2D top = new Point2D.Double(x, y);
758:                Point2D bottom = new Point2D.Double(x, y + height);
759:                Point2D right = new Point2D.Double(x + width, yCenter);
760:
761:                // Compute angle
762:                double dx = p.getX() - xCenter;
763:                double dy = p.getY() - yCenter;
764:                double alpha = Math.atan2(dy, dx);
765:                double t = Math.atan2(height, width);
766:                Point2D i;
767:                if (alpha < -Math.PI + t || alpha > Math.PI - t) { // Left edge
768:                    i = new Point2D.Double(x, yCenter - width * Math.tan(alpha)
769:                            / 2);
770:                } else if (yCenter > p.getY()) { // Top Slope
771:                    i = intersection(p, center, top, right);
772:                } else { // Bottom Slope
773:                    i = intersection(p, center, bottom, right);
774:                }
775:                return i;
776:            }
777:
778:            /**
779:             * Find the point of intersection of two straight lines (which follow the
780:             * equation y=mx+b) one line is an incoming edge and the other is one side
781:             * of the diamond.
782:             * 
783:             * @param lineOneStart
784:             *            The start point of the first line.
785:             * @param lineOneEnd
786:             *            The end point of the first line.
787:             * @param lineTwoStart
788:             *            The start point of the second line.
789:             * @param lineTwoEnd
790:             *            The end point of the second line.
791:             * @return Returns the intersection point between the first and the second
792:             *         line.
793:             */
794:            protected Point2D intersection(Point2D lineOneStart,
795:                    Point2D lineOneEnd, Point2D lineTwoStart, Point2D lineTwoEnd) {
796:                // m = delta y / delta x, the slope of a line
797:                // b = y - mx, the axis intercept
798:                double m1 = (double) (lineOneEnd.getY() - lineOneStart.getY())
799:                        / (double) (lineOneEnd.getX() - lineOneStart.getX());
800:                double b1 = lineOneStart.getY() - m1 * lineOneStart.getX();
801:                double m2 = (double) (lineTwoEnd.getY() - lineTwoStart.getY())
802:                        / (double) (lineTwoEnd.getX() - lineTwoStart.getX());
803:                double b2 = lineTwoStart.getY() - m2 * lineTwoStart.getX();
804:                double xinter = (b1 - b2) / (m2 - m1);
805:                double yinter = m1 * xinter + b1;
806:                Point2D intersection = new Point2D.Double(xinter, yinter);
807:                return intersection;
808:            }
809:
810:            /**
811:             * Overrides the parent's implementation to return a slightly larger
812:             * preferred size for circles and rounded rectangles.
813:             * 
814:             * @return Returns the preferreds size for the current view.
815:             */
816:            public Dimension getPreferredSize() {
817:                Dimension d = super .getPreferredSize();
818:                if (shape == SHAPE_CIRCLE) {
819:                    d.width += d.width / 8;
820:                    d.height += d.height / 2;
821:                } else if (shape == SHAPE_ROUNDED)
822:                    d.width += d.height / 5;
823:                else if (isRichText) {
824:                    textPane.setSize(ZERO_DIMENSION);
825:                    return textPane.getPreferredSize();
826:                } else if (valueComponent != null)
827:                    return valueComponent.getPreferredSize();
828:                return d;
829:            }
830:
831:            /**
832:             * Resets attributes that would affect rendering if the
833:             * {@link #installAttributes(CellView)} is not being called, which is the
834:             * case if the view is a group and it's groupOpaque attribute is set to
835:             * false.
836:             */
837:            protected void resetAttributes() {
838:                super .resetAttributes();
839:                shape = JGraphpadGraphConstants.getVertexShape(view
840:                        .getAllAttributes());
841:                isRichText = false;
842:                valueComponent = null;
843:            }
844:
845:            /**
846:             * Extends the parent's method to configure the renderer for displaying the
847:             * specified view.
848:             * 
849:             * @param view
850:             *            The view to configure the renderer for.
851:             */
852:            public void installAttributes(CellView view) {
853:                super .installAttributes(view);
854:                Map map = view.getAllAttributes();
855:                shape = JGraphpadGraphConstants.getVertexShape(view
856:                        .getAllAttributes());
857:                stretchImage = JGraphpadGraphConstants.isStretchImage(map);
858:
859:                // Adds the inset as an empty border to the existing border.
860:                int i = GraphConstants.getInset(map);
861:                Border insetBorder = (i > 0) ? BorderFactory.createEmptyBorder(
862:                        i, i, i, i) : null;
863:                if (insetBorder != null) {
864:                    if (getBorder() == null)
865:                        setBorder(insetBorder);
866:                    else
867:                        setBorder(BorderFactory.createCompoundBorder(
868:                                getBorder(), insetBorder));
869:                }
870:
871:                // Configures the rich text or component value
872:                userObject = graph.getModel().getValue(view.getCell());
873:                if (userObject instanceof  JGraphpadBusinessObject) {
874:                    JGraphpadBusinessObject obj = (JGraphpadBusinessObject) userObject;
875:                    isRichText = obj.isRichText();
876:                    valueComponent = (obj.isComponent()) ? (Component) obj
877:                            .getValue() : null;
878:                } else {
879:                    isRichText = false;
880:                    valueComponent = null;
881:                }
882:
883:                // Configures the rich text box for rendering the rich text
884:                if (isRichText) {
885:                    StyledDocument document = (StyledDocument) textPane
886:                            .getDocument();
887:                    ((JGraphpadRichTextValue) ((JGraphpadBusinessObject) userObject)
888:                            .getValue()).insertInto(document);
889:
890:                    // Applies the inset to the rich text renderer
891:                    if (insetBorder != null)
892:                        textPane.setBorder(insetBorder);
893:                    else
894:                        textPane.setBorder(BorderFactory.createEmptyBorder(
895:                                INSET, INSET, INSET, INSET));
896:
897:                    // Uses the label's alignment and sets it on the text pane to work
898:                    // around the problem of the text pane alignments not being stored.
899:                    // Note: As a consequence a text pane can only have one alignment
900:                    // for all text it contains. It is not possible to align the
901:                    // paragraphs individually.
902:                    int align = getHorizontalAlignment();
903:                    SimpleAttributeSet sas = new SimpleAttributeSet();
904:                    align = (align == JLabel.CENTER) ? StyleConstants.ALIGN_CENTER
905:                            : (align == JLabel.RIGHT) ? StyleConstants.ALIGN_RIGHT
906:                                    : StyleConstants.ALIGN_LEFT;
907:                    StyleConstants.setAlignment(sas, align);
908:                    document.setParagraphAttributes(0, document.getLength(),
909:                            sas, true);
910:                }
911:            }
912:
913:            /**
914:             * Detects whether or not a point has hit the folding icon. This
915:             * implementation never returns true if the
916:             * {@link #CLIENTPROPERTY_SHOWFOLDINGICONS} is not set on the enclosing
917:             * graph.
918:             * 
919:             * @param pt
920:             *            The point to check
921:             * @return Returns true if <code>pt</code> intersects with the folding
922:             *         icon.
923:             */
924:            public boolean inHitRegion(Point2D pt) {
925:                if (showFoldingIcons)
926:                    return handle.contains(Math.max(0, pt.getX() - 1), Math
927:                            .max(0, pt.getY() - 1));
928:                return false;
929:            }
930:
931:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.