Bug 68003 - NPE due to DragEditPartsTracker
Summary: NPE due to DragEditPartsTracker
Status: RESOLVED FIXED
Alias: None
Product: GEF
Classification: Tools
Component: GEF-Legacy GEF (MVC) (show other bugs)
Version: 3.0   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.1.0 M3   Edit
Assignee: Randy Hudson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 70607 (view as bug list)
Depends on:
Blocks:
 
Reported: 2004-06-21 10:45 EDT by Adam Wilson CLA
Modified: 2004-10-29 15:15 EDT (History)
2 users (show)

See Also:


Attachments
Test case (8.92 KB, application/x-zip-compressed)
2004-06-21 11:14 EDT, Adam Wilson CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Adam Wilson CLA 2004-06-21 10:45:23 EDT
getSelectionWithoutDependants() throws a NPE because the viewer parameter is 
null.  The underlying problem is as follows:

1. In AbstractTool.mouseDown(), the current viewer is set in a field.
2. From mouseDown(), handleButtonDown() is called.  The implementation is in 
SelectEditPartTracker, a subclass of AbstractTool.
3. handleButtonDown() calls select() on the viewer, which triggers workbench 
selection change notifications.
4. In the particular case that I encounter, we have a view listening for 
workbench selection change notifications that must invoke a 
IRunnableWithProgress in the context of a workbench window.  This removes the 
focus from the edit part and then restores it.  However, this leaves the 
SelectEditPartTracker with no viewer set.

Here is the stack trace:

java.lang.NullPointerException
	at java.lang.Throwable.<init>(Throwable.java)
	at java.lang.Throwable.<init>(Throwable.java)
	at java.lang.NullPointerException.<init>(NullPointerException.java:60)
	at org.eclipse.gef.tools.ToolUtilities.getSelectionWithoutDependants
(ToolUtilities.java:29)
	at org.eclipse.gef.tools.DragEditPartsTracker.createOperationSet
(DragEditPartsTracker.java:150)
	at org.eclipse.gef.tools.AbstractTool.getOperationSet
(AbstractTool.java:575)
	at org.eclipse.gef.tools.DragEditPartsTracker.captureSourceDimensions
(DragEditPartsTracker.java:108)
	at org.eclipse.gef.tools.DragEditPartsTracker.setState
(DragEditPartsTracker.java:516)
	at org.eclipse.gef.tools.AbstractTool.stateTransition
(AbstractTool.java:1260)
	at org.eclipse.gef.tools.SelectEditPartTracker.handleButtonDown
(SelectEditPartTracker.java:93)
	at org.eclipse.gef.tools.AbstractTool.mouseDown(AbstractTool.java:974)
	at org.eclipse.gef.tools.SelectionTool.mouseDown
(SelectionTool.java:481)
	at org.eclipse.gef.EditDomain.mouseDown(EditDomain.java:194)
	at org.eclipse.gef.ui.parts.DomainEventDispatcher.dispatchMousePressed
(DomainEventDispatcher.java:314)
	at org.eclipse.draw2d.LightweightSystem$EventHandler.mouseDown
(LightweightSystem.java:491)
	at org.eclipse.swt.widgets.TypedListener.handleEvent
(TypedListener.java:132)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:1353)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:1324)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench
(Workbench.java:243)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:141)
	at org.eclipse.ui.internal.ide.IDEApplication.run
(IDEApplication.java:90)
	at org.eclipse.core.internal.runtime.PlatformActivator$1.run
(PlatformActivator.java:298)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run
(EclipseStarter.java:249)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run
(EclipseStarter.java:126)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke
(NativeMethodAccessorImpl.java:84)
	at sun.reflect.NativeMethodAccessorImpl.invoke
