Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 312886

Summary: New ClippingStrategy causes Exception if connection remains after deleting Figure
Product: [Tools] GEF Reporter: <h1055071>
Component: GEF-Legacy GEF (MVC)Assignee: Alexander Nyßen <nyssen>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: nyssen, yann.tanguy
Version: unspecified   
Target Milestone: 3.6.2 (Helios SR2)   
Hardware: PC   
OS: Windows 7   
Whiteboard:

Description CLA 2010-05-14 06:59:35 EDT
Build Identifier: Eclipse 3.5.2, M20100211-1343 GEF 3.6 build I201004252051

(Originally posted in Bug #195527)

I'm getting an error exception with this new strategy. I have three figures -
one on it's own, and one inside another (parent) figure. The child figure
inside the parent has a connection to the one on it's own. When I delete the
parent figure (but not the connection) I get this:

!ENTRY org.eclipse.ui 4 0 2010-05-12 15:30:26.059
!MESSAGE Unhandled event loop exception
!STACK 0
org.eclipse.swt.SWTException: Failed to execute runnable
(java.lang.IndexOutOfBoundsException: Index: 3, Size: 3)
    at org.eclipse.swt.SWT.error(SWT.java:3884)
    at org.eclipse.swt.SWT.error(SWT.java:3799)
    at
org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:137)
    at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3885)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3506)
    at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2405)
    at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2369)
    at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
    at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
    at
org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
    at
org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
    at uk.ac.bolton.archimate.editor.Application.start(Application.java:62)
    at
org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
    at
org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at
org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at
org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
    at
org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
Caused by: java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
    at java.util.ArrayList.RangeCheck(ArrayList.java:547)
    at java.util.ArrayList.get(ArrayList.java:322)
    at
org.eclipse.draw2d.FigureUtilities.findCommonAncestor(FigureUtilities.java:369)
    at
org.eclipse.draw2d.ViewportUtilities.getNearestCommonViewport(ViewportUtilities.java:137)
    at
org.eclipse.draw2d.ConnectionLayer$ConnectionLayerClippingStrategy.getEdgeClippingRectangle(ConnectionLayer.java:91)
    at
org.eclipse.draw2d.ConnectionLayer$ConnectionLayerClippingStrategy.getClip(ConnectionLayer.java:55)
    at org.eclipse.draw2d.Figure.paintChildren(Figure.java:1099)
    at org.eclipse.draw2d.Figure.paintClientArea(Figure.java:1136)
    at org.eclipse.draw2d.Figure.paint(Figure.java:1065)
    at org.eclipse.draw2d.ConnectionLayer.paint(ConnectionLayer.java:277)
    at org.eclipse.draw2d.Figure.paintChildren(Figure.java:1103)
    at org.eclipse.draw2d.Figure.paintClientArea(Figure.java:1136)
    at org.eclipse.draw2d.Figure.paint(Figure.java:1065)
    at org.eclipse.draw2d.Figure.paintChildren(Figure.java:1103)
    at org.eclipse.draw2d.Figure.paintClientArea(Figure.java:1136)
    at
org.eclipse.draw2d.ScalableFreeformLayeredPane.paintClientArea(ScalableFreeformLayeredPane.java:61)
    at org.eclipse.draw2d.Figure.paint(Figure.java:1065)
    at org.eclipse.draw2d.Figure.paintChildren(Figure.java:1103)
    at org.eclipse.draw2d.Figure.paintClientArea(Figure.java:1136)
    at org.eclipse.draw2d.Figure.paint(Figure.java:1065)
    at org.eclipse.draw2d.Figure.paintChildren(Figure.java:1103)
    at org.eclipse.draw2d.Figure.paintClientArea(Figure.java:1131)
    at org.eclipse.draw2d.Viewport.paintClientArea(Viewport.java:156)
    at org.eclipse.draw2d.Figure.paint(Figure.java:1065)
    at org.eclipse.draw2d.Figure.paintChildren(Figure.java:1103)
    at org.eclipse.draw2d.Figure.paintClientArea(Figure.java:1136)
    at org.eclipse.draw2d.Figure.paint(Figure.java:1065)
    at
