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

Bug 320877

Summary: [ColumnViewer] MouseListener calls ColumnViewerEditor.applyEditorValue() when it shouldn't
Product: [RT] RAP Reporter: Bogdan B. <bbarzu>
Component: JFaceAssignee: Project Inbox <rap-inbox>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: bbarzu, eclipse.bugzilla, ivan, swimmer_86
Version: unspecified   
Target Milestone: 1.4 M2   
Hardware: All   
OS: All   
Whiteboard:
Attachments:
Description Flags
Code snippet
none
ColumnViewerEditor patch none

Description Bogdan B. CLA 2010-07-26 05:46:43 EDT
Build Identifier: rap-runtime-1.3.0-R-20100615-1704.zip

Actually the problem is the fact that the old (1.3, not the new one referred by #309519) implementation of "Tree widget does not fire mouseDown events".
To fix this bug, you added (only in RAP, see the comments in source code) the .mouseUp() method to the MouseListener defined by ColumnViewer.hookEditingSupport(), which further calls ColumnViewerEditor.handleEditorActivationEvent(), which calls .applyEditorValue(). 

But there are cases where this call is wrong, here an use case:
- I have a Tree with 2 columns that have 2 different editors
- I click a cell in the first column - the editors activates
- I type a value which WON'T pass the validation
- I click in the same line in the second column (having the second editor)

Now comes the wicked part: if and only if I click really fast (time between mouseDown() and mouseUp() is very short), then the SWT.Deactivate (for the first column editor) event is fired only AFTER mouseUp(). Not giving me the chance to call CellEditor.fireCancelEditor() before mouseUp() runs. And so the .applyEditorValue() is automatically called for an invalid value, which will make my model throw a validation exception.
But if I take my finger from the mouse button with a delay (not too much), than SWT.Deactivate is fired before .mouseUp() and I have my chance to cancel the editing.

The big question is: have you fixed the new Tree to fire the events you need?
Because if yes, then the .mouseUp() from ColumnViewer.hookEditingSupport() is not needed anymore. Which would fix my problem.
 

Reproducible: Always
Comment 1 Ivan Furnadjiev CLA 2010-08-09 05:28:24 EDT
Yes, the new client side Tree implementation fires mouseDown event correctly.
Comment 2 Ivan Furnadjiev CLA 2010-08-09 05:35:31 EDT
Bogdan, can you provide a self-running snippet to reproduce it?
Comment 3 Bogdan B. CLA 2010-08-13 08:10:05 EDT
I just tested it with 1.4M1 - it gets even worse:
every click in a CellEditor calls EditingSupport.setValue(), which is triggered by the MouseListener.mouseUp() from ColumnViewer.hookEditingSupport().
In my understanding the .mouseUp() method was only provided in RAP (NOT implemented in RCP) to fix a bug in the old 1.3.0 Tree implementation, because the "Tree widget did not fired mouseDown events" (please check the comments in the code). But in 1.4M1 you said they were fixed. Which means the mouseUp() method could be safely removed. 
Is it so? Because it would probably fix the issue.

I would gladly provide a self-running code snippet, but I don't have the "self-running" part.
It would help us (Dirk would need it also for Bug #322631) big time if you could provide us a "self-running" template where we could just put our code. Is there such thing to download from somewhere?
Comment 4 Ivan Furnadjiev CLA 2010-08-13 08:22:59 EDT
Hi Bogdan, yes... you are right... to fix this bug mouseUp() method should be removed. I've asked for a snippet to double-check that removing this method solves your issue. Can you confirm this?
Comment 5 Ivan Furnadjiev CLA 2010-08-13 08:24:55 EDT
As a self-running snippet I mean an EntryPoint with all needed code in there, like:
-----------
public class ApplicationTesterEntryPoint implements IEntryPoint {

  private void createContents( final Composite parent ) {
    parent.setLayout( GridLayoutFactory.fillDefaults().create() );
  }

  public int createUI() {
    Display display = new Display();
    Shell shell = new Shell( display );
    shell.setText( "Application Tester" );
    createContents( shell );
    shell.setSize( 1280, 600 );
    shell.setLocation( 20, 20 );
    shell.open();
    while( !shell.isDisposed() ) {
      if( !display.readAndDispatch() ) {
        display.sleep();
      }
    }
    display.dispose();
    return 0;
  }
}
---------
Put your part in createContents method.
Comment 6 Ivan Furnadjiev CLA 2010-08-16 12:52:11 EDT
The mouseUp() method from ColumnViewer.hookEditingSupport() has been remove as the new client Tree implementation fires mousedown event correctly. Bogdan, please reopen if the bug persist.
Comment 7 Bogdan B. CLA 2010-08-17 04:35:31 EDT
I did not answered because I wrote a snippet which actually works without problems. So my snippet won't be of any use. Probably there is a mix of other factors which makes mouseUp() to be called in my application, but I wasn't be able to find it. 
But I am confident that 1.4M2 will work fine, as you removed the .mouseUp(). I shall reopen the bug otherwise.
Comment 8 Bogdan B. CLA 2010-09-07 12:30:13 EDT
Created attachment 178338 [details]
Code snippet

Hi Ivan,

I finally managed to write a snippet, and I should appreciate it if you could test it before the 1.4M2 release date.

With 1.4M1 this snippet throws a NPE right when I click in a cell (from mouseUp()). The NPE is not thrown if you comment in the custom ColumnViewerEditorActivationStrategy part, but I need to test on single click. However, since you removed the mouseUp() method in M2, it should work there.

So please do the following test with 1.4M2 (CVS Head):
- without scrolling right
- click in a cell in Column 2 to open the editor
- click in another cell in the same row (Column 3) - ATENTION: you must click very fast (time between mouseDown and mouseUp must be so small as possible)

If you see "CellEditor.fireApplyEditorValue()" before seeing "SWT.Deactivate event" or "DisposeEvent", than the problem is still there (see the initial bug description for details).
Comment 9 Ivan Furnadjiev CLA 2010-09-07 13:36:02 EDT
Hi Bogdan,
I've just tested your snippet and I got NPE (CVS HEAD). Here is the content from the console:
------------------------
EditingSupport.getValue()
editor widget bounds Rectangle {802, 49, 200, 16} --> at display relative Point {826, 155}
SWT.Deactivate event
DisposeEvent
EditingSupport.setValue()

EditingSupport.getValue()
editor widget bounds Rectangle {602, 65, 200, 16} --> at display relative Point {626, 171}
SWT.Deactivate event
DisposeEvent
EditingSupport.setValue()

EditingSupport.getValue()
DisposeEvent
editor widget bounds Rectangle {602, 49, 200, 16} --> at display relative Point {626, 155}
2010-09-07 20:31:34.859:WARN::ERROR:  /rap
java.lang.NullPointerException
	at org.eclipse.jface.viewers.ColumnViewerEditor.activateCellEditor(ColumnViewerEditor.java:210)
	at org.eclipse.jface.viewers.ColumnViewerEditor.handleEditorActivationEvent(ColumnViewerEditor.java:443)
	at org.eclipse.jface.viewers.ColumnViewer.triggerEditorActivationEvent(ColumnViewer.java:674)
	at org.eclipse.jface.viewers.ColumnViewer.handleMouseDown(ColumnViewer.java:658)
	at org.eclipse.jface.viewers.ColumnViewer.access$0(ColumnViewer.java:654)
	at org.eclipse.jface.viewers.ColumnViewer$1.mouseDown(ColumnViewer.java:90)
	at org.eclipse.swt.events.MouseEvent.dispatchToObserver(MouseEvent.java:136)
	at org.eclipse.rwt.internal.events.Event.processEvent(Event.java:44)
	at org.eclipse.swt.events.TypedEvent.processEvent(TypedEvent.java:161)
	at org.eclipse.swt.events.TypedEvent.executeNext(TypedEvent.java:201)
	at org.eclipse.swt.widgets.Display.runPendingMessages(Display.java:1100)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:1090)
	at rap.bugs.entrypoint.TreeGridLinesEntryPoint.createUI(TreeGridLinesEntryPoint.java:98)
	at org.eclipse.rwt.internal.lifecycle.EntryPointManager.createUI(EntryPointManager.java:92)
	at org.eclipse.rwt.internal.lifecycle.RWTLifeCycle.createUI(RWTLifeCycle.java:245)
	at org.eclipse.rwt.internal.lifecycle.RWTLifeCycle$UIThreadController.run(RWTLifeCycle.java:114)
	at java.lang.Thread.run(Thread.java:619)
	at org.eclipse.rwt.internal.lifecycle.UIThread.run(UIThread.java:102)
-----------------------------
I think that this NPE has nothing to do with this bug. Isn't it?
Comment 10 Bogdan B. CLA 2010-09-09 07:33:45 EDT
Hi Ivan,

it may have nothing to do with this bug, but I'd really like to know what is wrong there. Like I said, I get the NPE on the first click with M1 (from mouseUp() ). But I see you clicked 3 times before you get it (you do'nt have the mouseUp() anymore), the third time in the same cell you clicked the second time.

