
org.jgraph.JGraph Maven / Gradle / Ivy
Show all versions of freak-core Show documentation
/*
* @(#)JGraph.java 1.0 1/1/02
*
* Copyright (c) 2001-2004, Gaudenz Alder
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of JGraph nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.jgraph;
import org.jgraph.event.GraphSelectionEvent;
import org.jgraph.event.GraphSelectionListener;
import org.jgraph.graph.*;
import org.jgraph.plaf.GraphUI;
import javax.accessibility.Accessible;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
/**
* A control that displays a network of related objects using the
* well-known paradigm of a graph.
*
* A JGraph object doesn't actually contain your data; it simply provides
* a view of the data. Like any non-trivial Swing component, the graph gets
* data by querying its data model.
*
* JGraph displays its data by drawing individual elements. Each element
* displayed by the graph contains exactly one item of data, which is
* called a cell. A cell may either be a vertex or an edge. Vertices may
* have neighbours or not, and edges may have source and target vertices
* or not, depending on whether they are connected.
*
* Creating a Graph
*
* The following code creates a JGraph object:
* JGraph graph = new JGraph();
* ...
* JScrollPane graphLayoutCache = new JScrollPane(graph)
*
* The code creates an instance of JGraph and puts it in a scroll pane.
* JGraphs constructor is called with no arguments in this example, which
* causes the constructor to create a sample model.
*
* Editing
*
* JGraph supports in-place editing of text and shapes. These features can
* be disabled using the setEnabled() method, which blocks all features, or
* individually, using the following methods:
*
* setEditable() controls in-place editing of cells. Moving, cloning, sizing,
* and bending, connection and disconnection of edges may also be disabled
* using the respective methods, namemly setMoveable(), setCloneable(),
* setSizeable(), setBendable(), setConnectable() and setDisconnectable().
*
* The model offers fainer control of connection establishment based
* on the passed-in edge and port. The individual cells offer yet
* another level of control in that they may allow/disallow being edited,
* moved, cloned, resized, and shaped, or connected/disconnected to or
* from other cells.
*
* Keyboard Bindings
*
* JGraph defines the following set of keyboard bindings:
*
* - Alt-Click forces marquee selection if over a cell.
*
- Shift- or Ctrl-Select extends or toggles the selection.
*
- Shift-Drag constrains the offset to one direction.
*
- Ctrl-Drag clones the selection.
*
- Doubleclick/F2 starts editing a cell.
*
* You can change the number of clicks that triggers editing using
* setEditClickCount().
*
* Customization
*
* There are a number of additional methods that customize JGraph.
* For example, setMinimumMove() defines the minimum amount of
* pixels before a move operation is initiated. setSnapSize() defines
* the maximum distance for a cell to be selected. setFloatEnabled()
* enables/disables port floating.
*
* With setDisconnectOnMove() you can indicate if the selected subgraph
* should be disconnected from the unselected rest when a move operation
* is initiated. setDragEnabled() enables/disables the use of Drag And
* Drop, and setDropEnabled() sets if the graph accepts Drops from
* external sources.
*
* Customizing a graphs display
*
* JGraph performs some look-and-feel specific painting. You can
* customize this painting in a limited way. For example, you can modify the
* grid using setGridColor() and setGridSize(), and you can change the handle
* colors using setHandleColor() and setLockedHandleColor().
*
* If you want finer control over the rendering, you can subclass one of the
* default renderers, and extend its paint()-method. A renderer is a
* Component-extension that paints a cell based on its attributes. Thus,
* neither the JGraph nor its look-and-feel-specific implementation actually
* contain the code that paints the cell. Instead, the graph uses the cell
* renderers painting code.
*
* Selection
*
* Apart from the single-cell and marquee-selection, JGraphs selection
* model also allows to "step-into" groups, and select children. This
* feature can be disabled using the setAllowsChildSelection() method
* of the selection model instance.
*
* If you are interested in knowing when the selection changes implement
* the GraphSelectionListener
interface and add the instance
* using the method addGraphSelectionListener
.
* valueChanged
will be invoked when the
* selection changes, that is if the user clicks twice on the same
* vertex valueChanged
will only be invoked once.
*
* Change Notification
*
* If you are interested in handling modifications, implement
* the GraphEventHandler
interface and add the instance
* using the method addGraphEventHandler
.
*
* For detection of double-clicks or when a user clicks on a cell,
* regardless of whether or not it was selected, I recommend you
* implement a MouseListener and use getFirstCellForLocation
.
*
* Undo Support
*
* To enable Undo-Support, a GraphUndoManager
must be added
* using addGraphSelectionListener
. The GraphUndoManager
* is an extension of Swing's GraphUndoManager
that maintains
* a command history in the context of multiple views. In this setup, a
* cell may have a set of attributes in each view attached to the model.
*
* For example, consider a position that is stored separately in each view.
* If a node is inserted, the change will be visible in all attached views,
* resulting in a new node that pops-up at the initial position.
* If the node is subsequently moved, say, in view1, this does not constitute
* a change in view2. If view2 does an "undo", the move and the
* insertion must be undone, whereas an "undo" in view1 will only undo
* the previous move operation.
*
* Like all JComponent
classes, you can use {@link InputMap} and
* {@link ActionMap} to associate an {@link Action} object with a
* {@link KeyStroke} and execute the action under specified conditions.
*
* @author Gaudenz Alder
* @version 2.1 16/03/03
*
*/
public class JGraph
// DO NOT REMOVE OR MODIFY THIS LINE!
extends JComponent // JAVA13: org.jgraph.plaf.basic.TransferHandler.JAdapterComponent
implements CellViewFactory, Scrollable, Accessible, Serializable {
public static final String VERSION = "JGraph (v3.1)";
public static final int DOT_GRID_MODE = 0;
public static final int CROSS_GRID_MODE = 1;
public static final int LINE_GRID_MODE = 2;
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "GraphUI";
/** Creates a new event and passes it off the selectionListeners
. */
protected transient GraphSelectionRedirector selectionRedirector;
//
// Bound Properties
//
/** The model that defines the graph displayed by this object. Bound property. */
transient protected GraphModel graphModel;
/** The view that defines the display properties of the model. Bound property. */
transient protected GraphLayoutCache graphLayoutCache;
/** Handler for marquee selection. */
transient protected BasicMarqueeHandler marquee;
/** Models the set of selected objects in this graph. Bound property. */
transient protected GraphSelectionModel selectionModel;
/** Scale of the graph. Default is 1. Bound property. */
protected double scale = 1.0;
/** True if the graph is anti-aliased. Default is false. Bound property. */
protected boolean antiAliased = false;
/** True if the graph allows editing the value of a cell. Bound property. */
protected boolean editable = true;
/** True if the grid is visible. Bound property. */
protected boolean gridVisible = false;
/** The size of the grid in points. Default is 10. Bound property.*/
protected int gridSize = 10;
/** The style of the grid. Use one of the _GRID_MODE constants. */
protected int gridMode = DOT_GRID_MODE;
/** True if the ports are visible. Bound property. */
protected boolean portsVisible = false;
//
// Look-And-Feel dependent
//
/** Highlight Color. Changes when the Look-and-Feel changes. */
protected Color highlightColor = Color.green;
/** Color of the handles and locked handles. Changes when the Look-and-Feel changes. */
protected Color handleColor, lockedHandleColor;
/** Color of the marquee. Changes when the Look-and-Feel changes. */
protected Color marqueeColor;
/** The color of the grid. Changes when the Look-and-Feel changes. */
protected Color gridColor;
//
// Datatransfer
//
/**
* True if Drag-and-Drop should be used for move operations. Default is
* false due to a JDK bug.
*/
protected boolean dragEnabled = false;
/**
* True if the graph accepts transfers from other components (graphs).
* This also affects the clipboard. Default is true.
*/
protected boolean dropEnabled = true;
//
// Unbound Properties
//
/** Number of clicks for editing to start. Default is 2 clicks.*/
protected int editClickCount = 2;
/** True if the graph allows interactions. Default is true. */
protected boolean enabled = true;
/** True if the snap method should be active (snap to grid). */
protected boolean gridEnabled = false;
/** Size of a handle. Default is 3 pixels.*/
protected int handleSize = 3;
/** Maximum distance between a cell and the mousepointer. Default is 4.*/
protected int tolerance = 4;
/** Minimum amount of pixels to start a move transaction. Default is 5. */
protected int minimumMove = 5;
/** True if inserted cells should be selected. Default is false. */
protected boolean selectNewCells = false;
/**
* True if selected edges are disconnected from unselected vertices on move.
* Default is true.
*/
protected boolean disconnectOnMove = false;
/** True if the graph allows move operations. Default is true. */
protected boolean moveable = true;
/** True if the graph allows "ctrl-drag" operations. Default is true. */
protected boolean cloneable = true;
/** True if the graph allows cells to be resized. Default is true. */
protected boolean sizeable = true;
/** True if the graph allows points to be midified/added/removed. Default is true. */
protected boolean bendable = true;
/** True if the graph allows new connections to be established. Default is true. */
protected boolean connectable = true;
/** True if the graph allows existing connections to be removed. Default is true. */
protected boolean disconnectable = true;
/**
* If true, when editing is to be stopped by way of selection changing,
* data in graph changing or other means stopCellEditing
* is invoked, and changes are saved. If false,
* cancelCellEditing
is invoked, and changes
* are discarded. Default is false.
*/
protected boolean invokesStopCellEditing;
/**
* This is set to true for the life of the setUI call.
*/
private boolean settingUI;
//
// Bound propery names
//
/**
* Bound property name for graphModel
.
*/
public final static String GRAPH_MODEL_PROPERTY = "model";
/**
* Bound property name for graphModel
.
*/
public final static String GRAPH_LAYOUT_CACHE_PROPERTY = "view";
/**
* Bound property name for graphModel
.
*/
public final static String MARQUEE_HANDLER_PROPERTY = "marquee";
/**
* Bound property name for editable
.
*/
public final static String EDITABLE_PROPERTY = "editable";
/**
* Bound property name for scale
.
*/
public final static String SCALE_PROPERTY = "scale";
/**
* Bound property name for antiAliased
.
*/
public final static String ANTIALIASED_PROPERTY = "antiAliased";
/**
* Bound property name for gridSize
.
*/
public final static String GRID_SIZE_PROPERTY = "gridSize";
/**
* Bound property name for gridVisible
.
*/
public final static String GRID_VISIBLE_PROPERTY = "gridVisible";
/**
* Bound property name for gridVisible
.
*/
public final static String PORTS_VISIBLE_PROPERTY = "portsVisible";
/**
* Bound property name for selectionModel
.
*/
public final static String SELECTION_MODEL_PROPERTY = "selectionModel";
/**
* Bound property name for messagesStopCellEditing
.
*/
public final static String INVOKES_STOP_CELL_EDITING_PROPERTY =
"invokesStopCellEditing";
/**
* Creates and returns a default GraphLayoutCache
.
*
* @return the default GraphLayoutCache
*/
protected static GraphLayoutCache createDefaultGraphView(JGraph graph) {
return new GraphLayoutCache(graph.getModel(), graph);
}
/**
* Returns an attributeMap for the specified position and color.
*/
public static Map createBounds(int x, int y, Color c) {
Map map = GraphConstants.createMap();
GraphConstants.setBounds(map, new Rectangle(x, y, 90, 30));
GraphConstants.setBorder(map, BorderFactory.createRaisedBevelBorder());
GraphConstants.setBackground(map, c.darker());
GraphConstants.setForeground(map, Color.white);
GraphConstants.setFont(map, GraphConstants.defaultFont.deriveFont(Font.BOLD, 12));
GraphConstants.setOpaque(map, true);
return map;
}
/**
* Returns a JGraph
with a sample model.
*/
public JGraph() {
this(null);
}
/**
* Returns an instance of JGraph
which displays the
* the specified data model.
*
* @param model the GraphModel
to use as the data model
*/
public JGraph(GraphModel model) {
this(model, (GraphLayoutCache) null);
}
/**
* Returns an instance of JGraph
which displays
* the specified data model using the specified view.
*
* @param model the GraphModel
to use as the data model
* @param view the GraphLayoutCache
to use as the view
*/
public JGraph(GraphModel model, GraphLayoutCache view) {
this(model, view, new BasicMarqueeHandler());
}
/**
* Returns an instance of JGraph
which displays
* the specified data model using the specified view.
*
* @param model the GraphModel
to use as the data model
*/
public JGraph(GraphModel model, BasicMarqueeHandler mh) {
this(model, null, mh);
}
/**
* Returns an instance of JGraph
which displays
* the specified data model using the specified view.
*
* @param model the GraphModel
to use as the data model
* @param view the GraphLayoutCache
to use as the view
*/
public JGraph(
GraphModel model,
GraphLayoutCache view,
BasicMarqueeHandler mh) {
selectionModel = new DefaultGraphSelectionModel(this);
setLayout(null);
marquee = mh;
if (view == null)
view = createDefaultGraphView(this);
setGraphLayoutCache(view);
updateUI();
if (model == null) {
model = new DefaultGraphModel();
setModel(model);
} else
setModel(model);
setDoubleBuffered(true);
}
//
// UI-delegate (GraphUI)
//
/**
* Returns the L and F object that renders this component.
* @return the GraphUI object that renders this component
*/
public GraphUI getUI() {
return (GraphUI) ui;
}
/**
* Sets the L and F object that renders this component.
* @param ui the GraphUI L and F object
* @see UIDefaults#getUI(JComponent)
*
*/
public void setUI(GraphUI ui) {
if ((GraphUI) this.ui != ui) {
settingUI = true;
try {
super.setUI(ui);
} finally {
settingUI = false;
}
}
}
/**
* Notification from the UIManager
that the L and F has changed.
* Replaces the current UI object with the latest version from the
* UIManager
. Subclassers can override this to support
* different GraphUIs.
* @see JComponent#updateUI
*
*/
public void updateUI() {
setUI(new org.jgraph.plaf.basic.BasicGraphUI());
invalidate();
}
/**
* Returns the name of the L and F class that renders this component.
* @return the string "GraphUI"
* @see JComponent#getUIClassID
*
*/
public String getUIClassID() {
return uiClassID;
}
//
// Content
//
/**
* Returns all cells that the model contains.
*/
public Object[] getRoots() {
return DefaultGraphModel.getRoots(graphModel);
}
/**
* Returns all cells that intersect the given rectangle.
*/
public Object[] getRoots(Rectangle clip) {
CellView[] views = graphLayoutCache.getRoots(clip);
Object[] cells = new Object[views.length];
for (int i = 0; i < views.length; i++)
cells[i] = views[i].getCell();
return cells;
}
/**
* Returns all cells
including all descendants.
* DEPRECATED: Use getDescendantList instead.
*/
public Object[] getDescendants(Object[] cells) {
Set set = DefaultGraphModel.getDescendants(getModel(), cells);
return set.toArray();
}
/**
* Returns all cells
including all descendants.
*/
public Object[] getDescendantList(Object[] cells) {
return DefaultGraphModel.getDescendantList(getModel(), cells).toArray();
}
/**
* Returns a map of (cell, clone)-pairs for all cells
* and their children. Special care is taken to replace the anchor
* references between ports. (Iterative implementation.)
*/
public Map cloneCells(Object[] cells) {
return graphModel.cloneCells(cells);
}
/**
* Returns the topmost cell at the specified location.
* @param x an integer giving the number of pixels horizontally from
* the left edge of the display area, minus any left margin
* @param y an integer giving the number of pixels vertically from
* the top of the display area, minus any top margin
* @return the topmost cell at the specified location
*/
public Object getFirstCellForLocation(int x, int y) {
return getNextCellForLocation(null, x, y);
}
/**
* Returns the cell at the specified location that is "behind" the
* current
cell. Returns the topmost cell if there are
* no more cells behind current
.
*/
public Object getNextCellForLocation(Object current, int x, int y) {
x /= scale;
y /= scale; // FIX: Consistency with other methods?
CellView cur = graphLayoutCache.getMapping(current, false);
CellView cell = getNextViewAt(cur, x, y);
if (cell != null)
return cell.getCell();
return null;
}
/**
* Returns the bounding rectangle of the specified cell.
*/
public Rectangle getCellBounds(Object cell) {
CellView view = graphLayoutCache.getMapping(cell, false);
if (view != null)
return view.getBounds();
return null;
}
/**
* Returns the bounding rectangle of the specified cells.
*/
public Rectangle getCellBounds(Object[] cells) {
if (cells != null && cells.length > 0) {
Rectangle ret = getCellBounds(cells[0]);
if (ret != null) {
ret = new Rectangle(ret);
for (int i = 1; i < cells.length; i++) {
Rectangle r = getCellBounds(cells[i]);
if (r != null)
SwingUtilities.computeUnion(
r.x,
r.y,
r.width,
r.height,
ret);
}
return ret;
}
}
return null;
}
/**
* Returns the next view at the specified location wrt. current
.
* This is used to iterate overlapping cells, and cells that are grouped.
* The current selection affects this method.
*/
public CellView getNextViewAt(CellView current, int x, int y) {
Object[] sel =
graphLayoutCache.order(getSelectionModel().getSelectables());
CellView[] cells = graphLayoutCache.getMapping(sel);
CellView cell = getNextViewAt(cells, current, x, y);
return cell;
}
/**
* Returns the next view at the specified location wrt. c
* in the specified array of views. The views must be in order, as
* returned, for example, by GraphLayoutCache.order(Object[]).
*/
public CellView getNextViewAt(CellView[] cells, CellView c, int x, int y) {
if (cells != null) {
Rectangle r =
new Rectangle(
x - tolerance,
y - tolerance,
2 * tolerance,
2 * tolerance);
// Iterate through cells and switch to active
// if current is traversed. Cache first cell.
CellView first = null;
boolean active = (c == null);
Graphics g = getGraphics();
for (int i = cells.length - 1; i >= 0; i--) {
if (cells[i] != null && cells[i].intersects(g, r)) {
if (active
&& !selectionModel.isChildrenSelected(cells[i].getCell()))
return cells[i];
else if (first == null)
first = cells[i];
active = active | (cells[i] == c);
}
}
return first;
}
return null;
}
/**
* Convenience method to return the port at the specified location.
*/
public Object getPortForLocation(int x, int y) {
PortView view = getPortViewAt(x, y);
if (view != null)
return view.getCell();
return null;
}
/**
* Returns the portview at the specified location.
*/
public PortView getPortViewAt(int x, int y) {
Rectangle r =
new Rectangle(
x - tolerance,
y - tolerance,
2 * tolerance,
2 * tolerance);
PortView[] ports = graphLayoutCache.getPorts();
for (int i = ports.length - 1; i >= 0; i--)
if (ports[i] != null && ports[i].intersects(getGraphics(), r))
return ports[i];
return null;
}
/**
* Converts the specified value to string. If the value is an instance of
* CellView or the current GraphLayoutCache returns a mapping for value, then
* then value attribute of that CellView is used. (The value is retrieved using
* getAllAttributes.) If the value is an instance
* of DefaultMutableTreeNode (e.g. DefaultGraphCell), then the userobject
* is returned as a String.
*/
public String convertValueToString(Object value) {
CellView view =
(value instanceof CellView)
? (CellView) value
: getGraphLayoutCache().getMapping(value, false);
if (view != null) {
Object newValue = GraphConstants.getValue(view.getAllAttributes());
if (newValue != null)
value = newValue;
else
value = view.getCell();
}
if (value instanceof DefaultMutableTreeNode
&& ((DefaultMutableTreeNode) value).getUserObject() != null)
return ((DefaultMutableTreeNode) value).getUserObject().toString();
else if (value != null)
return value.toString();
return null;
}
//
// Grid and Scale
//
/**
* Returns the given point applied to the grid.
* @param p a point in screen coordinates.
* @return the same point applied to the grid.
*/
public Point snap(Point p) {
if (gridEnabled && p != null) {
double sgs = (double) gridSize * getScale();
p.x = (int) Math.round(Math.round(p.x / sgs) * sgs);
p.y = (int) Math.round(Math.round(p.y / sgs) * sgs);
}
return p;
}
/**
* Returns the given point applied to the grid.
* @return the same point applied to the grid.
*/
public Dimension snap(Dimension d) {
if (gridEnabled && d != null) {
double sgs = (double) gridSize * getScale();
d.width = 1 + (int) Math.round(Math.round(d.width / sgs) * sgs);
d.height = 1 + (int) Math.round(Math.round(d.height / sgs) * sgs);
}
return d;
}
/**
* Upscale the given point in place, ie.
* using the given instance.
* @param p the point to be upscaled
* @return the upscaled point instance
*/
public Point toScreen(Point p) {
if (p == null)
return null;
p.x = (int) Math.round(p.x * scale);
p.y = (int) Math.round(p.y * scale);
return p;
}
/**
* Downscale the given point in place, ie.
* using the given instance.
* @param p the point to be downscaled
* @return the downscaled point instance
*/
public Point fromScreen(Point p) {
if (p == null)
return null;
p.x = (int) Math.round(p.x / scale);
p.y = (int) Math.round(p.y / scale);
return p;
}
/**
* Upscale the given rectangle in place, ie.
* using the given instance.
* @param rect the rectangle to be upscaled
* @return the upscaled rectangle instance
*/
public Rectangle toScreen(Rectangle rect) {
if (rect == null)
return null;
rect.x *= scale;
rect.y *= scale;
rect.width *= scale;
rect.height *= scale;
return rect;
}
/**
* Downscale the given rectangle in place, ie.
* using the given instance.
* @param rect the rectangle to be downscaled
* @return the down-scaled rectangle instance
*/
public Rectangle fromScreen(Rectangle rect) {
if (rect == null)
return null;
rect.x /= scale;
rect.y /= scale;
rect.width /= scale;
rect.height /= scale;
return rect;
}
//
// Cell View Factory
//
/**
* Constructs a view for the specified cell and associates it
* with the specified object using the specified CellMapper.
* This calls refresh on the created CellView to create all
* dependent views.
* Note: The mapping needs to be available before the views
* of child cells and ports are created.
*
* @param cell reference to the object in the model
*/
public CellView createView(Object cell, CellMapper map) {
CellView view = null;
if (graphModel.isPort(cell))
view = createPortView(cell, map);
else if (graphModel.isEdge(cell))
view = createEdgeView(cell, map);
else
view = createVertexView(cell, map);
map.putMapping(cell, view);
view.refresh(true); // Create Dependent Views
view.update();
return view;
}
/**
* Computes and updates the size for view
.
*/
public void updateAutoSize(CellView view) {
if (view != null && !isEditing()
&& GraphConstants.isAutoSize(view.getAllAttributes())) {
Rectangle bounds = view.getBounds();
if (bounds != null) {
Dimension d = getUI().getPreferredSize(this, view);
bounds.setSize(d);
}
}
}
/**
* Constructs an EdgeView view for the specified object.
*/
protected EdgeView createEdgeView(Object e, CellMapper cm) {
if (e instanceof Edge)
return createEdgeView((Edge) e, cm);
else
return new EdgeView(e, this, cm);
}
/**
* Constructs a PortView view for the specified object.
*/
protected PortView createPortView(Object p, CellMapper cm) {
if (p instanceof Port)
return createPortView((Port) p, cm);
else
return new PortView(p, this, cm);
}
/**
* Constructs an EdgeView view for the specified object.
*
* @deprecated replaced by {@link #createEdgeView(Object,CellMapper)}
* since JGraph no longer exposes dependecies on
* GraphCell subclasses (Port, Edge)
*/
protected EdgeView createEdgeView(Edge e, CellMapper cm) {
return new EdgeView(e, this, cm);
}
/**
* Constructs a PortView view for the specified object.
*
* @deprecated replaced by {@link #createPortView(Object,CellMapper)}
* since JGraph no longer exposes dependecies on
* GraphCell subclasses (Port, Edge)
*/
protected PortView createPortView(Port p, CellMapper cm) {
return new PortView(p, this, cm);
}
/**
* Constructs a VertexView view for the specified object.
*/
protected VertexView createVertexView(Object v, CellMapper cm) {
return new VertexView(v, this, cm);
}
//
// Unbound Properties
//
/**
* Returns the number of clicks for editing to start.
*/
public int getEditClickCount() {
return editClickCount;
}
/**
* Sets the number of clicks for editing to start.
*/
public void setEditClickCount(int count) {
editClickCount = count;
}
/**
* Returns true if the graph accepts drops/pastes from external sources.
*/
public boolean isDropEnabled() {
return dropEnabled;
}
/**
* Sets if the graph accepts drops/pastes from external sources.
*/
public void setDropEnabled(boolean flag) {
dropEnabled = flag;
}
/**
* Returns true if the graph uses Drag-and-Drop to move cells.
*/
public boolean isDragEnabled() {
return dragEnabled;
}
/**
* Sets if the graph uses Drag-and-Drop to move cells.
*/
public void setDragEnabled(boolean flag) {
dragEnabled = flag;
}
/*
* Returns true if the graph allows movement of cells.
*/
public boolean isMoveable() {
return moveable;
}
/**
* Sets if the graph allows movement of cells.
*/
public void setMoveable(boolean flag) {
moveable = flag;
}
/**
* Returns true if the graph allows adding/removing/modifying points.
*/
public boolean isBendable() {
return bendable;
}
/**
* Sets if the graph allows adding/removing/modifying points.
*/
public void setBendable(boolean flag) {
bendable = flag;
}
/**
* Returns true if the graph allows new connections to be established.
*/
public boolean isConnectable() {
return connectable;
}
/**
* Setse if the graph allows new connections to be established.
*/
public void setConnectable(boolean flag) {
connectable = flag;
}
/**
* Returns true if the graph allows existing connections to be removed.
*/
public boolean isDisconnectable() {
return disconnectable;
}
/**
* Sets if the graph allows existing connections to be removed.
*/
public void setDisconnectable(boolean flag) {
disconnectable = flag;
}
/**
* Returns true if cells are cloned on CTRL-Drag operations.
*/
public boolean isCloneable() {
return cloneable;
}
/**
* Sets if cells are cloned on CTRL-Drag operations.
*/
public void setCloneable(boolean flag) {
cloneable = flag;
}
/**
* Returns true if the graph allows cells to be resized.
*/
public boolean isSizeable() {
return sizeable;
}
/**
* Sets if the graph allows cells to be resized.
*/
public void setSizeable(boolean flag) {
sizeable = flag;
}
/**
* Returns true if selected edges should be disconnected from
* unselected vertices when they are moved.
*/
public boolean isDisconnectOnMove() {
return disconnectOnMove && disconnectable;
}
/**
* Sets if selected edges should be disconnected from
* unselected vertices when they are moved.
*/
public void setSelectNewCells(boolean flag) {
selectNewCells = flag;
}
/**
* Returns true if selected edges should be disconnected from
* unselected vertices when they are moved.
*/
public boolean isSelectNewCells() {
return selectNewCells;
}
/**
* Sets if selected edges should be disconnected from
* unselected vertices when they are moved.
*/
public void setDisconnectOnMove(boolean flag) {
disconnectOnMove = flag;
}
/**
* Returns true if the grid is active.
* @see #snap
*
*/
public boolean isGridEnabled() {
return gridEnabled;
}
/**
* If set to true, the grid will be active.
* @see #snap
*
*/
public void setGridEnabled(boolean flag) {
gridEnabled = flag;
}
/**
* Returns the maximum distance between the mousepointer and a cell to
* be selected.
*/
public int getTolerance() {
return tolerance;
}
/**
* Sets the maximum distance between the mousepointer and a cell to
* be selected.
*/
public void setTolerance(int size) {
tolerance = size;
}
/**
* Returns the size of the handles.
*/
public int getHandleSize() {
return handleSize;
}
/**
* Sets the size of the handles.
*/
public void setHandleSize(int size) {
handleSize = size;
}
/**
* Returns the miminum amount of pixels for a move operation.
*/
public int getMinimumMove() {
return minimumMove;
}
/**
* Sets the miminum amount of pixels for a move operation.
*/
public void setMinimumMove(int pixels) {
minimumMove = pixels;
}
//
// Laf-Specific color scheme. These colors are changed
// by BasicGraphUI when the laf changes.
//
/**
* Returns the current grid color.
*/
public Color getGridColor() {
return gridColor;
}
/**
* Sets the current grid color.
*/
public void setGridColor(Color newColor) {
gridColor = newColor;
}
/**
* Returns the current handle color.
*/
public Color getHandleColor() {
return handleColor;
}
/**
* Sets the current handle color.
*/
public void setHandleColor(Color newColor) {
handleColor = newColor;
}
/**
* Returns the current second handle color.
*/
public Color getLockedHandleColor() {
return lockedHandleColor;
}
/**
* Sets the current second handle color.
*/
public void setLockedHandleColor(Color newColor) {
lockedHandleColor = newColor;
}
/**
* Returns the current marquee color.
*/
public Color getMarqueeColor() {
return marqueeColor;
}
/**
* Sets the current marquee color.
*/
public void setMarqueeColor(Color newColor) {
marqueeColor = newColor;
}
/**
* Returns the current highlight color.
*/
public Color getHighlightColor() {
return highlightColor;
}
/**
* Sets the current selection highlight color.
*/
public void setHighlightColor(Color newColor) {
highlightColor = newColor;
}
//
// Bound properties
//
/**
* Returns the current scale.
* @return the current scale as a double
*/
public double getScale() {
return scale;
}
/**
* Sets the current scale.
*
* Fires a property change for the SCALE_PROPERTY.
* @param newValue the new scale
*/
public void setScale(double newValue) {
if (newValue > 0) {
double oldValue = this.scale;
scale = newValue;
firePropertyChange(SCALE_PROPERTY, oldValue, newValue);
}
}
/**
* Returns the size of the grid in pixels.
* @return the size of the grid as an int
*/
public int getGridSize() {
return gridSize;
}
/**
* Returns the current grid view mode.
*/
public int getGridMode() {
return gridMode;
}
/**
* Sets the size of the grid.
*
* Fires a property change for the GRID_SIZE_PROPERTY.
* @param newSize the new size of the grid in pixels
*/
public void setGridSize(int newSize) {
int oldValue = this.gridSize;
this.gridSize = newSize;
firePropertyChange(GRID_SIZE_PROPERTY, oldValue, newSize);
}
/**
* Sets the current grid view mode.
*
* @param mode The current grid view mode. Valid values are
* DOT_GRID_MODE
,
* CROSS_GRID_MODE
, and
* LINE_GRID_MODE
.
*/
public void setGridMode(int mode) {
if (mode == DOT_GRID_MODE
|| mode == CROSS_GRID_MODE
|| mode == LINE_GRID_MODE) {
gridMode = mode;
repaint();
}
}
/**
* Returns true if the grid will be visible.
* @return true if the grid is visible
*/
public boolean isGridVisible() {
return gridVisible;
}
/**
* If set to true, the grid will be visible.
* Fires a property change for the GRID_VISIBLE_PROPERTY.
*/
public void setGridVisible(boolean flag) {
boolean oldValue = gridVisible;
gridVisible = flag;
firePropertyChange(GRID_VISIBLE_PROPERTY, oldValue, flag);
}
/**
* Returns true if the ports will be visible.
* @return true if the ports are visible
*/
public boolean isPortsVisible() {
return portsVisible;
}
/**
* If set to true, the ports will be visible.
* Fires a property change for the PORTS_VISIBLE_PROPERTY.
*/
public void setPortsVisible(boolean flag) {
boolean oldValue = portsVisible;
portsVisible = flag;
firePropertyChange(PORTS_VISIBLE_PROPERTY, oldValue, flag);
}
/**
* Returns true if the graph will be anti aliased.
* @return true if the graph is anti aliased
*/
public boolean isAntiAliased() {
return antiAliased;
}
/**
* Sets antialiasing on or off based on the boolean value.
*
* Fires a property change for the ANTIALIASED_PROPERTY.
* @param newValue whether to turn antialiasing on or off
*/
public void setAntiAliased(boolean newValue) {
boolean oldValue = this.antiAliased;
this.antiAliased = newValue;
firePropertyChange(ANTIALIASED_PROPERTY, oldValue, newValue);
}
/**
* Returns true if the graph is editable, ie. if it allows
* cells to be edited.
* @return true if the graph is editable
*/
public boolean isEditable() {
return editable;
}
/**
* Determines whether the graph is editable. Fires a property
* change event if the new setting is different from the existing
* setting.
*
* Note: Editable determines whether the graph allows editing. This
* is not to be confused with enabled, which allows the graph to
* handle mouse events (including editing).
* @param flag a boolean value, true if the graph is editable
*/
public void setEditable(boolean flag) {
boolean oldValue = this.editable;
this.editable = flag;
firePropertyChange(EDITABLE_PROPERTY, oldValue, flag);
}
/**
* Returns the GraphModel
that is providing the data.
* @return the model that is providing the data
*/
public GraphModel getModel() {
return graphModel;
}
/**
* Sets the GraphModel
that will provide the data.
* Note: Updates the current GraphLayoutCache's model using setModel if the
* GraphLayoutCache points to a different model.
* Fires a property change for the GRAPH_MODEL_PROPERTY.
* @param newModel the GraphModel
that is to provide the data
*/
public void setModel(GraphModel newModel) {
GraphModel oldModel = graphModel;
graphModel = newModel;
firePropertyChange(GRAPH_MODEL_PROPERTY, oldModel, graphModel);
// FIX: Use Listener
if (graphLayoutCache != null
&& graphLayoutCache.getModel() != graphModel)
graphLayoutCache.setModel(graphModel);
invalidate();
}
/**
* Returns the GraphLayoutCache
that is providing the view-data.
* @return the view that is providing the view-data
*/
public GraphLayoutCache getGraphLayoutCache() {
return graphLayoutCache;
}
/**
* Sets the GraphLayoutCache
that will provide the view-data.
* Note: Updates the GraphLayoutCache's model using setModel if the
* GraphLayoutCache points to an other model than this graph.
* Fires a property change for the GRAPH_LAYOUT_CACHE_PROPERTY.
* @param newLayoutCache the GraphLayoutCache
that is to provide the view-data
*/
public void setGraphLayoutCache(GraphLayoutCache newLayoutCache) {
GraphLayoutCache oldLayoutCache = graphLayoutCache;
graphLayoutCache = newLayoutCache;
firePropertyChange(
GRAPH_LAYOUT_CACHE_PROPERTY,
oldLayoutCache,
graphLayoutCache);
// FIX: Use Listener
if (graphLayoutCache != null
&& graphLayoutCache.getModel() != getModel())
graphLayoutCache.setModel(getModel());
invalidate();
}
/**
* Returns the MarqueeHandler
that will handle
* marquee selection.
*/
public BasicMarqueeHandler getMarqueeHandler() {
return marquee;
}
/**
* Sets the MarqueeHandler
that will handle
* marquee selection.
*/
public void setMarqueeHandler(BasicMarqueeHandler newMarquee) {
BasicMarqueeHandler oldMarquee = marquee;
marquee = newMarquee;
firePropertyChange(MARQUEE_HANDLER_PROPERTY, oldMarquee, newMarquee);
invalidate();
}
/**
* Determines what happens when editing is interrupted by selecting
* another cell in the graph, a change in the graph's data, or by some
* other means. Setting this property to true
causes the
* changes to be automatically saved when editing is interrupted.
*
* Fires a property change for the INVOKES_STOP_CELL_EDITING_PROPERTY.
* @param newValue true means that stopCellEditing
is invoked
* when editing is interruped, and data is saved; false means that
* cancelCellEditing
is invoked, and changes are lost
*/
public void setInvokesStopCellEditing(boolean newValue) {
boolean oldValue = invokesStopCellEditing;
invokesStopCellEditing = newValue;
firePropertyChange(
INVOKES_STOP_CELL_EDITING_PROPERTY,
oldValue,
newValue);
}
/**
* Returns the indicator that tells what happens when editing is
* interrupted.
* @return the indicator that tells what happens when editing is
* interrupted
* @see #setInvokesStopCellEditing
*
*/
public boolean getInvokesStopCellEditing() {
return invokesStopCellEditing;
}
/**
* Returns isEditable
. This is invoked from the UI before
* editing begins to ensure that the given cell can be edited. This
* is provided as an entry point for subclassers to add filtered
* editing without having to resort to creating a new editor.
* @return true if the specified cell is editable
* @see #isEditable
*
*/
public boolean isCellEditable(Object cell) {
if (cell != null) {
CellView view = graphLayoutCache.getMapping(cell, false);
if (view != null) {
return isEditable()
&& GraphConstants.isEditable(view.getAllAttributes());
}
}
return false;
}
/**
* Overrides JComponent
's getToolTipText
* method in order to allow the graph to create a tooltip
* for the topmost cell under the mousepointer. This differs from JTree
* where the renderers tooltip is used.
*
* NOTE: For JGraph
to properly display tooltips of its
* renderers, JGraph
must be a registered component with the
* ToolTipManager
. This can be done by invoking
* ToolTipManager.sharedInstance().registerComponent(graph)
.
* This is not done automatically!
* @param event the MouseEvent
that initiated the
* ToolTip
display
* @return a string containing the tooltip or null
* if event
is null
*/
public String getToolTipText(MouseEvent event) {
if (event != null) {
Object cell = getFirstCellForLocation(event.getX(), event.getY());
String s = convertValueToString(cell);
return (s != null && s.length() > 0) ? s : null;
}
return null;
}
//
// The following are convenience methods that get forwarded to the
// current GraphSelectionModel.
//
/**
* Sets the graph's selection model. When a null
value is
* specified an emtpy
* selectionModel
is used, which does not allow selections.
* @param selectionModel the GraphSelectionModel
to use,
* or null
to disable selections
* @see GraphSelectionModel
*
*/
public void setSelectionModel(GraphSelectionModel selectionModel) {
if (selectionModel == null)
selectionModel = EmptySelectionModel.sharedInstance();
GraphSelectionModel oldValue = this.selectionModel;
// Remove Redirector From Old Selection Model
if (this.selectionModel != null && selectionRedirector != null)
this.selectionModel.removeGraphSelectionListener(
selectionRedirector);
this.selectionModel = selectionModel;
// Add Redirector To New Selection Model
if (selectionRedirector != null)
this.selectionModel.addGraphSelectionListener(selectionRedirector);
firePropertyChange(
SELECTION_MODEL_PROPERTY,
oldValue,
this.selectionModel);
}
/**
* Returns the model for selections. This should always return a
* non-null
value. If you don't want to allow anything
* to be selected
* set the selection model to null
, which forces an empty
* selection model to be used.
* @return the current selection model
* @see #setSelectionModel
*
*/
public GraphSelectionModel getSelectionModel() {
return selectionModel;
}
/**
* Clears the selection.
*/
public void clearSelection() {
getSelectionModel().clearSelection();
}
/**
* Returns true if the selection is currently empty.
* @return true if the selection is currently empty
*/
public boolean isSelectionEmpty() {
return getSelectionModel().isSelectionEmpty();
}
/**
* Adds a listener for GraphSelection
events.
* @param tsl the GraphSelectionListener
that will be notified
* when a cell is selected or deselected (a "negative
* selection")
*/
public void addGraphSelectionListener(GraphSelectionListener tsl) {
listenerList.add(GraphSelectionListener.class, tsl);
if (listenerList.getListenerCount(GraphSelectionListener.class) != 0
&& selectionRedirector == null) {
selectionRedirector = new GraphSelectionRedirector();
selectionModel.addGraphSelectionListener(selectionRedirector);
}
}
/**
* Removes a GraphSelection
listener.
* @param tsl the GraphSelectionListener
to remove
*/
public void removeGraphSelectionListener(GraphSelectionListener tsl) {
listenerList.remove(GraphSelectionListener.class, tsl);
if (listenerList.getListenerCount(GraphSelectionListener.class) == 0
&& selectionRedirector != null) {
selectionModel.removeGraphSelectionListener(selectionRedirector);
selectionRedirector = null;
}
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type. The event instance
* is lazily created using the parameters passed into
* the fire method.
* @param e the GraphSelectionEvent
generated by the
* GraphSelectionModel
* when a cell is selected or deselected
* @see javax.swing.event.EventListenerList
*
*/
protected void fireValueChanged(GraphSelectionEvent e) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == GraphSelectionListener.class) {
((GraphSelectionListener) listeners[i + 1]).valueChanged(e);
}
}
}
/**
* Selects the specified cell.
* @param cell the Object
specifying the cell to select
*/
public void setSelectionCell(Object cell) {
getSelectionModel().setSelectionCell(cell);
}
/**
* Selects the specified cells.
* @param cells an array of objects that specifies
* the cells to select
*/
public void setSelectionCells(Object[] cells) {
getSelectionModel().setSelectionCells(cells);
}
/**
* Adds the cell identified by the specified Object
* to the current selection.
* @param cell the cell to be added to the selection
*/
public void addSelectionCell(Object cell) {
getSelectionModel().addSelectionCell(cell);
}
/**
* Adds each cell in the array of cells to the current selection.
* @param cells an array of objects that specifies the cells to add
*/
public void addSelectionCells(Object[] cells) {
getSelectionModel().addSelectionCells(cells);
}
/**
* Removes the cell identified by the specified Object from the current
* selection.
* @param cell the cell to be removed from the selection
*/
public void removeSelectionCell(Object cell) {
getSelectionModel().removeSelectionCell(cell);
}
/**
* Returns the first selected cell.
* @return the Object
for the first selected cell,
* or null
if nothing is currently selected
*/
public Object getSelectionCell() {
return getSelectionModel().getSelectionCell();
}
/**
* Returns all selected cells.
* @return an array of objects representing the selected cells,
* or null
if nothing is currently selected
*/
public Object[] getSelectionCells() {
return getSelectionModel().getSelectionCells();
}
/**
* Returns the number of cells selected.
* @return the number of cells selected
*/
public int getSelectionCount() {
return getSelectionModel().getSelectionCount();
}
/**
* Returns true if the cell is currently selected.
* @param cell an object identifying a cell
* @return true if the cell is selected
*/
public boolean isCellSelected(Object cell) {
return getSelectionModel().isCellSelected(cell);
}
/**
* Scrolls to the specified cell. Only works when this
* JGraph
is contained in a JScrollPane
.
* @param cell the object identifying the cell to bring into view
*/
public void scrollCellToVisible(Object cell) {
Rectangle bounds = getCellBounds(cell);
if (bounds != null) {
bounds = new Rectangle(bounds);
scrollRectToVisible(toScreen(bounds));
}
}
/**
* Makes sure the specified point is visible.
* @param p the point that should be visible
*/
public void scrollPointToVisible(Point p) {
if (p != null) {
Rectangle bounds = new Rectangle(p);
if (bounds != null)
scrollRectToVisible(bounds);
}
}
/**
* Returns true if the graph is being edited. The item that is being
* edited can be obtained using getEditingCell
.
* @return true if the user is currently editing a cell
* @see #getSelectionCell
*
*/
public boolean isEditing() {
GraphUI graph = getUI();
if (graph != null)
return graph.isEditing(this);
return false;
}
/**
* Ends the current editing session.
* (The DefaultGraphCellEditor
* object saves any edits that are currently in progress on a cell.
* Other implementations may operate differently.)
* Has no effect if the tree isn't being edited.
*
* Note:
* To make edit-saves automatic whenever the user changes
* their position in the graph, use {@link #setInvokesStopCellEditing}.
*
* @return true if editing was in progress and is now stopped,
* false if editing was not in progress
*/
public boolean stopEditing() {
GraphUI graph = getUI();
if (graph != null)
return graph.stopEditing(this);
return false;
}
/**
* Cancels the current editing session. Has no effect if the
* graph isn't being edited.
*/
public void cancelEditing() {
GraphUI graph = getUI();
if (graph != null)
graph.cancelEditing(this);
}
/**
* Selects the specified cell and initiates editing.
* The edit-attempt fails if the CellEditor
* does not allow
* editing for the specified item.
*/
public void startEditingAtCell(Object cell) {
GraphUI graph = getUI();
if (graph != null)
graph.startEditingAtCell(this, cell);
}
/**
* Returns the cell that is currently being edited.
* @return the cell being edited
*/
public Object getEditingCell() {
GraphUI graph = getUI();
if (graph != null)
return graph.getEditingCell(this);
return null;
}
/**
* Messaged when the graph has changed enough that we need to resize
* the bounds, but not enough that we need to remove the cells
* (e.g cells were inserted into the graph). You should never have to
* invoke this, the UI will invoke this as it needs to. (Note: This
* is invoked by GraphUI, eg. after moving.)
*/
public void graphDidChange() {
revalidate();
repaint();
}
/**
* Serialization support.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
Vector values = new Vector();
s.defaultWriteObject();
// Save the cellEditor, if its Serializable.
if (graphModel instanceof Serializable) {
values.addElement("graphModel");
values.addElement(graphModel);
}
// Save the graphModel, if its Serializable.
if (graphLayoutCache instanceof Serializable) {
values.addElement("graphLayoutCache");
values.addElement(graphLayoutCache);
}
// Save the selectionModel, if its Serializable.
if (selectionModel instanceof Serializable) {
values.addElement("selectionModel");
values.addElement(selectionModel);
}
s.writeObject(values);
if (getUIClassID().equals(uiClassID)) {
/*byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);*/
if (/*count == 0 && */
ui != null) {
ui.installUI(this);
}
}
}
/**
* Serialization support.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
Vector values = (Vector) s.readObject();
int indexCounter = 0;
int maxCounter = values.size();
if (indexCounter < maxCounter
&& values.elementAt(indexCounter).equals("graphModel")) {
graphModel = (GraphModel) values.elementAt(++indexCounter);
indexCounter++;
}
if (indexCounter < maxCounter
&& values.elementAt(indexCounter).equals("graphLayoutCache")) {
graphLayoutCache =
(GraphLayoutCache) values.elementAt(++indexCounter);
indexCounter++;
}
if (indexCounter < maxCounter
&& values.elementAt(indexCounter).equals("selectionModel")) {
selectionModel =
(GraphSelectionModel) values.elementAt(++indexCounter);
indexCounter++;
}
// Reinstall the redirector.
if (listenerList.getListenerCount(GraphSelectionListener.class) != 0) {
selectionRedirector = new GraphSelectionRedirector();
selectionModel.addGraphSelectionListener(selectionRedirector);
}
}
/**
* EmptySelectionModel
is a GraphSelectionModel
* that does not allow anything to be selected.
*
* Warning:
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is appropriate
* for short term storage or RMI between applications running the same
* version of Swing. A future release of Swing will provide support for
* long term persistence.
*/
public static class EmptySelectionModel
extends DefaultGraphSelectionModel {
/** Unique shared instance. */
protected static final EmptySelectionModel sharedInstance =
new EmptySelectionModel();
/** A null
implementation that constructs an
* EmptySelectionModel. */
public EmptySelectionModel() {
super(null);
}
/** Returns a shared instance of an empty selection model. */
static public EmptySelectionModel sharedInstance() {
return sharedInstance;
}
/** A null
implementation that selects nothing. */
public void setSelectionCells(Object[] cells) {
}
/** A null
implementation that adds nothing. */
public void addSelectionCells(Object[] cells) {
}
/** A null
implementation that removes nothing. */
public void removeSelectionCells(Object[] cells) {
}
}
/**
* Handles creating a new GraphSelectionEvent
with the
* JGraph
as the
* source and passing it off to all the listeners.
*
* Warning:
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is appropriate
* for short term storage or RMI between applications running the same
* version of Swing. A future release of Swing will provide support for
* long term persistence.
*/
protected class GraphSelectionRedirector
implements Serializable, GraphSelectionListener {
/**
* Invoked by the GraphSelectionModel
when the
* selection changes.
*
* @param e the GraphSelectionEvent
generated by the
* GraphSelectionModel
*/
public void valueChanged(GraphSelectionEvent e) {
GraphSelectionEvent newE;
newE = (GraphSelectionEvent) e.cloneWithSource(JGraph.this);
fireValueChanged(newE);
}
} // End of class JGraph.GraphSelectionRedirector
//
// Scrollable interface
//
/**
* Returns the preferred display size of a JGraph
. The height is
* determined from getPreferredWidth
.
* @return the graph's preferred size
*/
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}
/**
* Returns the amount to increment when scrolling. The amount is 4.
* @param visibleRect the view area visible within the viewport
* @param orientation either SwingConstants.VERTICAL
* or SwingConstants.HORIZONTAL
* @param direction less than zero to scroll up/left,
* greater than zero for down/right
* @return the "unit" increment for scrolling in the specified direction
* @see JScrollBar#setUnitIncrement(int)
*
*/
public int getScrollableUnitIncrement(
Rectangle visibleRect,
int orientation,
int direction) {
if (orientation == SwingConstants.VERTICAL) {
return 2;
}
return 4;
}
/**
* Returns the amount for a block increment, which is the height or
* width of visibleRect
, based on orientation
.
* @param visibleRect the view area visible within the viewport
* @param orientation either SwingConstants.VERTICAL
* or SwingConstants.HORIZONTAL
* @param direction less than zero to scroll up/left,
* greater than zero for down/right.
* @return the "block" increment for scrolling in the specified direction
* @see JScrollBar#setBlockIncrement(int)
*
*/
public int getScrollableBlockIncrement(
Rectangle visibleRect,
int orientation,
int direction) {
return (orientation == SwingConstants.VERTICAL)
? visibleRect.height
: visibleRect.width;
}
/**
* Returns false to indicate that the width of the viewport does not
* determine the width of the graph, unless the preferred width of
* the graph is smaller than the viewports width. In other words:
* ensure that the graph is never smaller than its viewport.
* @return false
* @see Scrollable#getScrollableTracksViewportWidth
*
*/
public boolean getScrollableTracksViewportWidth() {
if (getParent() instanceof JViewport) {
return (
((JViewport) getParent()).getWidth()
> getPreferredSize().width);
}
return false;
}
/**
* Returns false to indicate that the height of the viewport does not
* determine the height of the graph, unless the preferred height
* of the graph is smaller than the viewports height. In other words:
* ensure that the graph is never smaller than its viewport.
* @return false
* @see Scrollable#getScrollableTracksViewportHeight
*
*/
public boolean getScrollableTracksViewportHeight() {
if (getParent() instanceof JViewport) {
return (
((JViewport) getParent()).getHeight()
> getPreferredSize().height);
}
return false;
}
/**
* Returns a string representation of this JGraph
.
* This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be null
.
* @return a string representation of this JGraph
.
*/
protected String paramString() {
String editableString = (editable ? "true" : "false");
String invokesStopCellEditingString =
(invokesStopCellEditing ? "true" : "false");
return super.paramString()
+ ",editable="
+ editableString
+ ",invokesStopCellEditing="
+ invokesStopCellEditingString;
}
public static void main(String[] args) {
System.out.println(VERSION);
}
}