org.eclipse.draw2d.DeferredUpdateManager.paint(DeferredUpdateManager.java:155)
    at org.eclipse.draw2d.LightweightSystem.paint(LightweightSystem.java:199)
    at
org.eclipse.draw2d.LightweightSystem$2.handleEvent(LightweightSystem.java:107)
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1003)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1027)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1012)
    at org.eclipse.swt.widgets.Composite.WM_PAINT(Composite.java:1324)
    at org.eclipse.swt.widgets.Control.windowProc(Control.java:4001)
    at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:342)
    at org.eclipse.swt.widgets.Display.windowProc(Display.java:4632)
    at org.eclipse.swt.internal.win32.OS.RedrawWindow(Native Method)
    at org.eclipse.swt.widgets.Control.update(Control.java:3810)
    at org.eclipse.swt.widgets.Control.update(Control.java:3800)
    at
org.eclipse.draw2d.NativeGraphicsSource.getGraphics(NativeGraphicsSource.java:43)
    at
org.eclipse.draw2d.DeferredUpdateManager.getGraphics(DeferredUpdateManager.java:138)
    at
org.eclipse.draw2d.DeferredUpdateManager.repairDamage(DeferredUpdateManager.java:292)
    at
org.eclipse.draw2d.DeferredUpdateManager.performUpdate(DeferredUpdateManager.java:181)
    at
org.eclipse.draw2d.DeferredUpdateManager$UpdateRequest.run(DeferredUpdateManager.java:48)
    at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
    at
org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)


This does not happen in GEF 3.5.2.


Reproducible: Always
Comment 1 CLA 2010-05-14 07:00:31 EDT
It happens as a side-effect of not removing the connections from the deleted
object. In 3.5.2 the orphaned connection(s) would remain on the diagram, but in
3.6 there is this exception.

You could argue that you when you run a Delete command you should also remove
any connections from the model. This is true, but at least in 3.5.2 it acted
gracefully.

To reproduce in Logic example:

1. In DeleteCommand.java comment out the code in methods
deleteConnections(LogicSubpart part).
2. Create a new Logic diagram and add a FullAdder and a Circuit.
3. Make a connection from an inner figure in the FullAdder to a point on the
Circuit.
4. Delete the inner figure's parent.
Comment 2 Alexander Nyßen CLA 2011-01-03 12:31:15 EST
The cause for this actually is that FigureUtilities#findCommonAncestor is not robust against calls with an orphaned figure. The following test case may be used to reproduce the issue:

public void test_findCommonAncestor_bugzilla312886() {
		IFigure orphanFigure = new Figure();
		IFigure figureParent = new Figure();
		IFigure figureChild = new Figure();
		figureParent.add(figureChild);

		assertNull(FigureUtilities
				.findCommonAncestor(figureChild, orphanFigure));
} 

It will deliver the following result: IndexOutOfBoundsException: Index : 2, Size:2
Comment 3 Alexander Nyßen CLA 2011-01-03 13:21:47 EST
- Fixed javadoc of FigureUtilities#findCommonAncestor() stated that the method would return null in case one figure is the ancestor of the other (the changes made as part of bug#130042 and the test case belonging to this demonstrated that other behavior was expected).
- Reimplemented FigureUtilities#findCommonAncestor() to correctly handle orphaned children, which was broken.
- Made ViewportUtilities#findNearestViewport() and ViewportUtilities#findNearestEnclosingViewport() robust against null arguments.
- Added additional test cases to FigureUtilitiesTest.

Committed changes to 3.6 maintenance branch and cvs HEAD (3.7). Marking as resolved in 3.6.2.