41
41
import javax.swing.Scrollable;
42
42
import javax.swing.SwingConstants;
44
import org.jgraph.event.GraphModelEvent;
44
45
import org.jgraph.event.GraphSelectionEvent;
45
46
import org.jgraph.event.GraphSelectionListener;
47
import org.jgraph.event.GraphLayoutCacheEvent.GraphLayoutCacheChange;
48
import org.jgraph.event.GraphModelEvent.GraphModelChange;
46
49
import org.jgraph.graph.AbstractCellView;
47
50
import org.jgraph.graph.AttributeMap;
48
51
import org.jgraph.graph.BasicMarqueeHandler;
183
186
// org.jgraph.plaf.basic.TransferHandler.JAdapterComponent
184
187
implements Scrollable, Accessible, Serializable {
186
public static final String VERSION = "JGraph (v5.10.1.5)";
189
public static final String VERSION = "JGraph (v5.12.0.4)";
188
191
public static final int DOT_GRID_MODE = 0;
242
245
/** Off screen image for double buffering */
243
246
protected transient Image offscreen;
245
/** Whether or not the current background image is correct */
246
protected transient boolean offscreenValid = false;
248
248
/** The bounds of the offscreen buffer */
249
249
protected transient Rectangle2D offscreenBounds;
254
254
/** Graphics object of off screen image */
255
255
protected transient Graphics offgraphics;
257
/** Whether or not the current background image is correct */
258
protected transient Rectangle2D offscreenDirty = null;
258
261
* The buffer around the offscreen graphics object that provides the
266
269
* buffering. Volatile
268
271
protected boolean volatileOffscreen = false;
273
/** Stores whether the last double buffer allocation worked or not */
274
protected boolean lastBufferAllocated = true;
270
276
/** Holds the background image. */
271
277
protected ImageIcon backgroundImage;
315
321
/** True if the ports are scaled. Bound property. */
316
322
protected boolean portsScaled = true;
324
/** True if port are painted above all other cells. */
325
protected boolean portsOnTop = true;
318
327
/** True if the graph allows to move cells below zero. */
319
328
protected boolean moveBelowZero = false;
1757
1767
zoomIn = false;
1760
offscreenValid = false;
1761
1770
firePropertyChange(SCALE_PROPERTY, oldValue, newValue);
1762
1771
// When zooming in, do it after the revalidation otherwise
1763
1772
// it intermittently moves to the old co-ordinate system
1780
* Invalidate the offscreen region, do not just delete it, since if the new
1781
* region is smaller than the old you may not wish to re-create the buffer
1783
public void clearOffscreen() {
1785
if (offscreen != null) {
1786
int h = offscreen.getHeight(this);
1787
int w = offscreen.getWidth(this);
1788
Rectangle2D dirtyRegion = new Rectangle2D.Double(0, 0, w, h);
1789
fromScreen(dirtyRegion);
1790
addOffscreenDirty(dirtyRegion);
1771
1795
* Returns the center of the component relative to the parent viewport's
1901
1925
firePropertyChange(PORTS_SCALED_PROPERTY, oldValue, flag);
1928
public boolean isPortsOnTop() {
1932
public void setPortsOnTop(boolean portsOnTop) {
1933
this.portsOnTop = portsOnTop;
1905
1937
* Returns true if the graph will be anti aliased.
2076
2108
offscreen = null;
2077
2109
offgraphics = null;
2110
Runtime runtime = Runtime.getRuntime();
2111
long maxMemory = runtime.maxMemory();
2112
long allocatedMemory = runtime.totalMemory();
2113
long freeMemory = runtime.freeMemory();
2114
long totalFreeMemory = (freeMemory + (maxMemory - allocatedMemory)) / 1024;
2115
// Calculate size of buffer required (assuming TYPE_INT_RGB which
2116
// stores each pixel in a 32-bit int )
2117
long memoryRequired = width*height*4/1024;
2118
if (memoryRequired > totalFreeMemory) {
2119
if (lastBufferAllocated) {
2120
// If the last attempt to allocate a buffer worked it might
2121
// be we need to reclaim the memory before the next one
2125
lastBufferAllocated = false;
2078
2128
if (offscreen == null && volatileOffscreen) {
2080
2130
offscreen = createVolatileImage(width, height);
2093
2143
// of it, might also be faster to calculate in
2094
2144
// advance whether they is enough memory to create image
2095
2145
// rather than let it try and throw error.
2146
lastBufferAllocated = false;
2149
lastBufferAllocated = true;
2098
2150
setupOffScreen(x, y, width, height, newOffscreenBuffer);
2099
2151
} else if (offscreen instanceof VolatileImage) {
2100
2152
int valCode = ((VolatileImage) offscreen)
2119
2171
setupOffScreen(x, y, width, height, newOffscreenBuffer);
2120
2172
} else if (valCode == VolatileImage.IMAGE_RESTORED) {
2121
setOffscreenValid(false);
2173
addOffscreenDirty((Rectangle2D)getBounds().clone());
2124
if (!isOffscreenValid()) {
2176
Rectangle2D offscreenDirty = getOffscreenDirty();
2177
if (offscreenDirty != null) {
2125
2178
offgraphics.setColor(getBackground());
2126
2179
offgraphics.setPaintMode();
2127
offgraphics.fillRect(0, 0, (int) graphBounds.getWidth(), (int) graphBounds
2129
((BasicGraphUI)getUI()).drawGraph(offgraphics, null);
2130
offscreenValid = true;
2180
toScreen(offscreenDirty);
2181
offscreenDirty.setRect(offscreenDirty.getX()
2182
- (getHandleSize() + 1), offscreenDirty.getY()
2183
- (getHandleSize() + 1), offscreenDirty.getWidth()
2184
+ (getHandleSize() + 1) * 2, offscreenDirty.getHeight()
2185
+ (getHandleSize() + 1) * 2);
2186
offgraphics.fillRect((int) offscreenDirty.getX(),
2187
(int) offscreenDirty.getY(), (int) offscreenDirty
2188
.getWidth(), (int) offscreenDirty.getHeight());
2189
((BasicGraphUI) getUI()).drawGraph(offgraphics, offscreenDirty);
2190
clearOffscreenDirty();
2132
2192
return offgraphics;
2169
2229
protected void setupOffScreen(int x, int y, int width, int height, Rectangle2D newOffscreenBuffer) {
2170
2230
offgraphics = offscreen.getGraphics();
2171
setOffscreenValid(false);
2172
2231
offgraphics.setColor(getBackground());
2173
2232
offgraphics.setPaintMode();
2174
2233
offgraphics.fillRect(0, 0, width, height);
2234
((BasicGraphUI)getUI()).drawGraph(offgraphics, null);
2175
2235
offscreenBounds = newOffscreenBuffer;
2176
2236
offscreenOffset = new Point2D.Double(x, y);
2237
// Clear the offscreen, we've just drawn the whole thing
2238
clearOffscreenDirty();
2183
2245
return offscreen;
2248
public Rectangle2D getOffscreenDirty() {
2249
return offscreenDirty;
2252
public void addOffscreenDirty(Rectangle2D offscreenDirty) {
2253
if (this.offscreenDirty == null && offscreenDirty != null){
2254
this.offscreenDirty = (Rectangle2D)offscreenDirty.clone();
2255
} else if (offscreenDirty != null){
2256
this.offscreenDirty.add(offscreenDirty);
2261
public void clearOffscreenDirty() {
2262
offscreenDirty = null;
2187
2266
* Utility method to draw the off screen buffer
2226
2305
return getGraphics().drawImage(offscreen, rect.x, rect.y,
2227
2306
rect.x + rect.width, rect.y + rect.height, rect.x, rect.y,
2228
2307
rect.x + rect.width, rect.y + rect.height, this);
2247
2327
public void setBackgroundImage(ImageIcon backgroundImage) {
2248
2328
ImageIcon oldValue = this.backgroundImage;
2249
2329
this.backgroundImage = backgroundImage;
2250
2331
firePropertyChange(PROPERTY_BACKGROUNDIMAGE, oldValue, backgroundImage);
2335
* Override parent to clear offscreen double buffer
2337
public void setBackground(Color bg) {
2339
super.setBackground(bg);
2254
2343
* @return the backgroundScaled
2256
2345
public boolean isBackgroundScaled() {
2261
* @return the offscreenValid
2263
public boolean isOffscreenValid() {
2264
return offscreenValid;
2268
* @param offscreenValid
2269
* the offscreenValid to set
2271
public void setOffscreenValid(boolean offscreenValid) {
2272
this.offscreenValid = offscreenValid;
2276
2350
* @return the offscreenOffset
2278
2352
public Point2D getOffscreenOffset() {
2320
2394
* the backgroundComponent to set
2322
2396
public void setBackgroundComponent(Component backgroundComponent) {
2323
2398
this.backgroundComponent = backgroundComponent;
2402
* Overriden to change painting style for opaque components
2403
* @see javax.swing.JComponent#setOpaque(boolean)
2405
public void setOpaque(boolean opaque) {
2406
super.setOpaque(opaque);
2327
2410
* Returns the <code>GraphModel</code> that is providing the data.
2345
2428
public void setModel(GraphModel newModel) {
2346
2429
GraphModel oldModel = graphModel;
2347
2430
graphModel = newModel;
2348
2432
firePropertyChange(GRAPH_MODEL_PROPERTY, oldModel, graphModel);
2349
2433
// FIX: Use Listener
2350
2434
if (graphLayoutCache != null
2379
2463
public void setGraphLayoutCache(GraphLayoutCache newLayoutCache) {
2380
2464
GraphLayoutCache oldLayoutCache = graphLayoutCache;
2381
2465
graphLayoutCache = newLayoutCache;
2382
2467
firePropertyChange(GRAPH_LAYOUT_CACHE_PROPERTY, oldLayoutCache,
2383
2468
graphLayoutCache);
2384
2469
if (graphLayoutCache != null
2856
* You should not call this method directly on a JGraph if you are using
2859
* @see javax.swing.JComponent#repaint(long, int, int, int, int)
2861
public void repaint(long tm, int x, int y, int width, int height) {
2862
super.repaint(tm, x, y, width, height);
2868
* @see javax.swing.JComponent#repaint(java.awt.Rectangle)
2870
public void repaint(Rectangle r) {
2871
offscreenValid = false;
2878
* @see java.awt.Component#repaint()
2880
public void repaint() {
2881
offscreenValid = false;
2888
* @see java.awt.Component#repaint(int, int, int, int)
2890
public void repaint(int x, int y, int width, int height) {
2891
offscreenValid = false;
2892
super.repaint(x, y, width, height);
2898
* @see java.awt.Component#repaint(long)
2900
public void repaint(long tm) {
2901
offscreenValid = false;
2905
2940
// /* (non-Javadoc)
2906
2941
// * @see javax.swing.JComponent#isOptimizedDrawingEnabled()
2999
* Calculates the clip
3001
* @return the total region dirty as a result of this change
3003
public Rectangle2D getClipRectangle(GraphLayoutCacheChange change) {
3004
List removed = DefaultGraphModel.getDescendants(getModel(), change.getRemoved());
3005
Rectangle2D removedBounds = (removed != null && !removed.isEmpty()) ? getCellBounds(removed.toArray()) : null;
3006
List inserted = DefaultGraphModel.getDescendants(getModel(), change.getInserted());
3007
Rectangle2D insertedBounds = (inserted != null && !inserted.isEmpty()) ? getCellBounds(inserted.toArray()) : null;
3008
List changed = DefaultGraphModel.getDescendants(getModel(), change.getChanged());
3009
Rectangle2D changedBounds = (changed != null && !changed.isEmpty()) ? getCellBounds(changed.toArray()) : null;
3010
List context = DefaultGraphModel.getDescendants(getModel(), change.getContext());
3011
Rectangle2D contextBounds = (context != null && !context.isEmpty()) ? getCellBounds(context.toArray()) : null;
3013
Rectangle2D clip = removedBounds;
3016
clip = insertedBounds;
3017
} else if (insertedBounds != null) {
3018
clip.add(insertedBounds);
3022
clip = changedBounds;
3023
} else if (changedBounds != null) {
3024
clip.add(changedBounds);
3028
clip = contextBounds;
3029
} else if (contextBounds != null) {
3030
clip.add(contextBounds);
2964
3037
* Serialization support.
2966
3039
private void writeObject(ObjectOutputStream s) throws IOException {