(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke
(DelegatingMethodAccessorImpl.java:59)
	at java.lang.reflect.Method.invoke(Method.java:390)
	at org.eclipse.core.launcher.Main.basicRun(Main.java:269)
	at org.eclipse.core.launcher.Main.run(Main.java:722)
	at org.eclipse.core.launcher.Main.main(Main.java:706)
Comment 1 Adam Wilson CLA 2004-06-21 11:07:02 EDT
I tagged this bug with the wrong GEF version.  It should have been 3.0.  
Specifically, I tested it against the I20040619 GEF build on top of Eclipse 
3.0 RC3.
Comment 2 Adam Wilson CLA 2004-06-21 11:14:04 EDT
Created attachment 12571 [details]
Test case

I attach a simple test case that illustrates this problem.

It requires the GEF logic example (I used I20040619).  The testcase plugin
contributes a new view that registers a selection listener on the workbench
window's selection service.  Inside this listener, it invokes an
IRunnableWithProgress that does nothing.

STEPS TO REPRODUCE:
1. Create a new GEF logic 4 bit adder model example.
2. Open the testcase view (Window -> Show View -> Other... -> Sample Category
-> Sample View).
3. Click on an element in the logic diagram.
4. Look at the Eclipse log file for the NPE.
Comment 3 Randy Hudson CLA 2004-06-21 13:13:56 EDT
See bug 65985.
Comment 4 Randy Hudson CLA 2004-06-21 13:16:23 EDT
Please try to reproduce using the RC2 version of the Platform.
Comment 5 Adam Wilson CLA 2004-06-21 13:37:18 EDT
I reproduced the test case from comment #2 using Eclipse 3.0 RC2 and GEF 
I20040619.
Comment 6 Randy Hudson CLA 2004-06-21 14:55:30 EDT
Thanks, I will investigate with the testcase.
Comment 7 Randy Hudson CLA 2004-06-22 13:39:06 EDT
I don't see anything we can do here.  At first I was thinking that the tool 
should be in its TERMINAL state because it was deactivated when focus was 
lost.  But doing that won't help you because then you will never be able to 
drag anything with the mouse.

What is it you want to happen?  Do you want the hourglass cursor when you 
select something?  The selection tool unloads any drag tracker when focus lost 
occurs.  The canvas should not lose focus during a mouse drag, if it does, the 
drag is aborted.

So we could avoid the NPE, but then you could not drag.
Comment 8 Randy Hudson CLA 2004-06-22 13:46:35 EDT
Can you use fork==TRUE so that the UI is not temporarily disabled?  This will 
avoid the focusLost event.  I'm guessing that this is what the Problems/Tasks 
views do.
Comment 9 Adam Wilson CLA 2004-06-23 17:44:19 EDT
We can't call call run() with the fork==true because the call is made when 
creating a new editor in AbstractTextEditor.internalInit(), which we can't 
change or override.

Our current workaround is to check if the active tool has a drag tracker 
(using reflection to access the private getDragTracker() method) and if it 
does then we cache it.  Then, after the runnable has finished, we call 
setViewer() on the cached drag tracker tool to restore the correct viewer.

We will keep on using our workaround since a solution at the GEF level doesn't 
seem reasonable.

Thanks for your help in taking a look at this.
Comment 10 Randy Hudson CLA 2004-06-23 18:01:55 EDT
Why don't you build a delay into your selection listener similar to Windows 
Explorer. In other words, invoke a Display.timerExec(opensEditor, 500). If 
selection changes before then, cancel that runnable and start a new one.

There are lots of cases where you will receive several selection events in 
rapid succession and it makes sense to only react to the last one.
Comment 11 Randy Hudson CLA 2004-06-23 18:02:34 EDT
Actually, we will fix this but it isn't the desired fix you are after, and may 
even break your workaround.
Comment 12 Randy Hudson CLA 2004-08-18 15:26:43 EDT
On windows, a native Tree or Table shows selection on mousedown, but *fires* 
notification on mouse up. But if you drag the mouse the widgets fire selection 
sooner.  So if we emulate this behavior you would still have problems once the 
mouse starts dragging, and it may break clients.

Steve, is there some way we could identify and ignore the spurious focusLost 
event?  It seems that in this scenario focus is guaranteed to return to the 
control which had it (unless setFocus or dispose occurs?)
Comment 13 Steve Northover CLA 2004-09-07 18:36:49 EDT
Not really, if focus is actually lost, then we can't (shouldn't) try to fake 
that it didn't or other things might break.  Can you create a simple SWT only 
test case and log a problem report?  Thanks.
Comment 14 Randy Hudson CLA 2004-10-13 13:26:42 EDT
AT:
org.eclipse.gef.tools.SelectEditPartTracker.handleButtonDown
(SelectEditPartTracker.java:93)

The drag tracker has been deactivated at this point, but is still attempting to 
do more processing of the mouseDown because it is still in STATE_INITIAL.

The fix is to add setState(STATE_TERMINAL) to AbstractTool#deactivate().  This 
way, any tool which has been deactivated will not continue to do stuff if it 
correctly checks its current state.
Comment 15 Randy Hudson CLA 2004-10-29 10:39:07 EDT
*** Bug 70607 has been marked as a duplicate of this bug. ***