Bug 447710 - Drag&drop takes wrong drag source widget if the mouse is moved fast after clicking
Summary: Drag&drop takes wrong drag source widget if the mouse is moved fast after cli...
Status: ASSIGNED
Alias: None
Product: RAP
Classification: RT
Component: RWT (show other bugs)
Version: 2.2   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-10-17 10:11 EDT by Gábor Lipták CLA
Modified: 2015-03-18 11:28 EDT (History)
0 users

See Also:


Attachments
The source files to reproduce the problem (11.76 KB, application/zip)
2014-10-22 05:44 EDT, Gábor Lipták CLA
no flags Details
A video about the bug. See that the column 11 should be dragged, but sometimes for example 10 is taken. (7.17 MB, video/x-msvideo)
2014-10-22 05:45 EDT, Gábor Lipták CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Gábor Lipták CLA 2014-10-17 10:11:17 EDT
We have a table, where the user can drag and drop columns to order them. We noticed, that if the user does it really quickly, wrong column gets dropped. After examining the JSON requests coming from the browser in case of a D&D we realized, that the DragStart and the MouseClick event has different x y coordinates, which should not be the case.

A small demo code will be on monday attached, with which it will be easily reproducable. Click on some column and IMMEDIATELY move the item really fast. 

After reading the rap-client.js I have found the bug, and I have a probably not that nice, but working solution.

So in org.eclipse.rap\bundles\org.eclipse.rap.rwt\js\rwt\remote\DNDSupport.js you find this method:

    _dragStartHandler : function( event ) {
      var wm = rwt.remote.WidgetManager.getInstance();
      var target = event.getCurrentTarget();
      var control = wm.findControl( event.getTarget() );
      if( control == target && !this._blockDrag ) {
        var hash = target.toHashCode();
        var dataTypes = this._dragSources[ hash ].dataTypes;
        if( dataTypes.length > 0 ) {
          for( var i = 0; i < dataTypes.length; i++ ) {
            event.addData( dataTypes[ i ], true );
          }
          this._actionOverwrite = null;
          this._currentDragSource = target;
          var dndHandler = rwt.event.DragAndDropHandler.getInstance();
          dndHandler.clearActions();
          var doc = rwt.widgets.base.ClientDocument.getInstance();
          doc.addEventListener( "mouseover", this._onMouseOver, this );
          doc.addEventListener( "keydown", this._onKeyEvent, this );
          doc.addEventListener( "keyup", this._onKeyEvent, this );
          this.setCurrentTargetWidget( event.getOriginalTarget() );
          // fix for bug 296348
          var widgetUtil = rwt.widgets.util.WidgetUtil;
          widgetUtil._fakeMouseEvent( this._currentTargetWidget, "mouseout" );
          var sourceWidget = dndHandler.__dragCache.sourceWidget;
          var feedbackWidget = this._getFeedbackWidget( control, sourceWidget );
          // Note: Unlike SWT, the feedbackWidget can not be rendered behind
          // the cursor, i.e. with a negative offset, as the widget would
          // get all the mouse-events instead of a potential drop-target.
          dndHandler.setFeedbackWidget( feedbackWidget, 10, 20 );
          event.startDrag();
          event.stopPropagation();
        }
        this._sendDragSourceEvent( target, "DragStart", event.getMouseEvent() );
      }
    },

This calls _sendDragSourceEvent:
    _sendDragSourceEvent : function( widget, type, qxDomEvent ) {
      var x = 0;
      var y = 0;
      if( qxDomEvent instanceof rwt.event.MouseEvent ) {
        x = qxDomEvent.getPageX();
        y = qxDomEvent.getPageY();
      }
      var parameters = {
        "x" : x,
        "y" : y,
        "time" : rwt.remote.EventUtil.eventTimestamp()
      };
      rwt.remote.Connection.getInstance().getRemoteObject( widget ).notify( type, parameters );
    },

When I debugged _sendDragSourceEvent I have seen, that the "dragstart" event is sent with the coordinates of the javascript mousemove event. I have just seen that some things are saved into the DragAndDropHandler on mouse click, so I came up with this fix below (ugly a bit, but works as expected):

_sendDragSourceEvent : function( widget, type, qxDomEvent ) {
      var x = 0;
      var y = 0;
      if( qxDomEvent instanceof rwt.event.MouseEvent ) {
		if ( type=="DragStart" ) {
			x = rwt.event.DragAndDropHandler.getInstance().__dragCache.pageX;
			y = rwt.event.DragAndDropHandler.getInstance().__dragCache.pageY;
		}
		else {
			x = qxDomEvent.getPageX();
			y = qxDomEvent.getPageY();
		}
      }
      var parameters = {
        "x" : x,
        "y" : y,
        "time" : rwt.remote.EventUtil.eventTimestamp()
      };
      rwt.remote.Connection.getInstance().getRemoteObject( widget ).notify( type, parameters );
    }

As a bonus I will soon fire a gerrit commit with the applied patch on the master. As far as I see master is also affected.

Since I need to create a fixed 2.2 version for myself it would be really good to hear your opinion if it is a correct fix or not. It seems to work, but your feedback is important for me.
Comment 1 Gábor Lipták CLA 2014-10-17 11:29:43 EDT
I have sent my patch twice by an error, but I guess it will be ok.
Comment 2 Gábor Lipták CLA 2014-10-22 05:44:19 EDT
Created attachment 248080 [details]
The source files to reproduce the problem
Comment 3 Gábor Lipták CLA 2014-10-22 05:45:24 EDT
Created attachment 248081 [details]
A video about the bug. See that the column 11 should be dragged, but sometimes for example 10 is taken.
Comment 4 Gábor Lipták CLA 2015-03-11 08:52:47 EDT
Hi,

are there any news here? Is my change accepted? Should I change something?

Regards,

Gábor
Comment 5 Ivan Furnadjiev CLA 2015-03-11 09:46:34 EDT
Sorry, but no news here. As you mentioned in the description, even the fix is working, it's "ugly a bit". I hope we'll come with something more cleaner for the release.
Comment 6 Ivan Furnadjiev CLA 2015-03-18 11:24:31 EDT
Gábor, today I looked at your code and I wondered why did you use the drag event x, y coordinates to obtain the dragged widget? The DragSourceEvent#getSource() (event.widget) should contain the correct dragged widget.
Comment 7 Gábor Lipták CLA 2015-03-18 11:28:11 EDT
I will check your hint and come back to you.