Source Code Cross Referenced for JGraph.java in  » Graphic-Library » jgraph » org » jgraph » 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 » jgraph » org.jgraph 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * @(#)JGraph.java
0003:         *
0004:         * Copyright (c) 2001-2006 Gaudenz Alder
0005:         *
0006:         */
0007:        package org.jgraph;
0008:
0009:        import java.awt.AlphaComposite;
0010:        import java.awt.Color;
0011:        import java.awt.Component;
0012:        import java.awt.Dimension;
0013:        import java.awt.Font;
0014:        import java.awt.Graphics;
0015:        import java.awt.Graphics2D;
0016:        import java.awt.GraphicsConfiguration;
0017:        import java.awt.Image;
0018:        import java.awt.Rectangle;
0019:        import java.awt.Transparency;
0020:        import java.awt.event.MouseEvent;
0021:        import java.awt.geom.Dimension2D;
0022:        import java.awt.geom.Point2D;
0023:        import java.awt.geom.Rectangle2D;
0024:        import java.awt.image.BufferedImage;
0025:        import java.awt.image.VolatileImage;
0026:        import java.io.IOException;
0027:        import java.io.ObjectInputStream;
0028:        import java.io.ObjectOutputStream;
0029:        import java.io.Serializable;
0030:        import java.util.ArrayList;
0031:        import java.util.Hashtable;
0032:        import java.util.List;
0033:        import java.util.Map;
0034:        import java.util.Vector;
0035:
0036:        import javax.accessibility.Accessible;
0037:        import javax.swing.BorderFactory;
0038:        import javax.swing.ImageIcon;
0039:        import javax.swing.JComponent;
0040:        import javax.swing.JViewport;
0041:        import javax.swing.Scrollable;
0042:        import javax.swing.SwingConstants;
0043:
0044:        import org.jgraph.event.GraphSelectionEvent;
0045:        import org.jgraph.event.GraphSelectionListener;
0046:        import org.jgraph.graph.AbstractCellView;
0047:        import org.jgraph.graph.AttributeMap;
0048:        import org.jgraph.graph.BasicMarqueeHandler;
0049:        import org.jgraph.graph.CellView;
0050:        import org.jgraph.graph.ConnectionSet;
0051:        import org.jgraph.graph.DefaultCellViewFactory;
0052:        import org.jgraph.graph.DefaultEdge;
0053:        import org.jgraph.graph.DefaultGraphCell;
0054:        import org.jgraph.graph.DefaultGraphModel;
0055:        import org.jgraph.graph.DefaultGraphSelectionModel;
0056:        import org.jgraph.graph.GraphConstants;
0057:        import org.jgraph.graph.GraphLayoutCache;
0058:        import org.jgraph.graph.GraphModel;
0059:        import org.jgraph.graph.GraphSelectionModel;
0060:        import org.jgraph.graph.PortView;
0061:        import org.jgraph.plaf.GraphUI;
0062:        import org.jgraph.plaf.basic.BasicGraphUI;
0063:
0064:        /**
0065:         * A control that displays a network of related objects using the well-known
0066:         * paradigm of a graph.
0067:         * <p>
0068:         * A JGraph object doesn't actually contain your data; it simply provides a view
0069:         * of the data. Like any non-trivial Swing component, the graph gets data by
0070:         * querying its data model.
0071:         * <p>
0072:         * JGraph displays its data by drawing individual elements. Each element
0073:         * displayed by the graph contains exactly one item of data, which is called a
0074:         * cell. A cell may either be a vertex or an edge. Vertices may have neighbours
0075:         * or not, and edges may have source and target vertices or not, depending on
0076:         * whether they are connected.
0077:         * <p>
0078:         * <strong>Creating a Graph </strong>
0079:         * <p>
0080:         * The following code creates a JGraph object:
0081:         * <p>
0082:         * JGraph graph = new JGraph(); <br>
0083:         * ... <br>
0084:         * JScrollPane graphLayoutCache = new JScrollPane(graph)
0085:         * <p>
0086:         * The code creates an instance of JGraph and puts it in a scroll pane. JGraphs
0087:         * constructor is called with no arguments in this example, which causes the
0088:         * constructor to create a sample model.
0089:         * <p>
0090:         * <strong>Editing </strong>
0091:         * <p>
0092:         * Outmoved, cloned, resized, and shaped, or connected/disconnected to or from
0093:         * other cells.
0094:         * <p>
0095:         * <strong>Keyboard Bindings </strong>
0096:         * <p>
0097:         * JGraph defines the following set of keyboard bindings:
0098:         * <p>
0099:         * <ul>
0100:         * <li>Alt-Click forces marquee selection if over a cell.
0101:         * <li>Shift- or Ctrl-Select extends or toggles the selection.
0102:         * <li>Shift-Drag constrains the offset to one direction.
0103:         * <li>Ctrl-Drag clones the selection.
0104:         * <li>Doubleclick/F2 starts editing a cell.
0105:         * </ul>
0106:         * You can change the number of clicks that triggers editing using
0107:         * setEditClickCount().
0108:         * <p>
0109:         * <strong>Customization </strong>
0110:         * <p>
0111:         * There are a number of additional methods that customize JGraph. For example,
0112:         * setMinimumMove() defines the minimum amount of pixels before a move operation
0113:         * is initiated. setSnapSize() defines the maximum distance for a cell to be
0114:         * selected. setFloatEnabled() enables/disables port floating.
0115:         * <p>
0116:         * With setDisconnectOnMove() you can indicate if the selected subgraph should
0117:         * be disconnected from the unselected rest when a move operation is initiated.
0118:         * setDragEnabled() enables/disables the use of Drag And Drop, and
0119:         * setDropEnabled() sets if the graph accepts Drops from external sources.
0120:         * <p>
0121:         * <strong>Customizing a graphs display </strong>
0122:         * <p>
0123:         * JGraph performs some look-and-feel specific painting. You can customize this
0124:         * painting in a limited way. For example, you can modify the grid using
0125:         * setGridColor() and setGridSize(), and you can change the handle colors using
0126:         * setHandleColor() and setLockedHandleColor().
0127:         * <p>
0128:         * If you want finer control over the rendering, you can subclass one of the
0129:         * default renderers, and extend its paint()-method. A renderer is a
0130:         * Component-extension that paints a cell based on its attributes. Thus, neither
0131:         * the JGraph nor its look-and-feel-specific implementation actually contain the
0132:         * code that paints the cell. Instead, the graph uses the cell renderers
0133:         * painting code.
0134:         * <p>
0135:         * <strong>Selection </strong>
0136:         * <p>
0137:         * Apart from the single-cell and marquee-selection, JGraphs selection model
0138:         * also allows to "step-into" groups, and select children. This feature can be
0139:         * disabled using the setAllowsChildSelection() method of the selection model
0140:         * instance.
0141:         * <p>
0142:         * If you are interested in knowing when the selection changes implement the
0143:         * <code>GraphSelectionListener</code> interface and add the instance using
0144:         * the method <code>addGraphSelectionListener</code>.
0145:         * <code>valueChanged</code> will be invoked when the selection changes, that
0146:         * is if the user clicks twice on the same vertex <code>valueChanged</code>
0147:         * will only be invoked once.
0148:         * <p>
0149:         * <strong>Change Notification </strong>
0150:         * <p>
0151:         * For detection of double-clicks or when a user clicks on a cell, regardless of
0152:         * whether or not it was selected, I recommend you implement a MouseListener and
0153:         * use <code>getFirstCellForLocation</code>.
0154:         * <p>
0155:         * <strong>Undo Support </strong>
0156:         * <p>
0157:         * To enable Undo-Support, a <code>GraphUndoManager</code> must be added using
0158:         * <code>addGraphSelectionListener</code>. The GraphUndoManager is an
0159:         * extension of Swing's <code>GraphUndoManager</code> that maintains a command
0160:         * history in the context of multiple views. In this setup, a cell may have a
0161:         * set of attributes in each view attached to the model.
0162:         * <p>
0163:         * For example, consider a position that is stored separately in each view. If a
0164:         * node is inserted, the change will be visible in all attached views, resulting
0165:         * in a new node that pops-up at the initial position. If the node is
0166:         * subsequently moved, say, in view1, this does not constitute a change in
0167:         * view2. If view2 does an "undo", the move <i>and </i> the insertion must be
0168:         * undone, whereas an "undo" in view1 will only undo the previous move
0169:         * operation.
0170:         * <p>
0171:         * Like all <code>JComponent</code> classes, you can use
0172:         * {@link javax.swing.InputMap}and {@link javax.swing.ActionMap}to associate
0173:         * an {@link javax.swing.Action}object with a {@link javax.swing.KeyStroke}and
0174:         * execute the action under specified conditions.
0175:         * 
0176:         * @author Gaudenz Alder
0177:         * @version 2.1 16/03/03
0178:         * 
0179:         */
0180:        public class JGraph
0181:        //DO NOT REMOVE OR MODIFY THIS LINE!
0182:                extends JComponent // JAVA13:
0183:                // org.jgraph.plaf.basic.TransferHandler.JAdapterComponent
0184:                implements  Scrollable, Accessible, Serializable {
0185:
0186:            public static final String VERSION = "JGraph (v5.10.1.5)";
0187:
0188:            public static final int DOT_GRID_MODE = 0;
0189:
0190:            public static final int CROSS_GRID_MODE = 1;
0191:
0192:            public static final int LINE_GRID_MODE = 2;
0193:
0194:            // Turn off XOR painting on MACs since it doesn't work
0195:            public static boolean IS_MAC = false;
0196:
0197:            static {
0198:                try {
0199:                    String osName = System.getProperty("os.name");
0200:                    if (osName != null) {
0201:                        IS_MAC = osName.toLowerCase().startsWith("mac os x");
0202:                    }
0203:                    String javaVersion = System.getProperty("java.version");
0204:                    if (javaVersion.startsWith("1.4")
0205:                            || javaVersion.startsWith("1.5")) {
0206:                        // TODO different double buffering for 1.6 JVM?
0207:                    }
0208:                } catch (Exception e) {
0209:                    // ignore
0210:                }
0211:            }
0212:
0213:            /**
0214:             * @see #getUIClassID
0215:             * @see #readObject
0216:             */
0217:            private static final String uiClassID = "GraphUI";
0218:
0219:            /** Creates a new event and passes it off the <code>selectionListeners</code>. */
0220:            protected transient GraphSelectionRedirector selectionRedirector;
0221:
0222:            //
0223:            // Bound Properties
0224:            //
0225:            /**
0226:             * The model that defines the graph displayed by this object. Bound
0227:             * property.
0228:             */
0229:            transient protected GraphModel graphModel;
0230:
0231:            /**
0232:             * The view that defines the display properties of the model. Bound
0233:             * property.
0234:             */
0235:            transient protected GraphLayoutCache graphLayoutCache;
0236:
0237:            /** Models the set of selected objects in this graph. Bound property. */
0238:            transient protected GraphSelectionModel selectionModel;
0239:
0240:            /** Handler for marquee selection. */
0241:            transient protected BasicMarqueeHandler marquee;
0242:
0243:            /** Off screen image for double buffering */
0244:            protected transient Image offscreen;
0245:
0246:            /** Whether or not the current background image is correct */
0247:            protected transient boolean offscreenValid = false;
0248:
0249:            /** The bounds of the offscreen buffer */
0250:            protected transient Rectangle2D offscreenBounds;
0251:
0252:            /** The offset of the offscreen buffer */
0253:            protected transient Point2D offscreenOffset;
0254:
0255:            /** Graphics object of off screen image */
0256:            protected transient Graphics offgraphics;
0257:
0258:            /**
0259:             * The buffer around the offscreen graphics object that provides the
0260:             * specified distance of scrolling before the buffer has to be redrawn.
0261:             * Increasing the value means fewer redraws but more memory is required.
0262:             */
0263:            protected transient int offscreenBuffer = 0;
0264:
0265:            /**
0266:             * Whether or not to try to use a volatile offscreen buffer for double
0267:             * buffering. Volatile 
0268:             */
0269:            protected boolean volatileOffscreen = false;
0270:
0271:            /** Holds the background image. */
0272:            protected ImageIcon backgroundImage;
0273:
0274:            /** A Component responsible for drawing the background image, if any */
0275:            protected Component backgroundComponent;
0276:
0277:            /** Whether or not the background image is scaled on zooming */
0278:            protected boolean backgroundScaled = true;
0279:
0280:            /** Scale of the graph. Default is 1. Bound property. */
0281:            protected double scale = 1.0;
0282:
0283:            /** True if the graph is anti-aliased. Default is false. Bound property. */
0284:            protected boolean antiAliased = false;
0285:
0286:            /** True if the graph allows editing the value of a cell. Bound property. */
0287:            protected boolean editable = true;
0288:
0289:            /** True if the graph allows editing of non-leaf cells. Bound property. */
0290:            protected boolean groupsEditable = false;
0291:
0292:            /**
0293:             * True if the graph allows selection of cells. Note: You must also disable
0294:             * selectNewCells if you disable this. Bound property.
0295:             */
0296:            protected boolean selectionEnabled = true;
0297:
0298:            /**
0299:             * True if the graph allows invalid null ports during previews (aka flip
0300:             * back edges). Default is true.
0301:             */
0302:            protected boolean previewInvalidNullPorts = true;
0303:
0304:            /** True if the grid is visible. Bound property. */
0305:            protected boolean gridVisible = false;
0306:
0307:            /** The size of the grid in points. Default is 10. Bound property. */
0308:            protected double gridSize = 10;
0309:
0310:            /** The style of the grid. Use one of the _GRID_MODE constants. */
0311:            protected int gridMode = DOT_GRID_MODE;
0312:
0313:            /** True if the ports are visible. Bound property. */
0314:            protected boolean portsVisible = false;
0315:
0316:            /** True if the ports are scaled. Bound property. */
0317:            protected boolean portsScaled = true;
0318:
0319:            /** True if the graph allows to move cells below zero. */
0320:            protected boolean moveBelowZero = false;
0321:
0322:            /** True if the graph allows to move cells beyond the graph bounds */
0323:            protected boolean moveBeyondGraphBounds = true;
0324:
0325:            /** True if the labels on edges may be moved. */
0326:            protected boolean edgeLabelsMovable = true;
0327:
0328:            /**
0329:             * True if the graph should be auto resized when cells are moved below the
0330:             * bottom right corner. Default is true.
0331:             */
0332:            protected boolean autoResizeGraph = true;
0333:
0334:            //
0335:            // Look-And-Feel dependent
0336:            //
0337:            /** Highlight Color. Changes when the Look-and-Feel changes. */
0338:            protected Color highlightColor = Color.green;
0339:
0340:            /**
0341:             * Color of the handles and locked handles. Changes when the Look-and-Feel
0342:             * changes.
0343:             */
0344:            protected Color handleColor, lockedHandleColor;
0345:
0346:            /** Color of the marquee. Changes when the Look-and-Feel changes. */
0347:            protected Color marqueeColor;
0348:
0349:            /** The color of the grid. Changes when the Look-and-Feel changes. */
0350:            protected Color gridColor;
0351:
0352:            //
0353:            // Datatransfer
0354:            //
0355:            /**
0356:             * True if Drag-and-Drop should be used for move operations. Default is
0357:             * false due to a JDK bug.
0358:             */
0359:            protected boolean dragEnabled = false;
0360:
0361:            /**
0362:             * True if the graph accepts transfers from other components (graphs). This
0363:             * also affects the clipboard. Default is true.
0364:             */
0365:            protected boolean dropEnabled = true;
0366:
0367:            /**
0368:             * True if the graph accepts transfers from other components (graphs). This
0369:             * also affects the clipboard. Default is true.
0370:             */
0371:            protected boolean xorEnabled = !IS_MAC;
0372:
0373:            //
0374:            // Unbound Properties
0375:            //
0376:            /** Number of clicks for editing to start. Default is 2 clicks. */
0377:            protected int editClickCount = 2;
0378:
0379:            /** True if the graph allows interactions. Default is true. */
0380:            protected boolean enabled = true;
0381:
0382:            /** True if the snap method should be active (snap to grid). */
0383:            protected boolean gridEnabled = false;
0384:
0385:            /** Size of a handle. Default is 3 pixels. */
0386:            protected int handleSize = 3;
0387:
0388:            /** Maximum distance between a cell and the mousepointer. Default is 4. */
0389:            protected int tolerance = 4;
0390:
0391:            /** Minimum amount of pixels to start a move transaction. Default is 5. */
0392:            protected int minimumMove = 5;
0393:
0394:            /**
0395:             * True if getPortViewAt should return the default port if no other port is
0396:             * found. Default is false.
0397:             */
0398:            protected boolean isJumpToDefaultPort = false;
0399:
0400:            /**
0401:             * Specifies if cells should be added to a group when moved over the group's
0402:             * area. Default is false.
0403:             */
0404:            protected boolean isMoveIntoGroups = false;
0405:
0406:            /**
0407:             * Specifies if cells should be removed from groups when removed from the
0408:             * group area. Default is false.
0409:             */
0410:            protected boolean isMoveOutOfGroups = false;
0411:
0412:            /**
0413:             * True if selected edges are disconnected from unselected vertices on move.
0414:             * Default is false.
0415:             */
0416:            protected boolean disconnectOnMove = false;
0417:
0418:            /** True if the graph allows move operations. Default is true. */
0419:            protected boolean moveable = true;
0420:
0421:            /** True if the graph allows "ctrl-drag" operations. Default is false. */
0422:            protected boolean cloneable = false;
0423:
0424:            /** True if the graph allows cells to be resized. Default is true. */
0425:            protected boolean sizeable = true;
0426:
0427:            /**
0428:             * True if the graph allows points to be modified/added/removed. Default is
0429:             * true.
0430:             */
0431:            protected boolean bendable = true;
0432:
0433:            /**
0434:             * True if the graph allows new connections to be established. Default is
0435:             * true.
0436:             */
0437:            protected boolean connectable = true;
0438:
0439:            /**
0440:             * True if the graph allows existing connections to be removed. Default is
0441:             * true.
0442:             */
0443:            protected boolean disconnectable = true;
0444:
0445:            /**
0446:             * If true, when editing is to be stopped by way of selection changing, data
0447:             * in graph changing or other means <code>stopCellEditing</code> is
0448:             * invoked, and changes are saved. If false, <code>cancelCellEditing</code>
0449:             * is invoked, and changes are discarded.
0450:             */
0451:            protected boolean invokesStopCellEditing;
0452:
0453:            //
0454:            // Bound propery names
0455:            //
0456:            /**
0457:             * Bound property name for <code>graphModel</code>.
0458:             */
0459:            public final static String GRAPH_MODEL_PROPERTY = "model";
0460:
0461:            /**
0462:             * Bound property name for <code>graphModel</code>.
0463:             */
0464:            public final static String GRAPH_LAYOUT_CACHE_PROPERTY = "view";
0465:
0466:            /**
0467:             * Bound property name for <code>graphModel</code>.
0468:             */
0469:            public final static String MARQUEE_HANDLER_PROPERTY = "marquee";
0470:
0471:            /**
0472:             * Bound property name for <code>editable</code>.
0473:             */
0474:            public final static String EDITABLE_PROPERTY = "editable";
0475:
0476:            /**
0477:             * Bound property name for <code>selectionEnabled</code>.
0478:             */
0479:            public final static String SELECTIONENABLED_PROPERTY = "selectionEnabled";
0480:
0481:            /**
0482:             * Bound property name for <code>scale</code>.
0483:             */
0484:            public final static String SCALE_PROPERTY = "scale";
0485:
0486:            /**
0487:             * Bound property name for <code>antiAliased</code>.
0488:             */
0489:            public final static String ANTIALIASED_PROPERTY = "antiAliased";
0490:
0491:            /**
0492:             * Bound property name for <code>gridSize</code>.
0493:             */
0494:            public final static String GRID_SIZE_PROPERTY = "gridSize";
0495:
0496:            /**
0497:             * Bound property name for <code>gridVisible</code>.
0498:             */
0499:            public final static String GRID_VISIBLE_PROPERTY = "gridVisible";
0500:
0501:            /**
0502:             * Bound property name for <code>gridColor</code>.
0503:             */
0504:            public final static String GRID_COLOR_PROPERTY = "gridColor";
0505:
0506:            /**
0507:             * Bound property name for <code>gridColor</code>.
0508:             */
0509:            public final static String HANDLE_COLOR_PROPERTY = "handleColor";
0510:
0511:            /**
0512:             * Bound property name for <code>gridColor</code>.
0513:             */
0514:            public final static String HANDLE_SIZE_PROPERTY = "handleSize";
0515:
0516:            /**
0517:             * Bound property name for <code>gridColor</code>.
0518:             */
0519:            public final static String LOCKED_HANDLE_COLOR_PROPERTY = "lockedHandleColor";
0520:
0521:            /**
0522:             * Bound property name for <code>gridVisible</code>.
0523:             */
0524:            public final static String PORTS_VISIBLE_PROPERTY = "portsVisible";
0525:
0526:            /**
0527:             * Bound property name for <code>portsScaled</code>.
0528:             */
0529:            public final static String PORTS_SCALED_PROPERTY = "portsScaled";
0530:
0531:            /**
0532:             * Bound property name for <code>selectionModel</code>.
0533:             */
0534:            public final static String SELECTION_MODEL_PROPERTY = "selectionModel";
0535:
0536:            /**
0537:             * Bound property name for <code>messagesStopCellEditing</code>.
0538:             */
0539:            public final static String INVOKES_STOP_CELL_EDITING_PROPERTY = "invokesStopCellEditing";
0540:
0541:            /**
0542:             * Bound property name for <code>backgroundImage</code>.
0543:             */
0544:            public final static String PROPERTY_BACKGROUNDIMAGE = "backgroundImage";
0545:
0546:            /**
0547:             * Creates and returns a sample <code>GraphModel</code>. Used primarily
0548:             * for beanbuilders to show something interesting.
0549:             */
0550:            public static void addSampleData(GraphModel model) {
0551:                ConnectionSet cs = new ConnectionSet();
0552:                Map attributes = new Hashtable();
0553:                // Styles For Implement/Extend/Aggregation
0554:                AttributeMap implementStyle = new AttributeMap();
0555:                GraphConstants.setLineBegin(implementStyle,
0556:                        GraphConstants.ARROW_TECHNICAL);
0557:                GraphConstants.setBeginSize(implementStyle, 10);
0558:                GraphConstants.setDashPattern(implementStyle, new float[] { 3,
0559:                        3 });
0560:                if (GraphConstants.DEFAULTFONT != null) {
0561:                    GraphConstants.setFont(implementStyle,
0562:                            GraphConstants.DEFAULTFONT.deriveFont(10));
0563:                }
0564:                AttributeMap extendStyle = new AttributeMap();
0565:                GraphConstants.setLineBegin(extendStyle,
0566:                        GraphConstants.ARROW_TECHNICAL);
0567:                GraphConstants.setBeginFill(extendStyle, true);
0568:                GraphConstants.setBeginSize(extendStyle, 10);
0569:                if (GraphConstants.DEFAULTFONT != null) {
0570:                    GraphConstants.setFont(extendStyle,
0571:                            GraphConstants.DEFAULTFONT.deriveFont(10));
0572:                }
0573:                AttributeMap aggregateStyle = new AttributeMap();
0574:                GraphConstants.setLineBegin(aggregateStyle,
0575:                        GraphConstants.ARROW_DIAMOND);
0576:                GraphConstants.setBeginFill(aggregateStyle, true);
0577:                GraphConstants.setBeginSize(aggregateStyle, 6);
0578:                GraphConstants.setLineEnd(aggregateStyle,
0579:                        GraphConstants.ARROW_SIMPLE);
0580:                GraphConstants.setEndSize(aggregateStyle, 8);
0581:                GraphConstants.setLabelPosition(aggregateStyle,
0582:                        new Point2D.Double(500, 0));
0583:                if (GraphConstants.DEFAULTFONT != null) {
0584:                    GraphConstants.setFont(aggregateStyle,
0585:                            GraphConstants.DEFAULTFONT.deriveFont(10));
0586:                }
0587:                //
0588:                // The Swing MVC Pattern
0589:                //
0590:                // Model Column
0591:                DefaultGraphCell gm = new DefaultGraphCell("GraphModel");
0592:                attributes.put(gm, createBounds(new AttributeMap(), 20, 100,
0593:                        Color.blue));
0594:                gm.addPort(null, "GraphModel/Center");
0595:                DefaultGraphCell dgm = new DefaultGraphCell("DefaultGraphModel");
0596:                attributes.put(dgm, createBounds(new AttributeMap(), 20, 180,
0597:                        Color.blue));
0598:                dgm.addPort(null, "DefaultGraphModel/Center");
0599:                DefaultEdge dgmImplementsGm = new DefaultEdge("implements");
0600:                cs
0601:                        .connect(dgmImplementsGm, gm.getChildAt(0), dgm
0602:                                .getChildAt(0));
0603:                attributes.put(dgmImplementsGm, implementStyle);
0604:                DefaultGraphCell modelGroup = new DefaultGraphCell("ModelGroup");
0605:                modelGroup.add(gm);
0606:                modelGroup.add(dgm);
0607:                modelGroup.add(dgmImplementsGm);
0608:                // JComponent Column
0609:                DefaultGraphCell jc = new DefaultGraphCell("JComponent");
0610:                attributes.put(jc, createBounds(new AttributeMap(), 180, 20,
0611:                        Color.green));
0612:                jc.addPort(null, "JComponent/Center");
0613:                DefaultGraphCell jg = new DefaultGraphCell("JGraph");
0614:                attributes.put(jg, createBounds(new AttributeMap(), 180, 100,
0615:                        Color.green));
0616:                jg.addPort(null, "JGraph/Center");
0617:                DefaultEdge jgExtendsJc = new DefaultEdge("extends");
0618:                cs.connect(jgExtendsJc, jc.getChildAt(0), jg.getChildAt(0));
0619:                attributes.put(jgExtendsJc, extendStyle);
0620:                // UI Column
0621:                DefaultGraphCell cu = new DefaultGraphCell("ComponentUI");
0622:                attributes.put(cu, createBounds(new AttributeMap(), 340, 20,
0623:                        Color.red));
0624:                cu.addPort(null, "ComponentUI/Center");
0625:                DefaultGraphCell gu = new DefaultGraphCell("GraphUI");
0626:                attributes.put(gu, createBounds(new AttributeMap(), 340, 100,
0627:                        Color.red));
0628:                gu.addPort(null, "GraphUI/Center");
0629:                DefaultGraphCell dgu = new DefaultGraphCell("BasicGraphUI");
0630:                attributes.put(dgu, createBounds(new AttributeMap(), 340, 180,
0631:                        Color.red));
0632:                dgu.addPort(null, "BasicGraphUI/Center");
0633:                DefaultEdge guExtendsCu = new DefaultEdge("extends");
0634:                cs.connect(guExtendsCu, cu.getChildAt(0), gu.getChildAt(0));
0635:                attributes.put(guExtendsCu, extendStyle);
0636:                DefaultEdge dguImplementsDu = new DefaultEdge("implements");
0637:                cs
0638:                        .connect(dguImplementsDu, gu.getChildAt(0), dgu
0639:                                .getChildAt(0));
0640:                attributes.put(dguImplementsDu, implementStyle);
0641:                DefaultGraphCell uiGroup = new DefaultGraphCell("UIGroup");
0642:                uiGroup.add(cu);
0643:                uiGroup.add(gu);
0644:                uiGroup.add(dgu);
0645:                uiGroup.add(dguImplementsDu);
0646:                uiGroup.add(guExtendsCu);
0647:                // Aggregations
0648:                DefaultEdge jgAggregatesGm = new DefaultEdge("model");
0649:                cs.connect(jgAggregatesGm, jg.getChildAt(0), gm.getChildAt(0));
0650:                attributes.put(jgAggregatesGm, aggregateStyle);
0651:                DefaultEdge jcAggregatesCu = new DefaultEdge("ui");
0652:                cs.connect(jcAggregatesCu, jc.getChildAt(0), cu.getChildAt(0));
0653:                attributes.put(jcAggregatesCu, aggregateStyle);
0654:                // Insert Cells into model
0655:                Object[] cells = new Object[] { jgAggregatesGm, jcAggregatesCu,
0656:                        modelGroup, jc, jg, jgExtendsJc, uiGroup };
0657:                model.insert(cells, attributes, cs, null, null);
0658:            }
0659:
0660:            /**
0661:             * Returns an attributeMap for the specified position and color.
0662:             */
0663:            public static Map createBounds(AttributeMap map, int x, int y,
0664:                    Color c) {
0665:                GraphConstants.setBounds(map, map.createRect(x, y, 90, 30));
0666:                GraphConstants.setBorder(map, BorderFactory
0667:                        .createRaisedBevelBorder());
0668:                GraphConstants.setBackground(map, c.darker().darker());
0669:                GraphConstants.setGradientColor(map, c.brighter().brighter()
0670:                        .brighter());
0671:                GraphConstants.setForeground(map, Color.white);
0672:                if (GraphConstants.DEFAULTFONT != null) {
0673:                    GraphConstants.setFont(map, GraphConstants.DEFAULTFONT
0674:                            .deriveFont(Font.BOLD, 12));
0675:                }
0676:                GraphConstants.setOpaque(map, true);
0677:                return map;
0678:            }
0679:
0680:            /**
0681:             * Returns a <code>JGraph</code> with a sample model.
0682:             */
0683:            public JGraph() {
0684:                this ((GraphModel) null);
0685:            }
0686:
0687:            /**
0688:             * Returns an instance of <code>JGraph</code> which displays the the
0689:             * specified data model.
0690:             * 
0691:             * @param model
0692:             *            the <code>GraphModel</code> to use as the data model
0693:             */
0694:            public JGraph(GraphModel model) {
0695:                this (model, (GraphLayoutCache) null);
0696:            }
0697:
0698:            /**
0699:             * Returns an instance of <code>JGraph</code> which displays the data
0700:             * model using the specified view.
0701:             * 
0702:             * @param cache
0703:             *            the <code>GraphLayoutCache</code> to use as the view
0704:             */
0705:            public JGraph(GraphLayoutCache cache) {
0706:                this ((cache != null) ? cache.getModel() : null, cache);
0707:            }
0708:
0709:            /**
0710:             * Returns an instance of <code>JGraph</code> which displays the specified
0711:             * data model using the specified view.
0712:             * 
0713:             * @param model
0714:             *            the <code>GraphModel</code> to use as the data model
0715:             * @param cache
0716:             *            the <code>GraphLayoutCache</code> to use as the cache
0717:             */
0718:            public JGraph(GraphModel model, GraphLayoutCache cache) {
0719:                this (model, cache, new BasicMarqueeHandler());
0720:            }
0721:
0722:            /**
0723:             * Returns an instance of <code>JGraph</code> which displays the specified
0724:             * data model and assigns the specified marquee handler
0725:             * 
0726:             * @param model
0727:             *            the <code>GraphModel</code> to use as the data model
0728:             * @param mh
0729:             *            the <code>BasicMarqueeHandler</code> to use as the marquee
0730:             *            handler
0731:             */
0732:            public JGraph(GraphModel model, BasicMarqueeHandler mh) {
0733:                this (model, null, mh);
0734:            }
0735:
0736:            /**
0737:             * Returns an instance of <code>JGraph</code> which displays the specified
0738:             * data model using the specified view and assigns the specified marquee
0739:             * handler
0740:             * 
0741:             * @param model
0742:             *            the <code>GraphModel</code> to use as the data model
0743:             * @param layoutCache
0744:             *            the <code>GraphLayoutCache</code> to use as the cache
0745:             * @param mh
0746:             *            the <code>BasicMarqueeHandler</code> to use as the marquee
0747:             *            handler
0748:             */
0749:            public JGraph(GraphModel model, GraphLayoutCache layoutCache,
0750:                    BasicMarqueeHandler mh) {
0751:                setDoubleBuffered(true);
0752:                selectionModel = new DefaultGraphSelectionModel(this );
0753:                setLayout(null);
0754:                marquee = mh;
0755:                if (model == null) {
0756:                    model = new DefaultGraphModel();
0757:                    setModel(model);
0758:                    addSampleData(model);
0759:                } else
0760:                    setModel(model);
0761:                if (layoutCache == null)
0762:                    layoutCache = new GraphLayoutCache(model,
0763:                            new DefaultCellViewFactory());
0764:                setGraphLayoutCache(layoutCache);
0765:                updateUI();
0766:            }
0767:
0768:            //
0769:            // UI-delegate (GraphUI)
0770:            //
0771:            /**
0772:             * Returns the L&F object that renders this component.
0773:             * 
0774:             * @return the GraphUI object that renders this component
0775:             */
0776:            public GraphUI getUI() {
0777:                return (GraphUI) ui;
0778:            }
0779:
0780:            /**
0781:             * Sets the L&F object that renders this component.
0782:             * 
0783:             * @param ui
0784:             *            the GraphUI L&F object
0785:             * @see javax.swing.UIDefaults#getUI(JComponent)
0786:             * 
0787:             */
0788:            public void setUI(GraphUI ui) {
0789:                if ((GraphUI) this .ui != ui) {
0790:                    super .setUI(ui);
0791:                }
0792:            }
0793:
0794:            /**
0795:             * Notification from the <code>UIManager</code> that the L&F has changed.
0796:             * Replaces the current UI object with the latest version from the
0797:             * <code>UIManager</code>. Subclassers can override this to support
0798:             * different GraphUIs.
0799:             * 
0800:             * @see JComponent#updateUI
0801:             * 
0802:             */
0803:            public void updateUI() {
0804:                setUI(new org.jgraph.plaf.basic.BasicGraphUI());
0805:                invalidate();
0806:            }
0807:
0808:            /**
0809:             * Returns the name of the L&F class that renders this component.
0810:             * 
0811:             * @return the string "GraphUI"
0812:             * @see JComponent#getUIClassID
0813:             * 
0814:             */
0815:            public String getUIClassID() {
0816:                return uiClassID;
0817:            }
0818:
0819:            //
0820:            // Content
0821:            //
0822:            /**
0823:             * Returns all root cells (cells that have no parent) that the model
0824:             * contains.
0825:             */
0826:            public Object[] getRoots() {
0827:                return DefaultGraphModel.getRoots(graphModel);
0828:            }
0829:
0830:            /**
0831:             * Returns all cells that intersect the given rectangle.
0832:             */
0833:            public Object[] getRoots(Rectangle clip) {
0834:                CellView[] views = graphLayoutCache.getRoots(clip);
0835:                Object[] cells = new Object[views.length];
0836:                for (int i = 0; i < views.length; i++)
0837:                    cells[i] = views[i].getCell();
0838:                return cells;
0839:            }
0840:
0841:            /**
0842:             * Returns all <code>cells</code> including all descendants in the passed
0843:             * in order of cells.
0844:             */
0845:            public Object[] getDescendants(Object[] cells) {
0846:                return DefaultGraphModel.getDescendants(getModel(), cells)
0847:                        .toArray();
0848:            }
0849:
0850:            /**
0851:             * Returns all <code>cells</code> including all descendants ordered using
0852:             * the current layering data stored by the model.
0853:             */
0854:            public Object[] order(Object[] cells) {
0855:                return DefaultGraphModel.order(getModel(), cells);
0856:            }
0857:
0858:            /**
0859:             * Returns a map of (cell, clone)-pairs for all <code>cells</code> and
0860:             * their children. Special care is taken to replace the anchor references
0861:             * between ports. (Iterative implementation.)
0862:             */
0863:            public Map cloneCells(Object[] cells) {
0864:                return graphModel.cloneCells(cells);
0865:            }
0866:
0867:            /**
0868:             * Returns the topmost cell view at the specified location using the view's
0869:             * bounds on non-leafs to check for containment. If reverse is true this
0870:             * will return the innermost view.
0871:             */
0872:            public CellView getTopmostViewAt(double x, double y,
0873:                    boolean reverse, boolean leafsOnly) {
0874:                Rectangle2D r = new Rectangle2D.Double(x, y, 1, 1);
0875:                Object[] cells = getDescendants(getRoots());
0876:                for (int i = (reverse) ? cells.length - 1 : 0; i >= 0
0877:                        && i < cells.length; i += (reverse) ? -1 : +1) {
0878:                    CellView view = getGraphLayoutCache().getMapping(cells[i],
0879:                            false);
0880:                    if (view != null
0881:                            && (!leafsOnly || view.isLeaf())
0882:                            && ((view.isLeaf() && view.intersects(this , r)) || (!view
0883:                                    .isLeaf() && view.getBounds()
0884:                                    .contains(x, y))))
0885:                        return view;
0886:                }
0887:                return null;
0888:            }
0889:
0890:            /**
0891:             * Returns the topmost cell at the specified location.
0892:             * 
0893:             * @param x
0894:             *            an integer giving the number of pixels horizontally from the
0895:             *            left edge of the display area, minus any left margin
0896:             * @param y
0897:             *            an integer giving the number of pixels vertically from the top
0898:             *            of the display area, minus any top margin
0899:             * @return the topmost cell at the specified location
0900:             */
0901:            public Object getFirstCellForLocation(double x, double y) {
0902:                return getNextCellForLocation(null, x, y);
0903:            }
0904:
0905:            /**
0906:             * Returns the cell at the specified location that is "behind" the
0907:             * <code>current</code> cell. Returns the topmost cell if there are no
0908:             * more cells behind <code>current</code>. Note: This does only return
0909:             * visible cells.
0910:             */
0911:            public Object getNextCellForLocation(Object current, double x,
0912:                    double y) {
0913:                CellView cur = graphLayoutCache.getMapping(current, false);
0914:                CellView cell = getNextViewAt(cur, x, y);
0915:                if (cell != null)
0916:                    return cell.getCell();
0917:                return null;
0918:            }
0919:
0920:            /**
0921:             * Returns the bounding rectangle of the specified cell.
0922:             */
0923:            public Rectangle2D getCellBounds(Object cell) {
0924:                CellView view = graphLayoutCache.getMapping(cell, false);
0925:                if (view != null)
0926:                    return view.getBounds();
0927:                return null;
0928:            }
0929:
0930:            /**
0931:             * Returns the bounding rectangle of the specified cells.
0932:             */
0933:            public Rectangle2D getCellBounds(Object[] cells) {
0934:                if (cells != null && cells.length > 0) {
0935:                    Rectangle2D r = getCellBounds(cells[0]);
0936:                    Rectangle2D ret = (r != null) ? (Rectangle2D) r.clone()
0937:                            : null;
0938:                    for (int i = 1; i < cells.length; i++) {
0939:                        r = getCellBounds(cells[i]);
0940:                        if (r != null) {
0941:                            if (ret == null)
0942:                                ret = (r != null) ? (Rectangle2D) r.clone()
0943:                                        : null;
0944:                            else
0945:                                Rectangle2D.union(ret, r, ret);
0946:                        }
0947:                    }
0948:                    return ret;
0949:                }
0950:                return null;
0951:            }
0952:
0953:            /**
0954:             * Returns the next view at the specified location wrt. <code>current</code>.
0955:             * This is used to iterate overlapping cells, and cells that are grouped.
0956:             * The current selection affects this method. <br>
0957:             * Note: This returns the next <i>selectable </i> view. <br>
0958:             * Note: Arguments are not expected to be scaled (they are scaled in here).
0959:             */
0960:            public CellView getNextViewAt(CellView current, double x, double y) {
0961:                return getNextViewAt(current, x, y, false);
0962:            }
0963:
0964:            /**
0965:             * Returns the next view at the specified location wrt. <code>current</code>.
0966:             * This is used to iterate overlapping cells, and cells that are grouped.
0967:             * The current selection affects this method. <br>
0968:             * Note: This returns the next <i>selectable </i> view. <br>
0969:             * Note: Arguments are not expected to be scaled (they are scaled in here).
0970:             */
0971:            public CellView getNextViewAt(CellView current, double x, double y,
0972:                    boolean leafsOnly) {
0973:                CellView[] cells = AbstractCellView
0974:                        .getDescendantViews(getGraphLayoutCache().getRoots());
0975:                return getNextViewAt(cells, current, x, y, leafsOnly);
0976:            }
0977:
0978:            /**
0979:             * Note: Arguments are not expected to be scaled (they are scaled in here).
0980:             */
0981:            public CellView getNextSelectableViewAt(CellView current, double x,
0982:                    double y) {
0983:                CellView[] selectables = getGraphLayoutCache().getMapping(
0984:                        getSelectionModel().getSelectables(), false);
0985:                return getNextViewAt(selectables, current, x, y);
0986:            }
0987:
0988:            /**
0989:             * Returns the next view at the specified location wrt. <code>c</code> in
0990:             * the specified array of views. The views must be in order, as returned,
0991:             * for example, by GraphLayoutCache.order(Object[]).
0992:             */
0993:            public CellView getNextViewAt(CellView[] cells, CellView c,
0994:                    double x, double y) {
0995:                return getNextViewAt(cells, c, x, y, false);
0996:            }
0997:
0998:            /**
0999:             * Returns the next view at the specified location wrt. <code>c</code> in
1000:             * the specified array of views. The views must be in order, as returned,
1001:             * for example, by GraphLayoutCache.order(Object[]).
1002:             */
1003:            public CellView getNextViewAt(CellView[] cells, CellView c,
1004:                    double x, double y, boolean leafsOnly) {
1005:                if (cells != null) {
1006:                    Rectangle2D r = fromScreen(new Rectangle2D.Double(x
1007:                            - tolerance, y - tolerance, 2 * tolerance,
1008:                            2 * tolerance));
1009:                    // Iterate through cells and switch to active
1010:                    // if current is traversed. Cache first cell.
1011:                    CellView first = null;
1012:                    boolean active = (c == null);
1013:                    for (int i = 0; i < cells.length; i++) {
1014:                        if (cells[i] != null
1015:                                && (!leafsOnly || cells[i].isLeaf())
1016:                                && cells[i].intersects(this , r)) {
1017:                            // TODO: This behaviour is specific to selection and
1018:                            // should be parametrized (it only returns a group with
1019:                            // selected children if no other portview is available)
1020:                            if (active
1021:                                    && !selectionModel
1022:                                            .isChildrenSelected(cells[i]
1023:                                                    .getCell())) {
1024:                                return cells[i];
1025:                            } else if (first == null)
1026:                                first = cells[i];
1027:                            active = active | (cells[i] == c);
1028:                        }
1029:                    }
1030:                    return first;
1031:                }
1032:                return null;
1033:            }
1034:
1035:            /**
1036:             * Returns the next view at the specified location wrt. <code>c</code> in
1037:             * the specified array of views. The views must be in order, as returned,
1038:             * for example, by GraphLayoutCache.order(Object[]).
1039:             */
1040:            public CellView getLeafViewAt(double x, double y) {
1041:                return getNextViewAt(null, x, y, true);
1042:            }
1043:
1044:            /**
1045:             * Convenience method to return the port at the specified location.
1046:             */
1047:            public Object getPortForLocation(double x, double y) {
1048:                PortView view = getPortViewAt(x, y, tolerance);
1049:                if (view != null)
1050:                    return view.getCell();
1051:                return null;
1052:            }
1053:
1054:            /**
1055:             * Returns the portview at the specified location. <br>
1056:             * Note: Arguments are not expected to be scaled (they are scaled in here).
1057:             */
1058:            public PortView getPortViewAt(double x, double y) {
1059:                return getPortViewAt(x, y, tolerance);
1060:            }
1061:
1062:            /**
1063:             * Returns the portview at the specified location. <br>
1064:             * Note: Arguments are not expected to be scaled (they are scaled in here).
1065:             */
1066:            public PortView getPortViewAt(double x, double y, int tolerance) {
1067:                double sx = x / scale;
1068:                double sy = y / scale;
1069:                Rectangle2D r = new Rectangle2D.Double(sx - tolerance, sy
1070:                        - tolerance, 2 * tolerance, 2 * tolerance);
1071:                PortView[] ports = graphLayoutCache.getPorts();
1072:                if (ports != null) {
1073:                    for (int i = ports.length - 1; i >= 0; i--)
1074:                        if (ports[i] != null && ports[i].intersects(this , r))
1075:                            return ports[i];
1076:                    if (isJumpToDefaultPort()) {
1077:                        CellView cellView = getNextViewAt(null, x, y, true);
1078:
1079:                        // Finds a non-edge cell under the mousepointer
1080:                        if (cellView != null
1081:                                && graphModel.isEdge(cellView.getCell())) {
1082:                            CellView nextView = getNextViewAt(cellView, x, y,
1083:                                    true);
1084:                            while (nextView != cellView
1085:                                    && graphModel.isEdge(nextView.getCell())) {
1086:                                nextView = getNextViewAt(nextView, x, y, true);
1087:                            }
1088:                            cellView = nextView;
1089:                        }
1090:                        if (cellView != null) {
1091:                            PortView defaultPort = getDefaultPortForCell(cellView
1092:                                    .getCell());
1093:                            return defaultPort;
1094:                        }
1095:                    }
1096:                }
1097:                return null;
1098:            }
1099:
1100:            /**
1101:             * Returns the default portview for the specified cell. The default
1102:             * implementation returns the first floating port (ie. the first port that
1103:             * does not define an offset) or <b>the </b> port, if there is only one
1104:             * port.
1105:             * 
1106:             * @param cell
1107:             *            the cell whose port is to be obtained
1108:             * @return the port view of the specified cell
1109:             */
1110:            public PortView getDefaultPortForCell(Object cell) {
1111:                if (cell != null && !getModel().isEdge(cell)) {
1112:                    int childCount = getModel().getChildCount(cell);
1113:                    for (int i = 0; i < childCount; i++) {
1114:                        Object childCell = getModel().getChild(cell, i);
1115:                        CellView child = getGraphLayoutCache().getMapping(
1116:                                childCell, false);
1117:                        if (child instanceof  PortView) {
1118:                            Point2D offset = GraphConstants.getOffset(child
1119:                                    .getAllAttributes());
1120:                            if (offset == null || childCount == 1)
1121:                                return (PortView) child;
1122:                        }
1123:                    }
1124:                }
1125:                return null;
1126:            }
1127:
1128:            /**
1129:             * Converts the specified value to string. If the value is an instance of
1130:             * CellView then the corresponding value or cell is used.
1131:             */
1132:            public String convertValueToString(Object value) {
1133:                if (value instanceof  CellView)
1134:                    value = ((CellView) value).getCell();
1135:                return String.valueOf(value);
1136:            }
1137:
1138:            //
1139:            // Grid and Scale
1140:            //
1141:            /**
1142:             * Returns the given point applied to the grid.
1143:             * 
1144:             * @param p
1145:             *            a point in screen coordinates.
1146:             * @return the same point applied to the grid.
1147:             */
1148:            public Point2D snap(Point2D p) {
1149:                if (gridEnabled && p != null) {
1150:                    double sgs = gridSize * getScale();
1151:                    p.setLocation(Math.round(Math.round(p.getX() / sgs) * sgs),
1152:                            Math.round(Math.round(p.getY() / sgs) * sgs));
1153:                }
1154:                return p;
1155:            }
1156:
1157:            /**
1158:             * Returns the given rectangle applied to the grid.
1159:             * 
1160:             * @param r
1161:             *            a rectangle in screen coordinates.
1162:             * @return the same rectangle applied to the grid.
1163:             */
1164:            public Rectangle2D snap(Rectangle2D r) {
1165:                if (gridEnabled && r != null) {
1166:                    double sgs = gridSize * getScale();
1167:                    r
1168:                            .setFrame(Math.round(Math.round(r.getX() / sgs)
1169:                                    * sgs), Math.round(Math.round(r.getY()
1170:                                    / sgs)
1171:                                    * sgs), 1 + Math.round(Math.round(r
1172:                                    .getWidth()
1173:                                    / sgs)
1174:                                    * sgs), 1 + Math.round(Math.round(r
1175:                                    .getHeight()
1176:                                    / sgs)
1177:                                    * sgs));
1178:                }
1179:                return r;
1180:            }
1181:
1182:            /**
1183:             * Returns the given dimension applied to the grid.
1184:             * 
1185:             * @param d
1186:             *            a dimension in screen coordinates to snap to.
1187:             * @return the same dimension applied to the grid.
1188:             */
1189:            public Dimension2D snap(Dimension2D d) {
1190:                if (gridEnabled && d != null) {
1191:                    double sgs = gridSize * getScale();
1192:                    d.setSize(1 + Math.round(Math.round(d.getWidth() / sgs)
1193:                            * sgs), 1 + Math.round(Math.round(d.getHeight()
1194:                            / sgs)
1195:                            * sgs));
1196:                }
1197:                return d;
1198:            }
1199:
1200:            /**
1201:             * Upscale the given point in place, using the given instance.
1202:             * 
1203:             * @param p
1204:             *            the point to be upscaled
1205:             * @return the upscaled point instance
1206:             */
1207:            public Point2D toScreen(Point2D p) {
1208:                if (p == null)
1209:                    return null;
1210:                p.setLocation(Math.round(p.getX() * scale), Math.round(p.getY()
1211:                        * scale));
1212:                return p;
1213:            }
1214:
1215:            /**
1216:             * Downscale the given point in place, using the given instance.
1217:             * 
1218:             * @param p
1219:             *            the point to be downscaled
1220:             * @return the downscaled point instance
1221:             */
1222:            public Point2D fromScreen(Point2D p) {
1223:                if (p == null)
1224:                    return null;
1225:                p.setLocation(Math.round(p.getX() / scale), Math.round(p.getY()
1226:                        / scale));
1227:                return p;
1228:            }
1229:
1230:            /**
1231:             * Upscale the given rectangle in place, using the given instance.
1232:             * 
1233:             * @param rect
1234:             *            the rectangle to be upscaled
1235:             * @return the upscaled rectangle instance
1236:             */
1237:            public Rectangle2D toScreen(Rectangle2D rect) {
1238:                if (rect == null)
1239:                    return null;
1240:                rect.setFrame(rect.getX() * scale, rect.getY() * scale, rect
1241:                        .getWidth()
1242:                        * scale, rect.getHeight() * scale);
1243:                return rect;
1244:            }
1245:
1246:            /**
1247:             * Downscale the given rectangle in place, using the given instance.
1248:             * 
1249:             * @param rect
1250:             *            the rectangle to be downscaled
1251:             * @return the down-scaled rectangle instance
1252:             */
1253:            public Rectangle2D fromScreen(Rectangle2D rect) {
1254:                if (rect == null)
1255:                    return null;
1256:                rect.setFrame(rect.getX() / scale, rect.getY() / scale, rect
1257:                        .getWidth()
1258:                        / scale, rect.getHeight() / scale);
1259:                return rect;
1260:            }
1261:
1262:            /**
1263:             * Computes and updates the size for <code>view</code>.
1264:             */
1265:            public void updateAutoSize(CellView view) {
1266:                if (view != null && !isEditing()) {
1267:                    Rectangle2D bounds = (view.getAttributes() != null) ? GraphConstants
1268:                            .getBounds(view.getAttributes())
1269:                            : null;
1270:                    AttributeMap attrs = getModel().getAttributes(
1271:                            view.getCell());
1272:                    if (bounds == null)
1273:                        bounds = GraphConstants.getBounds(attrs);
1274:                    if (bounds != null) {
1275:                        boolean autosize = GraphConstants.isAutoSize(view
1276:                                .getAllAttributes());
1277:                        boolean resize = GraphConstants.isResize(view
1278:                                .getAllAttributes());
1279:                        if (autosize || resize) {
1280:                            Dimension2D d = getUI()
1281:                                    .getPreferredSize(this , view);
1282:                            bounds.setFrame(bounds.getX(), bounds.getY(), d
1283:                                    .getWidth(), d.getHeight());
1284:                            // Remove resize attribute
1285:                            snap(bounds);
1286:                            if (resize) {
1287:                                if (view.getAttributes() != null)
1288:                                    view.getAttributes().remove(
1289:                                            GraphConstants.RESIZE);
1290:                                attrs.remove(GraphConstants.RESIZE);
1291:                            }
1292:                            view.refresh(getGraphLayoutCache(),
1293:                                    getGraphLayoutCache(), false);
1294:                        }
1295:                    }
1296:                }
1297:            }
1298:
1299:            /**
1300:             * Returns the attributes for the specified cell. If the layout cache
1301:             * returns a view for the cell then this method returns allAttributes,
1302:             * otherwise the method returns model.getAttributes(cell).
1303:             */
1304:            public AttributeMap getAttributes(Object cell) {
1305:                AttributeMap attrs;
1306:                CellView cellView = getGraphLayoutCache().getMapping(cell,
1307:                        false);
1308:                if (cellView != null) {
1309:                    attrs = cellView.getAllAttributes();
1310:                } else {
1311:                    attrs = getModel().getAttributes(cell);
1312:                }
1313:                return attrs;
1314:            }
1315:
1316:            //
1317:            // Unbound Properties
1318:            //
1319:            /**
1320:             * Returns the number of clicks for editing to start.
1321:             */
1322:            public int getEditClickCount() {
1323:                return editClickCount;
1324:            }
1325:
1326:            /**
1327:             * Sets the number of clicks for editing to start.
1328:             */
1329:            public void setEditClickCount(int count) {
1330:                editClickCount = count;
1331:            }
1332:
1333:            /**
1334:             * Returns true if the graph accepts drops/pastes from external sources.
1335:             */
1336:            public boolean isDropEnabled() {
1337:                return dropEnabled;
1338:            }
1339:
1340:            /**
1341:             * Sets if the graph accepts drops/pastes from external sources.
1342:             */
1343:            public void setDropEnabled(boolean flag) {
1344:                dropEnabled = flag;
1345:            }
1346:
1347:            /**
1348:             * Returns true if the graph accepts drops/pastes from external sources.
1349:             */
1350:            public boolean isXorEnabled() {
1351:                return xorEnabled;
1352:            }
1353:
1354:            /**
1355:             * Sets if the graph accepts drops/pastes from external sources.
1356:             */
1357:            public void setXorEnabled(boolean flag) {
1358:                xorEnabled = flag;
1359:            }
1360:
1361:            /**
1362:             * Returns true if the graph uses Drag-and-Drop to move cells.
1363:             */
1364:            public boolean isDragEnabled() {
1365:                return dragEnabled;
1366:            }
1367:
1368:            /**
1369:             * Sets if the graph uses Drag-and-Drop to move cells.
1370:             */
1371:            public void setDragEnabled(boolean flag) {
1372:                dragEnabled = flag;
1373:            }
1374:
1375:            /*
1376:             * Returns true if the graph allows movement of cells.
1377:             */
1378:            public boolean isMoveable() {
1379:                return moveable;
1380:            }
1381:
1382:            /**
1383:             * Sets if the graph allows movement of cells.
1384:             */
1385:            public void setMoveable(boolean flag) {
1386:                moveable = flag;
1387:            }
1388:
1389:            /**
1390:             * Returns true if the graph allows adding/removing/modifying points.
1391:             */
1392:            public boolean isBendable() {
1393:                return bendable;
1394:            }
1395:
1396:            /**
1397:             * Sets if the graph allows adding/removing/modifying points.
1398:             */
1399:            public void setBendable(boolean flag) {
1400:                bendable = flag;
1401:            }
1402:
1403:            /**
1404:             * Returns true if the graph allows new connections to be established.
1405:             */
1406:            public boolean isConnectable() {
1407:                return connectable;
1408:            }
1409:
1410:            /**
1411:             * Setse if the graph allows new connections to be established.
1412:             */
1413:            public void setConnectable(boolean flag) {
1414:                connectable = flag;
1415:            }
1416:
1417:            /**
1418:             * Returns true if the graph allows existing connections to be removed.
1419:             */
1420:            public boolean isDisconnectable() {
1421:                return disconnectable;
1422:            }
1423:
1424:            /**
1425:             * Sets if the graph allows existing connections to be removed.
1426:             */
1427:            public void setDisconnectable(boolean flag) {
1428:                disconnectable = flag;
1429:            }
1430:
1431:            /**
1432:             * Returns true if cells are cloned on CTRL-Drag operations.
1433:             */
1434:            public boolean isCloneable() {
1435:                return cloneable;
1436:            }
1437:
1438:            /**
1439:             * Sets if cells are cloned on CTRL-Drag operations.
1440:             */
1441:            public void setCloneable(boolean flag) {
1442:                cloneable = flag;
1443:            }
1444:
1445:            /**
1446:             * Returns true if the graph allows cells to be resized.
1447:             */
1448:            public boolean isSizeable() {
1449:                return sizeable;
1450:            }
1451:
1452:            /**
1453:             * Sets if the graph allows cells to be resized.
1454:             */
1455:            public void setSizeable(boolean flag) {
1456:                sizeable = flag;
1457:            }
1458:
1459:            /**
1460:             * Sets if selected edges should be disconnected from unselected vertices
1461:             * when they are moved.
1462:             */
1463:            public void setDisconnectOnMove(boolean flag) {
1464:                disconnectOnMove = flag;
1465:            }
1466:
1467:            /**
1468:             * Returns true if selected edges should be disconnected from unselected
1469:             * vertices when they are moved.
1470:             */
1471:            public boolean isDisconnectOnMove() {
1472:                return disconnectOnMove && disconnectable;
1473:            }
1474:
1475:            /**
1476:             * Sets if getPortViewAt should return the default port if no other port is
1477:             * found.
1478:             */
1479:            public void setJumpToDefaultPort(boolean flag) {
1480:                isJumpToDefaultPort = flag;
1481:            }
1482:
1483:            /**
1484:             * Returns true if getPortViewAt should return the default port if no other
1485:             * port is found.
1486:             */
1487:            public boolean isJumpToDefaultPort() {
1488:                return isJumpToDefaultPort;
1489:            }
1490:
1491:            /**
1492:             * Specifies if cells should be added to groups when moved over the group's
1493:             * area.
1494:             */
1495:            public void setMoveIntoGroups(boolean flag) {
1496:                isMoveIntoGroups = flag;
1497:            }
1498:
1499:            /**
1500:             * Returns true if cells should be added to groups when moved over the
1501:             * group's area.
1502:             */
1503:            public boolean isMoveIntoGroups() {
1504:                return isMoveIntoGroups;
1505:            }
1506:
1507:            /**
1508:             * Specifies if cells should be removed from groups when removed from the
1509:             * group's area.
1510:             */
1511:            public void setMoveOutOfGroups(boolean flag) {
1512:                isMoveOutOfGroups = flag;
1513:            }
1514:
1515:            /**
1516:             * Returns true if cells should be removed from groups when removed from the
1517:             * group's area.
1518:             */
1519:            public boolean isMoveOutOfGroups() {
1520:                return isMoveOutOfGroups;
1521:            }
1522:
1523:            /**
1524:             * Returns true if the grid is active.
1525:             * 
1526:             * @see #snap(Point2D)
1527:             * 
1528:             */
1529:            public boolean isGridEnabled() {
1530:                return gridEnabled;
1531:            }
1532:
1533:            /**
1534:             * If set to true, the grid will be active.
1535:             * 
1536:             * @see #snap(Point2D)
1537:             * 
1538:             */
1539:            public void setGridEnabled(boolean flag) {
1540:                gridEnabled = flag;
1541:            }
1542:
1543:            /**
1544:             * Returns true if the graph allows to move cells below zero.
1545:             */
1546:            public boolean isMoveBelowZero() {
1547:                return moveBelowZero;
1548:            }
1549:
1550:            /**
1551:             * Sets if the graph should auto resize when cells are being moved below the
1552:             * bottom right corner.
1553:             */
1554:            public void setMoveBelowZero(boolean moveBelowZero) {
1555:                this .moveBelowZero = moveBelowZero;
1556:            }
1557:
1558:            /**
1559:             * @return the moveBeyondGraphBounds
1560:             */
1561:            public boolean isMoveBeyondGraphBounds() {
1562:                return moveBeyondGraphBounds;
1563:            }
1564:
1565:            /**
1566:             * @param moveBeyondGraphBounds the moveBeyondGraphBounds to set
1567:             */
1568:            public void setMoveBeyondGraphBounds(boolean moveBeyondGraphBounds) {
1569:                this .moveBeyondGraphBounds = moveBeyondGraphBounds;
1570:            }
1571:
1572:            /**
1573:             * Returns true if edge labels may be dragged and dropped.
1574:             * 
1575:             * @return whether edge labels may be dragged and dropped
1576:             */
1577:            public boolean getEdgeLabelsMovable() {
1578:                return edgeLabelsMovable;
1579:            }
1580:
1581:            /**
1582:             * Set if edge labels may be moved with the mouse or not.
1583:             * 
1584:             * @param edgeLabelsMovable
1585:             *            true if edge labels may be dragged
1586:             */
1587:            public void setEdgeLabelsMovable(boolean edgeLabelsMovable) {
1588:                this .edgeLabelsMovable = edgeLabelsMovable;
1589:            }
1590:
1591:            /**
1592:             * Returns true if the graph should be automatically resized when cells are
1593:             * being moved below the bottom right corner. Note if the value of
1594:             * <code>moveBeyondGraphBounds</code> if <code>false</code> auto resizing
1595:             * is automatically disabled
1596:             */
1597:            public boolean isAutoResizeGraph() {
1598:                if (!moveBeyondGraphBounds) {
1599:                    return false;
1600:                }
1601:                return autoResizeGraph;
1602:            }
1603:
1604:            /**
1605:             * Sets whether or not the graph should be automatically resize when cells 
1606:             * are being moved below the bottom right corner
1607:             */
1608:            public void setAutoResizeGraph(boolean autoResizeGraph) {
1609:                this .autoResizeGraph = autoResizeGraph;
1610:            }
1611:
1612:            /**
1613:             * Returns the maximum distance between the mousepointer and a cell to be
1614:             * selected.
1615:             */
1616:            public int getTolerance() {
1617:                return tolerance;
1618:            }
1619:
1620:            /**
1621:             * Sets the maximum distance between the mousepointer and a cell to be
1622:             * selected.
1623:             */
1624:            public void setTolerance(int size) {
1625:                if (size < 1) {
1626:                    size = 1;
1627:                }
1628:                tolerance = size;
1629:            }
1630:
1631:            /**
1632:             * Returns the size of the handles.
1633:             */
1634:            public int getHandleSize() {
1635:                return handleSize;
1636:            }
1637:
1638:            /**
1639:             * Sets the size of the handles.
1640:             */
1641:            public void setHandleSize(int size) {
1642:                int oldValue = handleSize;
1643:                handleSize = size;
1644:                firePropertyChange(HANDLE_SIZE_PROPERTY, oldValue, size);
1645:            }
1646:
1647:            /**
1648:             * Returns the miminum amount of pixels for a move operation.
1649:             */
1650:            public int getMinimumMove() {
1651:                return minimumMove;
1652:            }
1653:
1654:            /**
1655:             * Sets the miminum amount of pixels for a move operation.
1656:             */
1657:            public void setMinimumMove(int pixels) {
1658:                minimumMove = pixels;
1659:            }
1660:
1661:            //
1662:            // Laf-Specific color scheme. These colors are changed
1663:            // by BasicGraphUI when the laf changes.
1664:            //
1665:            /**
1666:             * Returns the current grid color.
1667:             */
1668:            public Color getGridColor() {
1669:                return gridColor;
1670:            }
1671:
1672:            /**
1673:             * Sets the current grid color.
1674:             */
1675:            public void setGridColor(Color newColor) {
1676:                Color oldValue = gridColor;
1677:                gridColor = newColor;
1678:                firePropertyChange(GRID_COLOR_PROPERTY, oldValue, newColor);
1679:            }
1680:
1681:            /**
1682:             * Returns the current handle color.
1683:             */
1684:            public Color getHandleColor() {
1685:                return handleColor;
1686:            }
1687:
1688:            /**
1689:             * Sets the current handle color.
1690:             */
1691:            public void setHandleColor(Color newColor) {
1692:                Color oldValue = handleColor;
1693:                handleColor = newColor;
1694:                firePropertyChange(HANDLE_COLOR_PROPERTY, oldValue, newColor);
1695:            }
1696:
1697:            /**
1698:             * Returns the current second handle color.
1699:             */
1700:            public Color getLockedHandleColor() {
1701:                return lockedHandleColor;
1702:            }
1703:
1704:            /**
1705:             * Sets the current second handle color.
1706:             */
1707:            public void setLockedHandleColor(Color newColor) {
1708:                Color oldValue = lockedHandleColor;
1709:                lockedHandleColor = newColor;
1710:                firePropertyChange(LOCKED_HANDLE_COLOR_PROPERTY, oldValue,
1711:                        newColor);
1712:            }
1713:
1714:            /**
1715:             * Returns the current marquee color.
1716:             */
1717:            public Color getMarqueeColor() {
1718:                return marqueeColor;
1719:            }
1720:
1721:            /**
1722:             * Sets the current marquee color.
1723:             */
1724:            public void setMarqueeColor(Color newColor) {
1725:                marqueeColor = newColor;
1726:            }
1727:
1728:            /**
1729:             * Returns the current highlight color.
1730:             */
1731:            public Color getHighlightColor() {
1732:                return highlightColor;
1733:            }
1734:
1735:            /**
1736:             * Sets the current selection highlight color.
1737:             */
1738:            public void setHighlightColor(Color newColor) {
1739:                highlightColor = newColor;
1740:            }
1741:
1742:            //
1743:            // Bound properties
1744:            //
1745:            /**
1746:             * Returns the current scale.
1747:             * 
1748:             * @return the current scale as a double
1749:             */
1750:            public double getScale() {
1751:                return scale;
1752:            }
1753:
1754:            /**
1755:             * Sets the current scale.
1756:             * <p>
1757:             * Fires a property change for the SCALE_PROPERTY.
1758:             * 
1759:             * @param newValue
1760:             *            the new scale
1761:             */
1762:            public void setScale(double newValue) {
1763:                Point2D centerPoint = getCenterPoint();
1764:                setScale(newValue, centerPoint);
1765:            }
1766:
1767:            /**
1768:             * Sets the current scale and centers the graph to the specified point
1769:             * 
1770:             * @param newValue
1771:             *            the new scale
1772:             * @param center
1773:             *            the center of the graph
1774:             */
1775:            public void setScale(double newValue, Point2D center) {
1776:                if (newValue > 0 && newValue != this .scale) {
1777:                    Rectangle2D view = getViewPortBounds();
1778:                    double oldValue = this .scale;
1779:                    scale = newValue;
1780:                    boolean zoomIn = true;
1781:                    Rectangle newView = null;
1782:                    if (view != null) {
1783:                        double scaleRatio = newValue / oldValue;
1784:                        int newCenterX = (int) (center.getX() * scaleRatio);
1785:                        int newCenterY = (int) (center.getY() * scaleRatio);
1786:                        int newX = (int) (newCenterX - view.getWidth() / 2.0);
1787:                        int newY = (int) (newCenterY - view.getHeight() / 2.0);
1788:                        newView = new Rectangle(newX, newY, (int) view
1789:                                .getWidth(), (int) view.getHeight());
1790:                        // When zooming out scroll before revalidation otherwise
1791:                        // revalidation causes one scroll and scrollRectToVisible
1792:                        // another
1793:                        if (scaleRatio < 1.0) {
1794:                            scrollRectToVisible(newView);
1795:                            zoomIn = false;
1796:                        }
1797:                    }
1798:                    offscreenValid = false;
1799:                    firePropertyChange(SCALE_PROPERTY, oldValue, newValue);
1800:                    // When zooming in, do it after the revalidation otherwise
1801:                    // it intermittently moves to the old co-ordinate system
1802:                    if (zoomIn && newView != null) {
1803:                        scrollRectToVisible(newView);
1804:                    }
1805:                }
1806:            }
1807:
1808:            /**
1809:             * Returns the center of the component relative to the parent viewport's
1810:             * position.
1811:             */
1812:            public Point2D getCenterPoint() {
1813:                Rectangle2D viewBounds = getViewPortBounds();
1814:                if (viewBounds != null) {
1815:                    return new Point2D.Double(viewBounds.getCenterX(),
1816:                            viewBounds.getCenterY());
1817:                }
1818:                viewBounds = getBounds();
1819:                return new Point2D.Double(viewBounds.getCenterX(), viewBounds
1820:                        .getCenterY());
1821:            }
1822:
1823:            /**
1824:             * Return the bounds of the parent viewport, if one exists. If one does not
1825:             * exist, null is returned
1826:             * 
1827:             * @return the bounds of the parent viewport
1828:             */
1829:            public Rectangle2D getViewPortBounds() {
1830:                if (getParent() instanceof  JViewport) {
1831:                    return ((JViewport) getParent()).getViewRect();
1832:                }
1833:                return null;
1834:            }
1835:
1836:            /**
1837:             * Returns the size of the grid in pixels.
1838:             * 
1839:             * @return the size of the grid as an int
1840:             */
1841:            public double getGridSize() {
1842:                return gridSize;
1843:            }
1844:
1845:            /**
1846:             * Returns the current grid view mode.
1847:             */
1848:            public int getGridMode() {
1849:                return gridMode;
1850:            }
1851:
1852:            /**
1853:             * Sets the size of the grid.
1854:             * <p>
1855:             * Fires a property change for the GRID_SIZE_PROPERTY.
1856:             * 
1857:             * @param newSize
1858:             *            the new size of the grid in pixels
1859:             */
1860:            public void setGridSize(double newSize) {
1861:                double oldValue = this .gridSize;
1862:                this .gridSize = newSize;
1863:                firePropertyChange(GRID_SIZE_PROPERTY, oldValue, newSize);
1864:            }
1865:
1866:            /**
1867:             * Sets the current grid view mode.
1868:             * 
1869:             * @param mode
1870:             *            The current grid view mode. Valid values are <CODE>
1871:             *            DOT_GRID_MODE</CODE>,<CODE>CROSS_GRID_MODE</CODE>, and
1872:             *            <CODE>LINE_GRID_MODE</CODE>.
1873:             */
1874:            public void setGridMode(int mode) {
1875:                if (mode == DOT_GRID_MODE || mode == CROSS_GRID_MODE
1876:                        || mode == LINE_GRID_MODE) {
1877:                    gridMode = mode;
1878:                    repaint();
1879:                }
1880:            }
1881:
1882:            /**
1883:             * Returns true if the grid will be visible.
1884:             * 
1885:             * @return true if the grid is visible
1886:             */
1887:            public boolean isGridVisible() {
1888:                return gridVisible;
1889:            }
1890:
1891:            /**
1892:             * If set to true, the grid will be visible.
1893:             * <p>
1894:             * Fires a property change for the GRID_VISIBLE_PROPERTY.
1895:             */
1896:            public void setGridVisible(boolean flag) {
1897:                boolean oldValue = gridVisible;
1898:                gridVisible = flag;
1899:                firePropertyChange(GRID_VISIBLE_PROPERTY, oldValue, flag);
1900:            }
1901:
1902:            /**
1903:             * Returns true if the ports will be visible.
1904:             * 
1905:             * @return true if the ports are visible
1906:             */
1907:            public boolean isPortsVisible() {
1908:                return portsVisible;
1909:            }
1910:
1911:            /**
1912:             * If set to true, the ports will be visible.
1913:             * <p>
1914:             * Fires a property change for the PORTS_VISIBLE_PROPERTY.
1915:             */
1916:            public void setPortsVisible(boolean flag) {
1917:                boolean oldValue = portsVisible;
1918:                portsVisible = flag;
1919:                firePropertyChange(PORTS_VISIBLE_PROPERTY, oldValue, flag);
1920:            }
1921:
1922:            /**
1923:             * Returns true if the ports will be scaled.
1924:             * 
1925:             * @return true if the ports are visible
1926:             */
1927:            public boolean isPortsScaled() {
1928:                return portsScaled;
1929:            }
1930:
1931:            /**
1932:             * If set to true, the ports will be scaled.
1933:             * <p>
1934:             * Fires a property change for the PORTS_SCALED_PROPERTY.
1935:             */
1936:            public void setPortsScaled(boolean flag) {
1937:                boolean oldValue = portsScaled;
1938:                portsScaled = flag;
1939:                firePropertyChange(PORTS_SCALED_PROPERTY, oldValue, flag);
1940:            }
1941:
1942:            /**
1943:             * Returns true if the graph will be anti aliased.
1944:             * 
1945:             * @return true if the graph is anti aliased
1946:             */
1947:            public boolean isAntiAliased() {
1948:                return antiAliased;
1949:            }
1950:
1951:            /**
1952:             * Sets antialiasing on or off based on the boolean value.
1953:             * <p>
1954:             * Fires a property change for the ANTIALIASED_PROPERTY.
1955:             * 
1956:             * @param newValue
1957:             *            whether to turn antialiasing on or off
1958:             */
1959:            public void setAntiAliased(boolean newValue) {
1960:                boolean oldValue = this .antiAliased;
1961:                this .antiAliased = newValue;
1962:                firePropertyChange(ANTIALIASED_PROPERTY, oldValue, newValue);
1963:            }
1964:
1965:            /**
1966:             * Returns true if the graph is editable (if it allows cells to be edited).
1967:             * 
1968:             * @return true if the graph is editable
1969:             */
1970:            public boolean isEditable() {
1971:                return editable;
1972:            }
1973:
1974:            /**
1975:             * Determines whether the graph is editable. Fires a property change event
1976:             * if the new setting is different from the existing setting.
1977:             * <p>
1978:             * Note: Editable determines whether the graph allows editing. This is not
1979:             * to be confused with enabled, which allows the graph to handle mouse
1980:             * events (including editing).
1981:             * 
1982:             * @param flag
1983:             *            a boolean value, true if the graph is editable
1984:             */
1985:            public void setEditable(boolean flag) {
1986:                boolean oldValue = this .editable;
1987:                this .editable = flag;
1988:                firePropertyChange(EDITABLE_PROPERTY, oldValue, flag);
1989:            }
1990:
1991:            /**
1992:             * @return the groupsEditable
1993:             */
1994:            public boolean isGroupsEditable() {
1995:                return groupsEditable;
1996:            }
1997:
1998:            /**
1999:             * @param groupsEditable the groupsEditable to set
2000:             */
2001:            public void setGroupsEditable(boolean groupsEditable) {
2002:                this .groupsEditable = groupsEditable;
2003:            }
2004:
2005:            /**
2006:             * Returns true if the cell selection is enabled
2007:             * 
2008:             * @return true if the cell selection is enabled
2009:             */
2010:            public boolean isSelectionEnabled() {
2011:                return selectionEnabled;
2012:            }
2013:
2014:            /**
2015:             * Determines whether cell selection is enabled. Fires a property change
2016:             * event if the new setting is different from the existing setting.
2017:             * 
2018:             * @param flag
2019:             *            a boolean value, true if cell selection is enabled
2020:             */
2021:            public void setSelectionEnabled(boolean flag) {
2022:                boolean oldValue = this .selectionEnabled;
2023:                this .selectionEnabled = flag;
2024:                firePropertyChange(SELECTIONENABLED_PROPERTY, oldValue, flag);
2025:            }
2026:
2027:            /**
2028:             * Returns true if graph allows invalid null ports during previews
2029:             * 
2030:             * @return true if the graph allows invalid null ports during previews
2031:             */
2032:            public boolean isPreviewInvalidNullPorts() {
2033:                return previewInvalidNullPorts;
2034:            }
2035:
2036:            /**
2037:             * Determines whether the graph allows invalid null ports during previews
2038:             * 
2039:             * @param flag
2040:             *            a boolean value, true if the graph allows invalid null ports
2041:             *            during previews
2042:             */
2043:            public void setPreviewInvalidNullPorts(boolean flag) {
2044:                this .previewInvalidNullPorts = flag;
2045:            }
2046:
2047:            /**
2048:             * Returns the current double buffering graphics object. Checks to see if
2049:             * the graph bounds has changed since the last time the off screen image was
2050:             * created and if so, creates a new image.
2051:             * 
2052:             * @return the off screen graphics
2053:             */
2054:            public Graphics getOffgraphics() {
2055:                if (!isDoubleBuffered()) {
2056:                    // If double buffering is not enabled
2057:                    return null;
2058:                }
2059:                // Get the bounds of the entire graph
2060:                Rectangle2D graphBounds = getBounds();
2061:                // Get the visible area if in a scroll pane
2062:                Rectangle2D viewPortBounds = null;//getViewPortBounds();
2063:                // The result can be null if not a view port.
2064:                if (viewPortBounds == null) {
2065:                    viewPortBounds = graphBounds;
2066:                }
2067:                // Find the size of the double buffer in the JVM
2068:                int x = Math.max(0, (int) viewPortBounds.getX()
2069:                        - (int) offscreenBuffer);
2070:                int y = Math.max(0, (int) viewPortBounds.getY()
2071:                        - (int) offscreenBuffer);
2072:                int width = (int) viewPortBounds.getWidth()
2073:                        + (int) offscreenBuffer * 2;
2074:                int height = (int) viewPortBounds.getHeight()
2075:                        + (int) offscreenBuffer * 2;
2076:                // Code below used to work out max possible screen size, might not
2077:                // be needed in JVM 1.6?
2078:                //		try {
2079:                //		Rectangle virtualBounds = new Rectangle();
2080:                //		GraphicsEnvironment ge = GraphicsEnvironment
2081:                //		.getLocalGraphicsEnvironment();
2082:                //		GraphicsDevice[] devices = ge.getScreenDevices();
2083:                //		for (int i = 0; i < devices.length; i++) {
2084:                //		GraphicsConfiguration gc = devices[i].getDefaultConfiguration();
2085:                //		virtualBounds = virtualBounds.union(gc.getBounds());
2086:                //		}
2087:                //		doubleBufferSize = new Dimension(virtualBounds.width,
2088:                //		virtualBounds.height);
2089:                //		} catch (HeadlessException e) {
2090:                //		doubleBufferSize = new Dimension((int) graphBounds.getWidth(), (int)
2091:                //		graphBounds
2092:                //		.getHeight());
2093:                //		}
2094:                // If the screen size exceed either of the graph dimensions, limit them
2095:                // to the graph's
2096:                if (width > graphBounds.getWidth()) {
2097:                    width = (int) graphBounds.getWidth();
2098:                }
2099:                if (height > graphBounds.getHeight()) {
2100:                    height = (int) graphBounds.getHeight();
2101:                }
2102:
2103:                Rectangle2D newOffscreenBuffer = new Rectangle2D.Double(0, 0,
2104:                        width, height);
2105:                // Check whether the visible area is completely contained within the
2106:                // buffer. If not, the buffer need to be re-generated
2107:                if ((offscreen == null || offgraphics == null || offscreenBounds == null)
2108:                        || !(offscreenBounds.contains(newOffscreenBuffer))) {
2109:                    if (offscreen != null) {
2110:                        offscreen.flush();
2111:                    }
2112:                    if (offgraphics != null) {
2113:                        offgraphics.dispose();
2114:                    }
2115:                    offscreen = null;
2116:                    offgraphics = null;
2117:                    if (offscreen == null && volatileOffscreen) {
2118:                        try {
2119:                            offscreen = createVolatileImage(width, height);
2120:                        } catch (OutOfMemoryError e) {
2121:                            offscreen = null;
2122:                            offgraphics = null;
2123:                        }
2124:                    }
2125:                    if (offscreen == null) {
2126:                        // Probably running in headless mode, try to create a buffered
2127:                        // image.
2128:                        createBufferedImage(width, height);
2129:                    }
2130:                    if (offscreen == null) {
2131:                        // TODO assume the graph is too large and only buffer part
2132:                        // of it, might also be faster to calculate in
2133:                        // advance whether they is enough memory to create image
2134:                        // rather than let it try and throw error.
2135:                        return null;
2136:                    }
2137:                    setupOffScreen(x, y, width, height, newOffscreenBuffer);
2138:                } else if (offscreen instanceof  VolatileImage) {
2139:                    int valCode = ((VolatileImage) offscreen)
2140:                            .validate(getGraphicsConfiguration());
2141:                    if (!volatileOffscreen) {
2142:                        offscreen.flush();
2143:                        offgraphics.dispose();
2144:                        offscreen = null;
2145:                        offgraphics = null;
2146:                        createBufferedImage(width, height);
2147:                        setupOffScreen(x, y, width, height, newOffscreenBuffer);
2148:                    } else if (valCode == VolatileImage.IMAGE_INCOMPATIBLE) {
2149:                        offscreen.flush();
2150:                        offgraphics.dispose();
2151:                        try {
2152:                            offscreen = createVolatileImage(width, height);
2153:                        } catch (OutOfMemoryError e) {
2154:                            offscreen = null;
2155:                            offgraphics = null;
2156:                            return null;
2157:                        }
2158:                        setupOffScreen(x, y, width, height, newOffscreenBuffer);
2159:                    } else if (valCode == VolatileImage.IMAGE_RESTORED) {
2160:                        setOffscreenValid(false);
2161:                    }
2162:                }
2163:                if (!isOffscreenValid()) {
2164:                    offgraphics.setColor(getBackground());
2165:                    offgraphics.setPaintMode();
2166:                    offgraphics.fillRect(0, 0, (int) graphBounds.getWidth(),
2167:                            (int) graphBounds.getHeight());
2168:                    ((BasicGraphUI) getUI()).drawGraph(offgraphics, null);
2169:                    offscreenValid = true;
2170:                }
2171:                return offgraphics;
2172:            }
2173:
2174:            /**
2175:             * Utility method to create a standard buffered image
2176:             * @param width
2177:             * @param height
2178:             */
2179:            protected void createBufferedImage(int width, int height) {
2180:                GraphicsConfiguration graphicsConfig = getGraphicsConfiguration();
2181:                if (graphicsConfig != null) {
2182:                    try {
2183:                        offscreen = graphicsConfig.createCompatibleImage(width,
2184:                                height, Transparency.OPAQUE);
2185:                    } catch (OutOfMemoryError e) {
2186:                        offscreen = null;
2187:                        offgraphics = null;
2188:                    }
2189:                } else {
2190:                    try {
2191:                        offscreen = new BufferedImage(width, height,
2192:                                BufferedImage.TYPE_INT_RGB);
2193:                    } catch (OutOfMemoryError e) {
2194:                        offscreen = null;
2195:                        offgraphics = null;
2196:                    }
2197:                }
2198:            }
2199:
2200:            /**
2201:             * Utility method that initialises the offscreen graphics area
2202:             * @param x
2203:             * @param y
2204:             * @param width
2205:             * @param height
2206:             * @param newOffscreenBuffer
2207:             */
2208:            protected void setupOffScreen(int x, int y, int width, int height,
2209:                    Rectangle2D newOffscreenBuffer) {
2210:                offgraphics = offscreen.getGraphics();
2211:                setOffscreenValid(false);
2212:                offgraphics.setColor(getBackground());
2213:                offgraphics.setPaintMode();
2214:                offgraphics.fillRect(0, 0, width, height);
2215:                offscreenBounds = newOffscreenBuffer;
2216:                offscreenOffset = new Point2D.Double(x, y);
2217:            }
2218:
2219:            /**
2220:             * @return the offscreen
2221:             */
2222:            public Image getOffscreen() {
2223:                return offscreen;
2224:            }
2225:
2226:            /**
2227:             * Utility method to draw the off screen buffer
2228:             * 
2229:             * @param dx1
2230:             *            the <i>x</i> coordinate of the first corner of the
2231:             *            destination rectangle.
2232:             * @param dy1
2233:             *            the <i>y</i> coordinate of the first corner of the
2234:             *            destination rectangle.
2235:             * @param dx2
2236:             *            the <i>x</i> coordinate of the second corner of the
2237:             *            destination rectangle.
2238:             * @param dy2
2239:             *            the <i>y</i> coordinate of the second corner of the
2240:             *            destination rectangle.
2241:             * @param sx1
2242:             *            the <i>x</i> coordinate of the first corner of the source
2243:             *            rectangle.
2244:             * @param sy1
2245:             *            the <i>y</i> coordinate of the first corner of the source
2246:             *            rectangle.
2247:             * @param sx2
2248:             *            the <i>x</i> coordinate of the second corner of the source
2249:             *            rectangle.
2250:             * @param sy2
2251:             *            the <i>y</i> coordinate of the second corner of the source
2252:             *            rectangle.
2253:             * @return <code>true</code> if the current output representation is
2254:             *         complete; <code>false</code> otherwise.
2255:             */
2256:            public boolean drawImage(int dx1, int dy1, int dx2, int dy2,
2257:                    int sx1, int sy1, int sx2, int sy2) {
2258:                getOffgraphics();
2259:                return getGraphics().drawImage(offscreen, (int) sx1, (int) sy1,
2260:                        (int) sx2, (int) sy2, (int) sx1, (int) sy1, (int) sx2,
2261:                        (int) sy2, this );
2262:            }
2263:
2264:            public boolean drawImage(Graphics g) {
2265:                Rectangle rect = getBounds();
2266:                return getGraphics()
2267:                        .drawImage(offscreen, rect.x, rect.y,
2268:                                rect.x + rect.width, rect.y + rect.height,
2269:                                rect.x, rect.y, rect.x + rect.width,
2270:                                rect.y + rect.height, this );
2271:            }
2272:
2273:            /**
2274:             * Returns the background image.
2275:             * 
2276:             * @return Returns the backgroundImage.
2277:             */
2278:            public ImageIcon getBackgroundImage() {
2279:                return backgroundImage;
2280:            }
2281:
2282:            /**
2283:             * Sets the background image. Fires a property change event for
2284:             * {@link #PROPERTY_BACKGROUNDIMAGE}.
2285:             * 
2286:             * @param backgroundImage
2287:             *            The backgroundImage to set.
2288:             */
2289:            public void setBackgroundImage(ImageIcon backgroundImage) {
2290:                ImageIcon oldValue = this .backgroundImage;
2291:                this .backgroundImage = backgroundImage;
2292:                firePropertyChange(PROPERTY_BACKGROUNDIMAGE, oldValue,
2293:                        backgroundImage);
2294:            }
2295:
2296:            /**
2297:             * @return the backgroundScaled
2298:             */
2299:            public boolean isBackgroundScaled() {
2300:                return backgroundScaled;
2301:            }
2302:
2303:            /**
2304:             * @return the offscreenValid
2305:             */
2306:            public boolean isOffscreenValid() {
2307:                return offscreenValid;
2308:            }
2309:
2310:            /**
2311:             * @param offscreenValid
2312:             *            the offscreenValid to set
2313:             */
2314:            public void setOffscreenValid(boolean offscreenValid) {
2315:                this .offscreenValid = offscreenValid;
2316:            }
2317:
2318:            /**
2319:             * @return the offscreenOffset
2320:             */
2321:            public Point2D getOffscreenOffset() {
2322:                return offscreenOffset;
2323:            }
2324:
2325:            /**
2326:             * @param offscreenOffset the offscreenOffset to set
2327:             */
2328:            public void setOffscreenOffset(Point2D offscreenOffset) {
2329:                this .offscreenOffset = offscreenOffset;
2330:            }
2331:
2332:            /**
2333:             * @return the volatileOffscreen
2334:             */
2335:            public boolean isVolatileOffscreen() {
2336:                return volatileOffscreen;
2337:            }
2338:
2339:            /**
2340:             * @param volatileOffscreen the volatileOffscreen to set
2341:             */
2342:            public void setVolatileOffscreen(boolean volatileOffscreen) {
2343:                this .volatileOffscreen = volatileOffscreen;
2344:            }
2345:
2346:            /**
2347:             * @param backgroundScaled
2348:             *            the backgroundScaled to set
2349:             */
2350:            public void setBackgroundScaled(boolean backgroundScaled) {
2351:                this .backgroundScaled = backgroundScaled;
2352:            }
2353:
2354:            /**
2355:             * @return the backgroundComponent
2356:             */
2357:            public Component getBackgroundComponent() {
2358:                return backgroundComponent;
2359:            }
2360:
2361:            /**
2362:             * @param backgroundComponent
2363:             *            the backgroundComponent to set
2364:             */
2365:            public void setBackgroundComponent(Component backgroundComponent) {
2366:                this .backgroundComponent = backgroundComponent;
2367:            }
2368:
2369:            /**
2370:             * Returns the <code>GraphModel</code> that is providing the data.
2371:             * 
2372:             * @return the model that is providing the data
2373:             */
2374:            public GraphModel getModel() {
2375:                return graphModel;
2376:            }
2377:
2378:            /**
2379:             * Sets the <code>GraphModel</code> that will provide the data. Note:
2380:             * Updates the current GraphLayoutCache's model using setModel if the
2381:             * GraphLayoutCache points to a different model.
2382:             * <p>
2383:             * Fires a property change for the GRAPH_MODEL_PROPERTY.
2384:             * 
2385:             * @param newModel
2386:             *            the <code>GraphModel</code> that is to provide the data
2387:             */
2388:            public void setModel(GraphModel newModel) {
2389:                GraphModel oldModel = graphModel;
2390:                graphModel = newModel;
2391:                firePropertyChange(GRAPH_MODEL_PROPERTY, oldModel, graphModel);
2392:                // FIX: Use Listener
2393:                if (graphLayoutCache != null
2394:                        && graphLayoutCache.getModel() != graphModel)
2395:                    graphLayoutCache.setModel(graphModel);
2396:                clearSelection();
2397:                invalidate();
2398:            }
2399:
2400:            /**
2401:             * Returns the <code>GraphLayoutCache</code> that is providing the
2402:             * view-data.
2403:             * 
2404:             * @return the view that is providing the view-data
2405:             */
2406:            public GraphLayoutCache getGraphLayoutCache() {
2407:                return graphLayoutCache;
2408:            }
2409:
2410:            /**
2411:             * Sets the <code>GraphLayoutCache</code> that will provide the view-data.
2412:             * <p>
2413:             * Note: Updates the graphs's model using using the model from the layout
2414:             * cache.
2415:             * <p>
2416:             * Fires a property change for the GRAPH_LAYOUT_CACHE_PROPERTY.
2417:             * 
2418:             * @param newLayoutCache
2419:             *            the <code>GraphLayoutCache</code> that is to provide the
2420:             *            view-data
2421:             */
2422:            public void setGraphLayoutCache(GraphLayoutCache newLayoutCache) {
2423:                GraphLayoutCache oldLayoutCache = graphLayoutCache;
2424:                graphLayoutCache = newLayoutCache;
2425:                firePropertyChange(GRAPH_LAYOUT_CACHE_PROPERTY, oldLayoutCache,
2426:                        graphLayoutCache);
2427:                if (graphLayoutCache != null
2428:                        && graphLayoutCache.getModel() != getModel())
2429:                    setModel(graphLayoutCache.getModel());
2430:                invalidate();
2431:            }
2432:
2433:            /**
2434:             * Returns the <code>MarqueeHandler</code> that will handle marquee
2435:             * selection.
2436:             */
2437:            public BasicMarqueeHandler getMarqueeHandler() {
2438:                return marquee;
2439:            }
2440:
2441:            /**
2442:             * Sets the <code>MarqueeHandler</code> that will handle marquee
2443:             * selection.
2444:             * 
2445:             * @param newMarquee
2446:             *            the <code>BasicMarqueeHandler</code> that is to provide
2447:             *            marquee handling
2448:             */
2449:            public void setMarqueeHandler(BasicMarqueeHandler newMarquee) {
2450:                BasicMarqueeHandler oldMarquee = marquee;
2451:                marquee = newMarquee;
2452:                firePropertyChange(MARQUEE_HANDLER_PROPERTY, oldMarquee,
2453:                        newMarquee);
2454:                invalidate();
2455:            }
2456:
2457:            /**
2458:             * Determines what happens when editing is interrupted by selecting another
2459:             * cell in the graph, a change in the graph's data, or by some other means.
2460:             * Setting this property to <code>true</code> causes the changes to be
2461:             * automatically saved when editing is interrupted.
2462:             * <p>
2463:             * Fires a property change for the INVOKES_STOP_CELL_EDITING_PROPERTY.
2464:             * 
2465:             * @param newValue
2466:             *            true means that <code>stopCellEditing</code> is invoked when
2467:             *            editing is interruped, and data is saved; false means that
2468:             *            <code>cancelCellEditing</code> is invoked, and changes are
2469:             *            lost
2470:             */
2471:            public void setInvokesStopCellEditing(boolean newValue) {
2472:                boolean oldValue = invokesStopCellEditing;
2473:                invokesStopCellEditing = newValue;
2474:                firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY,
2475:                        oldValue, newValue);
2476:            }
2477:
2478:            /**
2479:             * Returns the indicator that tells what happens when editing is
2480:             * interrupted.
2481:             * 
2482:             * @return the indicator that tells what happens when editing is interrupted
2483:             * @see #setInvokesStopCellEditing
2484:             * 
2485:             */
2486:            public boolean getInvokesStopCellEditing() {
2487:                return invokesStopCellEditing;
2488:            }
2489:
2490:            /**
2491:             * Returns <code>true</code> if the graph and the cell are editable. This
2492:             * is invoked from the UI before editing begins to ensure that the given
2493:             * cell can be edited.
2494:             * 
2495:             * @return true if the specified cell is editable
2496:             * @see #isEditable
2497:             * 
2498:             */
2499:            public boolean isCellEditable(Object cell) {
2500:                if (cell != null) {
2501:                    CellView view = graphLayoutCache.getMapping(cell, false);
2502:                    if (view != null) {
2503:                        return isEditable()
2504:                                && GraphConstants.isEditable(view
2505:                                        .getAllAttributes());
2506:                    }
2507:                }
2508:                return false;
2509:            }
2510:
2511:            /**
2512:             * Overrides <code>JComponent</code>'s<code>getToolTipText</code>
2513:             * method in order to allow the graph to create a tooltip for the topmost
2514:             * cell under the mousepointer. This differs from JTree where the renderers
2515:             * tooltip is used.
2516:             * <p>
2517:             * NOTE: For <code>JGraph</code> to properly display tooltips of its
2518:             * renderers, <code>JGraph</code> must be a registered component with the
2519:             * <code>ToolTipManager</code>. This can be done by invoking
2520:             * <code>ToolTipManager.sharedInstance().registerComponent(graph)</code>.
2521:             * This is not done automatically!
2522:             * 
2523:             * @param e
2524:             *            the <code>MouseEvent</code> that initiated the
2525:             *            <code>ToolTip</code> display
2526:             * @return a string containing the tooltip or <code>null</code> if
2527:             *         <code>event</code> is null
2528:             */
2529:            public String getToolTipText(MouseEvent e) {
2530:                if (e != null) {
2531:                    Object cell = getFirstCellForLocation(e.getX(), e.getY());
2532:                    CellView view = getGraphLayoutCache().getMapping(cell,
2533:                            false);
2534:                    if (view != null) {
2535:                        Component c = view.getRendererComponent(this , false,
2536:                                false, false);
2537:                        if (c instanceof  JComponent) {
2538:                            Rectangle2D rect = getCellBounds(cell);
2539:                            Point2D where = fromScreen(e.getPoint());
2540:                            // Pass the event to the renderer in graph coordinates;
2541:                            // the renderer is ignorant of screen scaling
2542:                            e = new MouseEvent(c, e.getID(), e.getWhen(), e
2543:                                    .getModifiers(), (int) (where.getX() - rect
2544:                                    .getX()),
2545:                                    (int) (where.getY() - rect.getY()), e
2546:                                            .getClickCount(), e
2547:                                            .isPopupTrigger());
2548:                            return ((JComponent) c).getToolTipText(e);
2549:                        }
2550:                    }
2551:                }
2552:                return super .getToolTipText(e);
2553:            }
2554:
2555:            //
2556:            // The following are convenience methods that get forwarded to the
2557:            // current GraphSelectionModel.
2558:            //
2559:            /**
2560:             * Sets the graph's selection model. When a <code>null</code> value is
2561:             * specified an emtpy <code>selectionModel</code> is used, which does not
2562:             * allow selections.
2563:             * 
2564:             * @param selectionModel
2565:             *            the <code>GraphSelectionModel</code> to use, or
2566:             *            <code>null</code> to disable selections
2567:             * @see GraphSelectionModel
2568:             * 
2569:             */
2570:            public void setSelectionModel(GraphSelectionModel selectionModel) {
2571:                if (selectionModel == null)
2572:                    selectionModel = EmptySelectionModel.sharedInstance();
2573:                GraphSelectionModel oldValue = this .selectionModel;
2574:                // Remove Redirector From Old Selection Model
2575:                if (this .selectionModel != null && selectionRedirector != null)
2576:                    this .selectionModel
2577:                            .removeGraphSelectionListener(selectionRedirector);
2578:                this .selectionModel = selectionModel;
2579:                // Add Redirector To New Selection Model
2580:                if (selectionRedirector != null)
2581:                    this .selectionModel
2582:                            .addGraphSelectionListener(selectionRedirector);
2583:                firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue,
2584:                        this .selectionModel);
2585:            }
2586:
2587:            /**
2588:             * Returns the model for selections. This should always return a non-
2589:             * <code>null</code> value. If you don't want to allow anything to be
2590:             * selected set the selection model to <code>null</code>, which forces an
2591:             * empty selection model to be used.
2592:             * 
2593:             * @return the current selection model
2594:             * @see #setSelectionModel
2595:             * 
2596:             */
2597:            public GraphSelectionModel getSelectionModel() {
2598:                return selectionModel;
2599:            }
2600:
2601:            /**
2602:             * Clears the selection.
2603:             */
2604:            public void clearSelection() {
2605:                getSelectionModel().clearSelection();
2606:            }
2607:
2608:            /**
2609:             * Returns true if the selection is currently empty.
2610:             * 
2611:             * @return true if the selection is currently empty
2612:             */
2613:            public boolean isSelectionEmpty() {
2614:                return getSelectionModel().isSelectionEmpty();
2615:            }
2616:
2617:            /**
2618:             * Adds a listener for <code>GraphSelection</code> events.
2619:             * 
2620:             * @param tsl
2621:             *            the <code>GraphSelectionListener</code> that will be
2622:             *            notified when a cell is selected or deselected (a "negative
2623:             *            selection")
2624:             */
2625:            public void addGraphSelectionListener(GraphSelectionListener tsl) {
2626:                listenerList.add(GraphSelectionListener.class, tsl);
2627:                if (listenerList.getListenerCount(GraphSelectionListener.class) != 0
2628:                        && selectionRedirector == null) {
2629:                    selectionRedirector = new GraphSelectionRedirector();
2630:                    selectionModel
2631:                            .addGraphSelectionListener(selectionRedirector);
2632:                }
2633:            }
2634:
2635:            /**
2636:             * Removes a <code>GraphSelection</code> listener.
2637:             * 
2638:             * @param tsl
2639:             *            the <code>GraphSelectionListener</code> to remove
2640:             */
2641:            public void removeGraphSelectionListener(GraphSelectionListener tsl) {
2642:                listenerList.remove(GraphSelectionListener.class, tsl);
2643:                if (listenerList.getListenerCount(GraphSelectionListener.class) == 0
2644:                        && selectionRedirector != null) {
2645:                    selectionModel
2646:                            .removeGraphSelectionListener(selectionRedirector);
2647:                    selectionRedirector = null;
2648:                }
2649:            }
2650:
2651:            /**
2652:             * Notifies all listeners that have registered interest for notification on
2653:             * this event type. The event instance is lazily created using the
2654:             * parameters passed into the fire method.
2655:             * 
2656:             * @param e
2657:             *            the <code>GraphSelectionEvent</code> generated by the
2658:             *            <code>GraphSelectionModel</code> when a cell is selected or
2659:             *            deselected
2660:             * @see javax.swing.event.EventListenerList
2661:             * 
2662:             */
2663:            protected void fireValueChanged(GraphSelectionEvent e) {
2664:                // Guaranteed to return a non-null array
2665:                Object[] listeners = listenerList.getListenerList();
2666:                // Process the listeners last to first, notifying
2667:                // those that are interested in this event
2668:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
2669:                    if (listeners[i] == GraphSelectionListener.class) {
2670:                        ((GraphSelectionListener) listeners[i + 1])
2671:                                .valueChanged(e);
2672:                    }
2673:                }
2674:            }
2675:
2676:            /**
2677:             * Selects the specified cell.
2678:             * 
2679:             * @param cell
2680:             *            the <code>Object</code> specifying the cell to select
2681:             */
2682:            public void setSelectionCell(Object cell) {
2683:                getSelectionModel().setSelectionCell(cell);
2684:            }
2685:
2686:            /**
2687:             * Selects the specified cells.
2688:             * 
2689:             * @param cells
2690:             *            an array of objects that specifies the cells to select
2691:             */
2692:            public void setSelectionCells(Object[] cells) {
2693:                getSelectionModel().setSelectionCells(cells);
2694:            }
2695:
2696:            /**
2697:             * Adds the cell identified by the specified <code>Object</code> to the
2698:             * current selection.
2699:             * 
2700:             * @param cell
2701:             *            the cell to be added to the selection
2702:             */
2703:            public void addSelectionCell(Object cell) {
2704:                getSelectionModel().addSelectionCell(cell);
2705:            }
2706:
2707:            /**
2708:             * Adds each cell in the array of cells to the current selection.
2709:             * 
2710:             * @param cells
2711:             *            an array of objects that specifies the cells to add
2712:             */
2713:            public void addSelectionCells(Object[] cells) {
2714:                getSelectionModel().addSelectionCells(cells);
2715:            }
2716:
2717:            /**
2718:             * Removes the cell identified by the specified Object from the current
2719:             * selection.
2720:             * 
2721:             * @param cell
2722:             *            the cell to be removed from the selection
2723:             */
2724:            public void removeSelectionCell(Object cell) {
2725:                getSelectionModel().removeSelectionCell(cell);
2726:            }
2727:
2728:            /**
2729:             * Returns the first selected cell.
2730:             * 
2731:             * @return the <code>Object</code> for the first selected cell, or
2732:             *         <code>null</code> if nothing is currently selected
2733:             */
2734:            public Object getSelectionCell() {
2735:                return getSelectionModel().getSelectionCell();
2736:            }
2737:
2738:            /**
2739:             * Returns all selected cells.
2740:             * 
2741:             * @return an array of objects representing the selected cells, or
2742:             *         <code>null</code> if nothing is currently selected
2743:             */
2744:            public Object[] getSelectionCells() {
2745:                return getSelectionModel().getSelectionCells();
2746:            }
2747:
2748:            /**
2749:             * Returns all selected cells in <code>cells</code>.
2750:             */
2751:            public Object[] getSelectionCells(Object[] cells) {
2752:                if (cells != null) {
2753:                    List selected = new ArrayList(cells.length);
2754:                    for (int i = 0; i < cells.length; i++) {
2755:                        if (isCellSelected(cells[i]))
2756:                            selected.add(cells[i]);
2757:                    }
2758:                    return selected.toArray();
2759:                }
2760:                return null;
2761:            }
2762:
2763:            /**
2764:             * Returns the selection cell at the specified location.
2765:             * 
2766:             * @return Returns the selection cell for <code>pt</code>.
2767:             */
2768:            public Object getSelectionCellAt(Point2D pt) {
2769:                pt = fromScreen((Point2D) pt.clone());
2770:                Object[] cells = getSelectionCells();
2771:                if (cells != null) {
2772:                    for (int i = 0; i < cells.length; i++)
2773:                        if (getCellBounds(cells[i]).contains(pt.getX(),
2774:                                pt.getY()))
2775:                            return cells[i];
2776:                }
2777:                return null;
2778:            }
2779:
2780:            /**
2781:             * Returns the number of cells selected.
2782:             * 
2783:             * @return the number of cells selected
2784:             */
2785:            public int getSelectionCount() {
2786:                return getSelectionModel().getSelectionCount();
2787:            }
2788:
2789:            /**
2790:             * Returns true if the cell is currently selected.
2791:             * 
2792:             * @param cell
2793:             *            an object identifying a cell
2794:             * @return true if the cell is selected
2795:             */
2796:            public boolean isCellSelected(Object cell) {
2797:                return getSelectionModel().isCellSelected(cell);
2798:            }
2799:
2800:            /**
2801:             * Scrolls to the specified cell. Only works when this <code>JGraph</code>
2802:             * is contained in a <code>JScrollPane</code>.
2803:             * 
2804:             * @param cell
2805:             *            the object identifying the cell to bring into view
2806:             */
2807:            public void scrollCellToVisible(Object cell) {
2808:                Rectangle2D bounds = getCellBounds(cell);
2809:                if (bounds != null) {
2810:                    Rectangle2D b2 = toScreen((Rectangle2D) bounds.clone());
2811:                    scrollRectToVisible(new Rectangle((int) b2.getX(), (int) b2
2812:                            .getY(), (int) b2.getWidth(), (int) b2.getHeight()));
2813:                }
2814:            }
2815:
2816:            /**
2817:             * Makes sure the specified point is visible.
2818:             * 
2819:             * @param p
2820:             *            the point that should be visible
2821:             */
2822:            public void scrollPointToVisible(Point2D p) {
2823:                if (p != null)
2824:                    scrollRectToVisible(new Rectangle((int) p.getX(), (int) p
2825:                            .getY(), 1, 1));
2826:            }
2827:
2828:            /**
2829:             * Returns true if the graph is being edited. The item that is being edited
2830:             * can be obtained using <code>getEditingCell</code>.
2831:             * 
2832:             * @return true if the user is currently editing a cell
2833:             * @see #getSelectionCell
2834:             * 
2835:             */
2836:            public boolean isEditing() {
2837:                GraphUI graph = getUI();
2838:                if (graph != null)
2839:                    return graph.isEditing(this );
2840:                return false;
2841:            }
2842:
2843:            /**
2844:             * Ends the current editing session. (The
2845:             * <code>DefaultGraphCellEditor</code> object saves any edits that are
2846:             * currently in progress on a cell. Other implementations may operate
2847:             * differently.) Has no effect if the tree isn't being edited. <blockquote>
2848:             * <b>Note: </b> <br>
2849:             * To make edit-saves automatic whenever the user changes their position in
2850:             * the graph, use {@link #setInvokesStopCellEditing}. </blockquote>
2851:             * 
2852:             * @return true if editing was in progress and is now stopped, false if
2853:             *         editing was not in progress
2854:             */
2855:            public boolean stopEditing() {
2856:                GraphUI graph = getUI();
2857:                if (graph != null)
2858:                    return graph.stopEditing(this );
2859:                return false;
2860:            }
2861:
2862:            /**
2863:             * Cancels the current editing session. Has no effect if the graph isn't
2864:             * being edited.
2865:             */
2866:            public void cancelEditing() {
2867:                GraphUI graph = getUI();
2868:                if (graph != null)
2869:                    graph.cancelEditing(this );
2870:            }
2871:
2872:            /**
2873:             * Selects the specified cell and initiates editing. The edit-attempt fails
2874:             * if the <code>CellEditor</code> does not allow editing for the specified
2875:             * item.
2876:             */
2877:            public void startEditingAtCell(Object cell) {
2878:                GraphUI graph = getUI();
2879:                if (graph != null)
2880:                    graph.startEditingAtCell(this , cell);
2881:            }
2882:
2883:            /**
2884:             * Returns the cell that is currently being edited.
2885:             * 
2886:             * @return the cell being edited
2887:             */
2888:            public Object getEditingCell() {
2889:                GraphUI graph = getUI();
2890:                if (graph != null)
2891:                    return graph.getEditingCell(this );
2892:                return null;
2893:            }
2894:
2895:            /**
2896:             * Messaged when the graph has changed enough that we need to resize the
2897:             * bounds, but not enough that we need to remove the cells (e.g cells were
2898:             * inserted into the graph). You should never have to invoke this, the UI
2899:             * will invoke this as it needs to. (Note: This is invoked by GraphUI, eg.
2900:             * after moving.)
2901:             */
2902:            public void graphDidChange() {
2903:                revalidate();
2904:                repaint();
2905:            }
2906:
2907:            /**
2908:             * You should not call this method directly on a JGraph if you are using
2909:             * double buffering.
2910:             * 
2911:             * @see javax.swing.JComponent#repaint(long, int, int, int, int)
2912:             */
2913:            public void repaint(long tm, int x, int y, int width, int height) {
2914:                super .repaint(tm, x, y, width, height);
2915:            }
2916:
2917:            /*
2918:             * (non-Javadoc)
2919:             * 
2920:             * @see javax.swing.JComponent#repaint(java.awt.Rectangle)
2921:             */
2922:            public void repaint(Rectangle r) {
2923:                offscreenValid = false;
2924:                super .repaint(r);
2925:            }
2926:
2927:            /*
2928:             * (non-Javadoc)
2929:             * 
2930:             * @see java.awt.Component#repaint()
2931:             */
2932:            public void repaint() {
2933:                offscreenValid = false;
2934:                super .repaint();
2935:            }
2936:
2937:            /*
2938:             * (non-Javadoc)
2939:             * 
2940:             * @see java.awt.Component#repaint(int, int, int, int)
2941:             */
2942:            public void repaint(int x, int y, int width, int height) {
2943:                offscreenValid = false;
2944:                super .repaint(x, y, width, height);
2945:            }
2946:
2947:            /*
2948:             * (non-Javadoc)
2949:             * 
2950:             * @see java.awt.Component#repaint(long)
2951:             */
2952:            public void repaint(long tm) {
2953:                offscreenValid = false;
2954:                super .repaint(tm);
2955:            }
2956:
2957:            // /* (non-Javadoc)
2958:            // * @see javax.swing.JComponent#isOptimizedDrawingEnabled()
2959:            // */
2960:            // @Override
2961:            // public boolean isOptimizedDrawingEnabled() {
2962:            // return true;
2963:            // }
2964:
2965:            /**
2966:             * Returns a {@link BufferedImage} for the graph using inset as an empty
2967:             * border around the cells of the graph. If bg is null then a transparent
2968:             * background is applied to the image, else the background is filled with
2969:             * the bg color. Therefore, one should only use a null background if the
2970:             * fileformat support transparency, eg. GIF and PNG. For JPG, you can use
2971:             * <code>Color.WHITE</code> for example.
2972:             * 
2973:             * @return Returns an image of the graph.
2974:             */
2975:            public BufferedImage getImage(Color bg, int inset) {
2976:                // TODO, this method could just use the offscreen if available
2977:                Object[] cells = getRoots();
2978:                Rectangle2D bounds = getCellBounds(cells);
2979:                if (bounds != null) {
2980:                    toScreen(bounds);
2981:                    GraphicsConfiguration graphicsConfig = getGraphicsConfiguration();
2982:                    BufferedImage img = null;
2983:                    if (graphicsConfig != null) {
2984:                        img = getGraphicsConfiguration().createCompatibleImage(
2985:                                (int) bounds.getWidth() + 2 * inset,
2986:                                (int) bounds.getHeight() + 2 * inset,
2987:                                (bg != null) ? Transparency.OPAQUE
2988:                                        : Transparency.BITMASK);
2989:                    } else {
2990:                        img = new BufferedImage((int) bounds.getWidth() + 2
2991:                                * inset, (int) bounds.getHeight() + 2 * inset,
2992:                                (bg != null) ? BufferedImage.TYPE_INT_RGB
2993:                                        : BufferedImage.TYPE_INT_ARGB);
2994:                    }
2995:
2996:                    Graphics2D graphics = img.createGraphics();
2997:                    if (bg != null) {
2998:                        graphics.setColor(bg);
2999:                        graphics
3000:                                .fillRect(0, 0, img.getWidth(), img.getHeight());
3001:                    } else {
3002:                        graphics.setComposite(AlphaComposite.getInstance(
3003:                                AlphaComposite.CLEAR, 0.0f));
3004:                        graphics
3005:                                .fillRect(0, 0, img.getWidth(), img.getHeight());
3006:                        graphics.setComposite(AlphaComposite.SrcOver);
3007:                    }
3008:                    graphics.translate((int) (-bounds.getX() + inset),
3009:                            (int) (-bounds.getY() + inset));
3010:                    print(graphics);
3011:                    graphics.dispose();
3012:                    return img;
3013:                }
3014:                return null;
3015:            }
3016:
3017:            /**
3018:             * Serialization support.
3019:             */
3020:            private void writeObject(ObjectOutputStream s) throws IOException {
3021:                Vector values = new Vector();
3022:                s.defaultWriteObject();
3023:                // Save the cellEditor, if its Serializable.
3024:                if (graphModel instanceof  Serializable) {
3025:                    values.addElement("graphModel");
3026:                    values.addElement(graphModel);
3027:                }
3028:                // Save the graphModel, if its Serializable.
3029:                values.addElement("graphLayoutCache");
3030:                values.addElement(graphLayoutCache);
3031:
3032:                // Save the selectionModel, if its Serializable.
3033:                if (selectionModel instanceof  Serializable) {
3034:                    values.addElement("selectionModel");
3035:                    values.addElement(selectionModel);
3036:                }
3037:                // Save the marquee handler, if its Serializable.
3038:                if (marquee instanceof  Serializable) {
3039:                    values.addElement("marquee");
3040:                    values.addElement(marquee);
3041:                }
3042:                s.writeObject(values);
3043:                if (getUIClassID().equals(uiClassID)) {
3044:                    /*
3045:                     * byte count = JComponent.getWriteObjCounter(this);
3046:                     * JComponent.setWriteObjCounter(this, --count);
3047:                     */
3048:                    if (/* count == 0 && */
3049:                    ui != null) {
3050:                        ui.installUI(this );
3051:                    }
3052:                }
3053:            }
3054:
3055:            /**
3056:             * Serialization support.
3057:             */
3058:            private void readObject(ObjectInputStream s) throws IOException,
3059:                    ClassNotFoundException {
3060:                s.defaultReadObject();
3061:                Vector values = (Vector) s.readObject();
3062:                int indexCounter = 0;
3063:                int maxCounter = values.size();
3064:                if (indexCounter < maxCounter
3065:                        && values.elementAt(indexCounter).equals("graphModel")) {
3066:                    graphModel = (GraphModel) values.elementAt(++indexCounter);
3067:                    indexCounter++;
3068:                }
3069:                if (indexCounter < maxCounter
3070:                        && values.elementAt(indexCounter).equals(
3071:                                "graphLayoutCache")) {
3072:                    graphLayoutCache = (GraphLayoutCache) values
3073:                            .elementAt(++indexCounter);
3074:                    indexCounter++;
3075:                }
3076:                if (indexCounter < maxCounter
3077:                        && values.elementAt(indexCounter).equals(
3078:                                "selectionModel")) {
3079:                    selectionModel = (GraphSelectionModel) values
3080:                            .elementAt(++indexCounter);
3081:                    indexCounter++;
3082:                }
3083:                if (indexCounter < maxCounter
3084:                        && values.elementAt(indexCounter).equals("marquee")) {
3085:                    marquee = (BasicMarqueeHandler) values
3086:                            .elementAt(++indexCounter);
3087:                    indexCounter++;
3088:                }
3089:                // Reinstall the redirector.
3090:                if (listenerList.getListenerCount(GraphSelectionListener.class) != 0) {
3091:                    selectionRedirector = new GraphSelectionRedirector();
3092:                    selectionModel
3093:                            .addGraphSelectionListener(selectionRedirector);
3094:                }
3095:            }
3096:
3097:            /**
3098:             * <code>EmptySelectionModel</code> is a <code>GraphSelectionModel</code>
3099:             * that does not allow anything to be selected.
3100:             * <p>
3101:             * <strong>Warning: </strong> Serialized objects of this class will not be
3102:             * compatible with future Swing releases. The current serialization support
3103:             * is appropriate for short term storage or RMI between applications running
3104:             * the same version of Swing. A future release of Swing will provide support
3105:             * for long term persistence.
3106:             */
3107:            public static class EmptySelectionModel extends
3108:                    DefaultGraphSelectionModel {
3109:
3110:                /** Unique shared instance. */
3111:                protected static final EmptySelectionModel sharedInstance = new EmptySelectionModel();
3112:
3113:                /**
3114:                 * A <code>null</code> implementation that constructs an
3115:                 * EmptySelectionModel.
3116:                 */
3117:                public EmptySelectionModel() {
3118:                    super (null);
3119:                }
3120:
3121:                /** Returns a shared instance of an empty selection model. */
3122:                static public EmptySelectionModel sharedInstance() {
3123:                    return sharedInstance;
3124:                }
3125:
3126:                /** A <code>null</code> implementation that selects nothing. */
3127:                public void setSelectionCells(Object[] cells) {
3128:                }
3129:
3130:                /** A <code>null</code> implementation that adds nothing. */
3131:                public void addSelectionCells(Object[] cells) {
3132:                }
3133:
3134:                /** A <code>null</code> implementation that removes nothing. */
3135:                public void removeSelectionCells(Object[] cells) {
3136:                }
3137:            }
3138:
3139:            /**
3140:             * Handles creating a new <code>GraphSelectionEvent</code> with the
3141:             * <code>JGraph</code> as the source and passing it off to all the
3142:             * listeners.
3143:             * <p>
3144:             * <strong>Warning: </strong> Serialized objects of this class will not be
3145:             * compatible with future Swing releases. The current serialization support
3146:             * is appropriate for short term storage or RMI between applications running
3147:             * the same version of Swing. A future release of Swing will provide support
3148:             * for long term persistence.
3149:             */
3150:            protected class GraphSelectionRedirector implements  Serializable,
3151:                    GraphSelectionListener {
3152:
3153:                /**
3154:                 * Invoked by the <code>GraphSelectionModel</code> when the selection
3155:                 * changes.
3156:                 * 
3157:                 * @param e
3158:                 *            the <code>GraphSelectionEvent</code> generated by the
3159:                 *            <code>GraphSelectionModel</code>
3160:                 */
3161:                public void valueChanged(GraphSelectionEvent e) {
3162:                    GraphSelectionEvent newE;
3163:                    newE = (GraphSelectionEvent) e.cloneWithSource(JGraph.this );
3164:                    fireValueChanged(newE);
3165:                }
3166:            } // End of class JGraph.GraphSelectionRedirector
3167:
3168:            //
3169:            // Scrollable interface
3170:            //
3171:            /**
3172:             * Returns the preferred display size of a <code>JGraph</code>. The
3173:             * height is determined from <code>getPreferredWidth</code>.
3174:             * 
3175:             * @return the graph's preferred size
3176:             */
3177:            public Dimension getPreferredScrollableViewportSize() {
3178:                return getPreferredSize();
3179:            }
3180:
3181:            /**
3182:             * Returns the amount to increment when scrolling. The amount is 4.
3183:             * 
3184:             * @param visibleRect
3185:             *            the view area visible within the viewport
3186:             * @param orientation
3187:             *            either <code>SwingConstants.VERTICAL</code> or
3188:             *            <code>SwingConstants.HORIZONTAL</code>
3189:             * @param direction
3190:             *            less than zero to scroll up/left, greater than zero for
3191:             *            down/right
3192:             * @return the "unit" increment for scrolling in the specified direction
3193:             * @see javax.swing.JScrollBar#setUnitIncrement(int)
3194:             * 
3195:             */
3196:            public int getScrollableUnitIncrement(Rectangle visibleRect,
3197:                    int orientation, int direction) {
3198:                if (orientation == SwingConstants.VERTICAL) {
3199:                    return 2;
3200:                }
3201:                return 4;
3202:            }
3203:
3204:            /**
3205:             * Returns the amount for a block increment, which is the height or width of
3206:             * <code>visibleRect</code>, based on <code>orientation</code>.
3207:             * 
3208:             * @param visibleRect
3209:             *            the view area visible within the viewport
3210:             * @param orientation
3211:             *            either <code>SwingConstants.VERTICAL</code> or
3212:             *            <code>SwingConstants.HORIZONTAL</code>
3213:             * @param direction
3214:             *            less than zero to scroll up/left, greater than zero for
3215:             *            down/right.
3216:             * @return the "block" increment for scrolling in the specified direction
3217:             * @see javax.swing.JScrollBar#setBlockIncrement(int)
3218:             * 
3219:             */
3220:            public int getScrollableBlockIncrement(Rectangle visibleRect,
3221:                    int orientation, int direction) {
3222:                return (orientation == SwingConstants.VERTICAL) ? visibleRect.height
3223:                        : visibleRect.width;
3224:            }
3225:
3226:            /**
3227:             * Returns false to indicate that the width of the viewport does not
3228:             * determine the width of the graph, unless the preferred width of the graph
3229:             * is smaller than the viewports width. In other words: ensure that the
3230:             * graph is never smaller than its viewport.
3231:             * 
3232:             * @return false
3233:             * @see Scrollable#getScrollableTracksViewportWidth
3234:             * 
3235:             */
3236:            public boolean getScrollableTracksViewportWidth() {
3237:                if (getParent() instanceof  JViewport) {
3238:                    return (((JViewport) getParent()).getWidth() > getPreferredSize().width);
3239:                }
3240:                return false;
3241:            }
3242:
3243:            /**
3244:             * Returns false to indicate that the height of the viewport does not
3245:             * determine the height of the graph, unless the preferred height of the
3246:             * graph is smaller than the viewports height. In other words: ensure that
3247:             * the graph is never smaller than its viewport.
3248:             * 
3249:             * @return false
3250:             * @see Scrollable#getScrollableTracksViewportHeight
3251:             * 
3252:             */
3253:            public boolean getScrollableTracksViewportHeight() {
3254:                if (getParent() instanceof  JViewport) {
3255:                    return (((JViewport) getParent()).getHeight() > getPreferredSize().height);
3256:                }
3257:                return false;
3258:            }
3259:
3260:            /**
3261:             * Returns a string representation of this <code>JGraph</code>. This
3262:             * method is intended to be used only for debugging purposes, and the
3263:             * content and format of the returned string may vary between
3264:             * implementations. The returned string may be empty but may not be
3265:             * <code>null</code>.
3266:             * 
3267:             * @return a string representation of this <code>JGraph</code>.
3268:             */
3269:            protected String paramString() {
3270:                String editableString = (editable ? "true" : "false");
3271:                String invokesStopCellEditingString = (invokesStopCellEditing ? "true"
3272:                        : "false");
3273:                return super .paramString() + ",editable=" + editableString
3274:                        + ",invokesStopCellEditing="
3275:                        + invokesStopCellEditingString;
3276:            }
3277:
3278:            public static void main(String[] args) {
3279:                System.out.println(VERSION);
3280:            }
3281:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.