Is there a possibility to test it myself, can you give me a link where I could download your nightly builds of M2?
Comment 11 Ivan Furnadjiev CLA 2010-09-09 07:45:18 EDT
Hi Bogdan, it will be easy to work directly against CVS HEAD ( see http://www.eclipse.org/rap/source/ ). Get the "RAP User Team Project Set" and checkout all RAP bundles in a new workspace. Put your application in the same workspace. Change your launch configuration to use RAP bundles from the workspace instead of target platform. That's all.
Comment 12 Bogdan B. CLA 2010-09-13 09:47:10 EDT
Hi Ivan, I tried that but I get a NullPointerException when I try to start my app:
it seems it can not find resource/widget/rap/display/bg.gif

Any ideea?

java.lang.NullPointerException
	at org.eclipse.rwt.internal.resources.ResourceManagerImpl.createRequestURL(ResourceManagerImpl.java:392)
	at org.eclipse.rwt.internal.resources.ResourceManagerImpl.getLocation(ResourceManagerImpl.java:312)
	at org.eclipse.rap.ui.internal.servlet.ResourceManagerFactory$ResourceManagerWrapper.getLocation(ResourceManagerFactory.java:105)
	at org.eclipse.rwt.internal.service.StartupPage.getBgImage(StartupPage.java:63)
	at org.eclipse.rwt.internal.service.StartupPage.render(StartupPage.java:73)
	at org.eclipse.rwt.internal.service.StartupPage.send(StartupPage.java:44)
	at org.eclipse.rwt.internal.service.LifeCycleServiceHandler.runLifeCycle(LifeCycleServiceHandler.java:73)
	at org.eclipse.rwt.internal.service.LifeCycleServiceHandler.synchronizedService(LifeCycleServiceHandler.java:54)
	at org.eclipse.rwt.internal.service.LifeCycleServiceHandler.service(LifeCycleServiceHandler.java:42)
	at org.eclipse.rwt.internal.service.ServiceManager$HandlerDispatcher.service(ServiceManager.java:98)
	at org.eclipse.rwt.internal.engine.RWTDelegate.doPost(RWTDelegate.java:60)
	at org.eclipse.rap.ui.internal.servlet.RequestHandler.service(RequestHandler.java:51)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	at org.eclipse.equinox.http.servlet.internal.ServletRegistration.service(ServletRegistration.java:61)
	at org.eclipse.equinox.http.servlet.internal.ProxyServlet.processAlias(ProxyServlet.java:126)
	at org.eclipse.equinox.http.servlet.internal.ProxyServlet.service(ProxyServlet.java:60)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	at org.eclipse.equinox.http.jetty.internal.HttpServerManager$InternalHttpServiceServlet.service(HttpServerManager.java:318)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:390)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at org.mortbay.jetty.Server.handle(Server.java:322)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
	at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:924)
	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)
	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
	at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Comment 13 Bogdan B. CLA 2010-09-14 03:09:07 EDT
