![JAR search and dependency download from the Maven repository](/logo.png)
rwt.remote.DNDSupport.js Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2009, 2022 Innoopract Informationssysteme GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Innoopract Informationssysteme GmbH - initial API and implementation
* EclipseSource - ongoing development
******************************************************************************/
namespace( "rwt.remote" );
rwt.remote.DNDSupport = function() {
this._dragSources = {};
this._dropTargets = {};
this._eventQueue = {};
this._requestScheduled = false;
this._currentDragControl = null;
this._currentDropControl = null;
this._currentTargetElement = null;
this._currentMousePosition = { x : 0, y : 0 };
this._actionOverwrite = null;
this._dataTypeOverwrite = null;
this._dropFeedbackRenderer = null;
this._dropFeedbackFlags = 0;
this._dragFeedbackWidget = null;
this._blockDrag = false;
};
rwt.remote.DNDSupport.getInstance = function() {
return rwt.runtime.Singletons.get( rwt.remote.DNDSupport );
};
rwt.remote.DNDSupport.prototype = {
/////////////
// dragSource
registerDragSource : function( dragSource ) {
var control = dragSource.control;
control.addEventListener( "dragstart", this._dragStartHandler, this );
control.addEventListener( "dragend", this._dragEndHandler, this );
this._dragSources[ control.toHashCode() ] = dragSource;
},
setDragSourceTransferTypes : function( widget, transferTypes ) {
this._getDragSource( widget ).dataTypes = transferTypes;
},
deregisterDragSource : function( dragSource ) {
var control = dragSource.control;
control.removeEventListener( "dragstart", this._dragStartHandler, this );
control.removeEventListener( "dragend", this._dragEndHandler, this );
delete this._dragSources[ control.toHashCode() ];
},
isDragSource : function( widget ) {
return typeof this._getDragSource( widget ) != "undefined";
},
isDropTarget : function( widget ) {
return typeof this._getDropTarget( widget ) != "undefined";
},
_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 dataTypes = this._getDragSource( target ).dataTypes;
if( dataTypes.length > 0 ) {
for( var i = 0; i < dataTypes.length; i++ ) {
event.addData( dataTypes[ i ], true );
}
this._actionOverwrite = null;
this._currentDragControl = target;
var dndHandler = rwt.event.DragAndDropHandler.getInstance();
dndHandler.clearActions();
var doc = rwt.widgets.base.ClientDocument.getInstance();
doc.addEventListener( "elementOver", this._onMouseOver, this );
doc.addEventListener( "keydown", this._onKeyEvent, this );
doc.addEventListener( "keyup", this._onKeyEvent, this );
this.setCurrentTargetElement( event.getOriginalTarget() );
// fix for bug 296348
rwt.widgets.util.WidgetUtil._fakeMouseEvent( this._currentTargetElement, "mouseout" );
var sourceElement = dndHandler.__dragCache.sourceElement;
var feedbackWidget = this._getFeedbackWidget( control, sourceElement );
// 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() );
}
},
_dragEndHandler : function( event ) {
var target = event.getCurrentTarget();
var mouseEvent = event.getMouseEvent();
// fix for Bug 301544: block new dragStarts until request is send
this._blockDrag = true;
this._sendDragSourceEvent( target, "DragEnd", mouseEvent );
this._cleanUp();
event.stopPropagation();
},
_sendDragSourceEvent : function( widget, type, qxDomEvent ) {
var x = 0;
var y = 0;
if( qxDomEvent instanceof rwt.event.MouseEvent ) {
x = qxDomEvent.getPageX();
y = qxDomEvent.getPageY();
}
var event = {};
event[ "widget" ] = this._getDragSource( widget );
event[ "eventName" ] = type;
event[ "param" ] = {
"x" : Math.round( x ),
"y" : Math.round( y ),
"time" : rwt.remote.EventUtil.eventTimestamp()
};
this._eventQueue[ type ] = event;
var connection = rwt.remote.Connection.getInstance();
if( !this._requestScheduled ) {
connection.addEventListener( "send", this._onSend, this );
this._requestScheduled = true;
}
connection.send();
},
/////////////
// dropTarget
registerDropTarget : function( dropTarget ) {
var control = dropTarget.control;
control.addEventListener( "dragover", this._dragOverHandler, this );
control.addEventListener( "dragmove", this._dragMoveHandler, this );
control.addEventListener( "dragout", this._dragOutHandler, this );
control.addEventListener( "dragdrop", this._dragDropHandler, this );
this._dropTargets[ control.toHashCode() ] = dropTarget;
control.setSupportsDropMethod( rwt.util.Functions.returnTrue );
},
setDropTargetTransferTypes : function( widget, transferTypes ) {
widget.setDropDataTypes( transferTypes );
},
deregisterDropTarget : function( dropTarget ) {
var control = dropTarget.control;
control.setDropDataTypes( [] );
control.removeEventListener( "dragover", this._dragOverHandler, this );
control.removeEventListener( "dragmove", this._dragMoveHandler, this );
control.removeEventListener( "dragout", this._dragOutHandler, this );
control.removeEventListener( "dragdrop", this._dragDropHandler, this );
delete this._dropTargets[ control.toHashCode() ];
control.setSupportsDropMethod( null );
},
_dragOverHandler : function( event ) {
var target = event.getCurrentTarget();
var mouseEvent = event.getMouseEvent();
this._currentDropControl = target;
var action = this._computeCurrentAction( mouseEvent, target );
this._setAction( action, null );
this._sendDropTargetEvent( target, "DragEnter", mouseEvent, action );
event.stopPropagation();
},
_dragMoveHandler : function( event ) {
var target = event.getCurrentTarget();
var mouseEvent = event.getMouseEvent();
this._currentMousePosition.x = mouseEvent.getPageX();
this._currentMousePosition.y = mouseEvent.getPageY();
var action = this._computeCurrentAction( mouseEvent, target );
this._setAction( action, mouseEvent );
this._sendDropTargetEvent( target, "DragOver", mouseEvent, action );
event.stopPropagation();
},
_dragOutHandler : function( event ) {
var target = event.getCurrentTarget();
var mouseEvent = event.getMouseEvent();
if( this._currentTargetElement !== mouseEvent.getDomTarget() ) {
this._onMouseOver( mouseEvent );
}
var dndHandler = rwt.event.DragAndDropHandler.getInstance();
dndHandler.clearActions();
this.setFeedback( target, null, 0 );
this._currentDropControl = null;
this._actionOverwrite = null;
this._dataTypeOverwrite = null;
if( this._isEventScheduled( "DragEnter" ) ) {
this._cancelEvent( "DragEnter" );
this._cancelEvent( "DragOver" );
} else {
this._sendDropTargetEvent( target, "DragLeave", mouseEvent, "none" );
}
event.stopPropagation();
},
_dragDropHandler : function( event ) {
var target = event.getCurrentTarget();
var mouseEvent = event.getMouseEvent();
var action = this._computeCurrentAction( mouseEvent, target );
this._sendDropTargetEvent( target, "DropAccept", mouseEvent, action );
event.stopPropagation();
},
_sendDropTargetEvent : function( widget, type, qxDomEvent, action ) {
var item = this._getCurrentItemTarget();
var itemId = item != null ? rwt.remote.ObjectRegistry.getId( item ) : null;
var x = 0;
var y = 0;
if( qxDomEvent instanceof rwt.event.MouseEvent ) {
x = qxDomEvent.getPageX();
y = qxDomEvent.getPageY();
} else {
x = this._currentMousePosition.x;
y = this._currentMousePosition.y;
}
var source = rwt.remote.ObjectRegistry.getId( this._currentDragControl );
var time = rwt.remote.EventUtil.eventTimestamp();
var operation = action == "alias" ? "link" : action;
var event = {};
event[ "widget" ] = this._getDropTarget( widget );
event[ "eventName" ] = type;
event[ "param" ] = {
"x" : Math.round( x ),
"y" : Math.round( y ),
"item" : itemId,
"operation" : operation,
"feedback" : this._dropFeedbackFlags,
"dataType" : this._dataTypeOverwrite,
"source" : source,
"time" : time
};
this._eventQueue[ type ] = event;
if( !this._requestScheduled ) {
var connection = rwt.remote.Connection.getInstance();
connection.addEventListener( "send", this._onSend, this );
this._requestScheduled = true;
rwt.client.Timer.once( connection.send, connection, 200 );
}
},
_isEventScheduled : function( type ) {
return typeof this._eventQueue[ type ] != "undefined";
},
_cancelEvent : function( type ) {
delete this._eventQueue[ type ];
},
_setPropertyRetroactively : function( widget, property, value ) {
for( var type in this._eventQueue ) {
var event = this._eventQueue[ type ];
if( event[ "widget" ].control === widget ) {
event[ "param" ][ property ] = value;
}
}
},
_attachEvents : function() {
var connection = rwt.remote.Connection.getInstance();
var order = this._getEventOrder( this._eventQueue );
for( var i = 0; i < order.length; i++ ) {
var event = this._eventQueue[ order[ i ] ];
if( event ) {
connection.getRemoteObject( event.widget ).notify( event.eventName, event.param );
}
}
this._eventQueue = {};
},
_getEventOrder : function( events ) {
var order;
if( this._isLeaveBeforeEnter( events ) ) {
order = [ "DragStart", "DragLeave", "DragEnter", "DragOperationChanged", "DragOver",
"DropAccept", "DragEnd" ];
} else {
order = [ "DragStart", "DragEnter", "DragOperationChanged", "DragOver", "DragLeave",
"DropAccept", "DragEnd" ];
}
return order;
},
_isLeaveBeforeEnter : function( events ) {
var leave = events[ "DragLeave" ];
var enter = events[ "DragEnter" ];
return leave && enter && leave[ "param" ].time <= enter[ "param" ].time;
},
_getCurrentItemTarget : function() {
var result = null;
var target = this._getCurrentFeedbackTarget();
if( target instanceof rwt.widgets.base.GridRow ) {
var tree = this._currentDropControl;
result = tree._rowContainer.findItemByRow( target );
} else {
result = target;
}
return result;
},
//////////
// actions
_setAction : function( newAction, sourceEvent ) {
// NOTE: using setCurrentAction would conflict with key events
var dndHandler = rwt.event.DragAndDropHandler.getInstance();
var oldAction = dndHandler.getCurrentAction();
if( oldAction != newAction ) {
dndHandler.clearActions();
dndHandler.setAction( newAction );
if( sourceEvent != null ) {
this._sendDropTargetEvent( this._currentDropControl,
"DragOperationChanged",
sourceEvent,
newAction );
}
}
},
_operationsToActions : function( operations ) {
var result = {};
for( var i = 0; i < operations.length; i++ ) {
var action = this._toAction( operations[ i ] );
result[ action ] = action != null;
}
return result;
},
_toAction : function( operation ) {
var result;
switch( operation ) {
case "DROP_MOVE":
result = "move";
break;
case "DROP_COPY":
result = "copy";
break;
case "DROP_LINK":
result = "alias";
break;
default:
result = operation;
break;
}
return result;
},
_computeCurrentAction : function( domEvent, target ) {
var result;
if( this._actionOverwrite != null ) {
result = this._actionOverwrite;
} else {
result = "move";
var shift = domEvent.isShiftPressed();
var ctrl = domEvent.isCtrlPressed();
var alt = domEvent.isAltPressed();
if( ctrl && !shift && !alt ) {
result = "copy";
} else if( alt && !shift && !ctrl ) {
result = "alias";
} else if( !alt && shift && ctrl ) {
result = "alias";
}
var dropActions = this._getDropTarget( target ).actions;
var dragActions = this._getDragSource( this._currentDragControl ).actions;
if( !dragActions[ result ] || !dropActions[ result ] ) {
result = "none";
}
}
return result;
},
///////////
// feedback
// TODO [tb] : allow overwrite using DropTarget.setDropTargetEffect?
/*
* Creates a feedback-renderer matching the given widget,
* "implementing" the following interface:
* setFeedback : function( feedbackMap )
* renderFeedback : function( target )
* isFeedbackNode : function( node )
*/
_createFeedback : function( widget ) {
if( this._dropFeedbackRenderer == null ) {
if( widget instanceof rwt.widgets.Grid ) {
this._dropFeedbackRenderer = new rwt.widgets.util.GridDNDFeedback( widget );
}
}
},
_renderFeedback : function() {
if( this._dropFeedbackRenderer != null ) {
var target = this._getCurrentFeedbackTarget();
this._dropFeedbackRenderer.renderFeedback( target );
}
},
_getCurrentFeedbackTarget : function() {
var result = null;
if( this._currentDropControl instanceof rwt.widgets.Grid ) {
var element = this._currentTargetElement;
result = this._currentDropControl.getRowContainer().findRowByElement( element );
}
return result;
},
// TODO [tb] : allow overwrite using DragSourceEvent.image?
_getFeedbackWidget : function( sourceControl, sourceElement ) {
if( this._dragFeedbackWidget == null ) {
this._dragFeedbackWidget = new rwt.widgets.base.MultiCellWidget( [ "image", "label" ] );
this._dragFeedbackWidget.setOpacity( 0.7 );
this._dragFeedbackWidget.setEnabled( false );
this._dragFeedbackWidget.setPadding( 2 );
}
if( sourceControl instanceof rwt.widgets.Grid ) {
var row = sourceControl.getRowContainer().findRowByElement( sourceElement );
if( row ) {
this._configureTreeRowFeedback( row );
return this._dragFeedbackWidget;
}
}
return null;
},
_configureTreeRowFeedback : function( row ) {
var widget = this._dragFeedbackWidget;
var tree = this._currentDragControl;
var item = tree._rowContainer.findItemByRow( row );
if( item != null ) {
var config = tree.getRenderConfig();
var image = item.getImage( config.treeColumn );
if( image != null ) {
widget.setCellContent( 0, image[ 0 ] );
var imageWidth = config.itemImageWidth[ config.treeColumn ];
widget.setCellDimension( 0, imageWidth, row.getHeight() );
}
var backgroundColor = item.getCellBackground( config.treeColumn );
var textColor = item.getCellForeground( config.treeColumn );
widget.setBackgroundColor( backgroundColor );
widget.setTextColor( textColor );
var text = item.getText( config.treeColumn );
if( !config.markupEnabled ) {
text = rwt.util.Encoding.escapeText( text, false );
}
widget.setCellContent( 1, text );
widget.setFont( config.font );
}
},
_resetFeedbackWidget : function() {
if( this._dragFeedbackWidget != null ) {
this._dragFeedbackWidget.setParent( null );
this._dragFeedbackWidget.setFont( null );
this._dragFeedbackWidget.setCellContent( 0, null );
this._dragFeedbackWidget.setCellDimension( 0, null, null );
this._dragFeedbackWidget.setCellContent( 1, null );
this._dragFeedbackWidget.setBackgroundColor( null );
}
},
///////////////
// eventhandler
_onSend : function() {
this._attachEvents();
this._requestScheduled = false;
this._blockDrag = false;
rwt.remote.Connection.getInstance().removeEventListener( "send", this._onSend, this );
},
_onMouseOver : function( event ) {
var target = event.getDomTarget();
if( this._dropFeedbackRenderer != null ) {
if( !this._dropFeedbackRenderer.isFeedbackNode( target ) ) {
this.setCurrentTargetElement( target );
}
} else {
this.setCurrentTargetElement( target );
}
},
setCurrentTargetElement : function( target ) {
this._currentTargetElement = target;
this._renderFeedback();
},
_onKeyEvent : function( event ) {
if( event.getType() == "keyup" && event.getKeyIdentifier() == "Alt" ) {
// NOTE: This combination causes problems with future dom events,
// so instead we cancel the operation.
this._sendDragSourceEvent( this._currentDragControl, "DragEnd", event );
this.cancel();
} else if( this._currentDropControl != null ) {
var dndHandler = rwt.event.DragAndDropHandler.getInstance();
var action = this._computeCurrentAction( event, this._currentDropControl );
this._setAction( action, event );
dndHandler._renderCursor();
}
},
/////////
// helper
_cleanUp : function() {
// fix for bug 296348
var widgetUtil = rwt.widgets.util.WidgetUtil;
widgetUtil._fakeMouseEvent( this._currentTargetElement, "elementOver" );
widgetUtil._fakeMouseEvent( this._currentTargetElement, "mouseover" );
this.setCurrentTargetElement( null );
if( this._currentDropControl != null) {
this.setFeedback( this._currentDropControl, null, 0 );
this._currentDropControl = null;
}
var dndHandler = rwt.event.DragAndDropHandler.getInstance();
dndHandler.setFeedbackWidget( null );
this._resetFeedbackWidget();
this._currentDragControl = null;
this._dataTypeOverwrite = null;
this._currentMousePosition.x = 0;
this._currentMousePosition.y = 0;
var doc = rwt.widgets.base.ClientDocument.getInstance();
doc.removeEventListener( "elementOver", this._onMouseOver, this );
doc.removeEventListener( "keydown", this._onKeyEvent, this );
doc.removeEventListener( "keyup", this._onKeyEvent, this );
},
_getDragSource : function( control ) {
return this._dragSources[ control.toHashCode() ];
},
_getDropTarget : function( control ) {
return this._dropTargets[ control.toHashCode() ];
},
//////////////////
// server response
cancel : function() {
if( this._currentDragControl != null ) {
var dndHandler = rwt.event.DragAndDropHandler.getInstance();
dndHandler.globalCancelDrag();
this._cleanUp();
}
},
setOperationOverwrite : function( widget, operation ) {
if( widget == this._currentDropControl ) {
var action = this._toAction( operation );
var dndHandler = rwt.event.DragAndDropHandler.getInstance();
this._actionOverwrite = action;
this._setAction( action, null );
dndHandler._renderCursor();
}
this._setPropertyRetroactively( widget, "operation", operation );
},
/*
* feedback is an array of strings with possible values
* "select", "before", "after", "expand" and "scroll", while
* flags is the "feedback"-field of SWTs dropTargetEvent,
* representing the same information as an integer.
*/
setFeedback : function( widget, feedback, flags ) {
if( widget == this._currentDropControl ) {
if( feedback != null ) {
this._createFeedback( widget );
if( this._dropFeedbackRenderer != null ) {
var feedbackMap = {};
for( var i = 0; i < feedback.length; i++ ) {
feedbackMap[ feedback[ i ] ] = true;
}
this._dropFeedbackRenderer.setFeedback( feedbackMap );
this._renderFeedback();
}
} else if( this._dropFeedbackRenderer != null ) {
this._dropFeedbackRenderer.dispose();
this._dropFeedbackRenderer = null;
}
this._dropFeedbackFlags = flags;
}
},
setDataType : function( widget, type ) {
if( widget == this._currentDropControl ) {
this._dataTypeOverwrite = type;
}
this._setPropertyRetroactively( widget, "dataType", type );
}
};
© 2015 - 2025 Weber Informatics LLC | Privacy Policy