I fixed that: I had to remove some plug-ins from my launch configuration and now it works. I shall test this bug against M2.
Comment 14 Bogdan B. CLA 2010-09-14 12:36:51 EDT
Hi Ivan,

I just tested my snippet against M2 CVS HEAD and I really have to insist on this bug, because RAP behaves differently than RCP in this case.

So, following scenario:
1) start my snippet
2) click in a cell - a cell editor will open
3) click in the same row in another cell

In this moment, you see on the console:
EditingSupport.setValue()
EditingSupport.getValue()
...
SWT.Deactivate event

If you would test it in RCP, than you would see:
SWT.Deactivate event
EditingSupport.getValue()

Where my SWT.Deactivate Listener calls CellEditor.fireCancelEditing().

Which means that RCP first deactivates the old editor, and only after that fires the mouseDown(). 
RAP first fires the mouseDown(), which in my opinion is wrong because mouseDown() calls ColumnViewerEditor.handleEditorActivationEvent(), where cellEditor is still the one closing. So the following code from handleEditorActivationEvent() actually applies the editing:
if (cellEditor != null) {
    applyEditorValue();
}
But actually I would want to cancel the editing at this point.

In RCP, at this point, cellEditor is already null because I already canceled the editing from my Deactivate Listener. So apply will not be called.

Do you see it as a bug too?
Comment 15 Ivan Furnadjiev CLA 2010-09-15 07:27:02 EDT
I think that the problem is in the order between ShellEvent and MouseEvent events. If you look at TypedEvent#EVENT_ORDER (this is the order in which RAP process the events) the ShellEvents are process after the MouseEvent. Moving the ShellEvent just after the ActivateEvent (they have the same meaning) should solve the problem, but currently I'm not sure about the consequences of this reorder.
Comment 16 Bogdan B. CLA 2010-09-16 10:14:56 EDT
Hi Ivan, thank you for the hint! I can understand that you do not want to change the event processing order, it's too risky.

Anyway, I solved it by overriding the activation method to ensure the canceling of the previously activated editor:

ColumnViewer.triggerEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
    if (getColumnViewerEditor() != null && isCellEditorActive()) {
        // cancel the editing in the old CellEditor        
    }
    super.triggerEditorActivationEvent(event);
}

Is not too elegant, but unless you have a better one, I think it's time to let this bug rest in peace :).
Comment 17 Yury CLA 2010-09-20 06:57:59 EDT
Hi, Ivan, Bogdan!

I had got a similar problem (and I'm almost sure it was the same problem) with mouse and shell events working with celleditors. My fixes were in ColumnViewerEditor and I'm not sure that they are pretty good, but they had fixed my problem. You can see this fixes in the attached patch.

Best regards, 
Yury.
Comment 18 Yury CLA 2010-09-20 06:58:45 EDT
Created attachment 179234 [details]
ColumnViewerEditor patch
Comment 19 Ivan Furnadjiev CLA 2010-09-20 10:13:10 EDT
I've opened a bug 325756 to double check that the RAP events are processed in the same order as SWT.