/******************************************************************************* * Copyright (c) 2009, 2014 EclipseSource 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: * EclipseSource - initial API and implementation ******************************************************************************/ package org.eclipse.swt.internal.widgets.displaykit; import static org.eclipse.rap.rwt.internal.lifecycle.DisplayUtil.getId; import static org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil.getId; import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject; import static org.eclipse.rap.rwt.testfixture.internal.Fixture.getProtocolMessage; import static org.eclipse.swt.internal.widgets.displaykit.DNDSupport.handleOperations; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.eclipse.rap.json.JsonArray; import org.eclipse.rap.json.JsonObject; import org.eclipse.rap.rwt.internal.lifecycle.PhaseId; import org.eclipse.rap.rwt.internal.protocol.ControlOperationHandler; import org.eclipse.rap.rwt.internal.protocol.Operation.CallOperation; import org.eclipse.rap.rwt.testfixture.internal.Fixture; import org.eclipse.rap.rwt.testfixture.internal.TestMessage; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSource; import org.eclipse.swt.dnd.DragSourceAdapter; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.DropTargetListener; import org.eclipse.swt.dnd.HTMLTransfer; import org.eclipse.swt.dnd.RTFTransfer; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.events.DragDetectEvent; import org.eclipse.swt.events.DragDetectListener; import org.eclipse.swt.events.TypedEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.internal.dnd.dragsourcekit.DragSourceOperationHandler; import org.eclipse.swt.internal.dnd.droptargetkit.DropTargetOperationHandler; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.junit.After; import org.junit.Before; import org.junit.Test; public class DNDSupport_Test { private Display display; private Shell shell; private List<TypedEvent> events; private List<Integer> eventTypes; private Control sourceControl; private Control targetControl; private DragSource dragSource; private DropTarget dropTarget; private Transfer[] transfers; @Before public void setUp() { Fixture.setUp(); display = new Display(); shell = new Shell( display ); shell.open(); sourceControl = new Label( shell, SWT.NONE ); targetControl = new Label( shell, SWT.NONE ); events = new ArrayList<TypedEvent>(); eventTypes = new ArrayList<Integer>(); Fixture.fakeNewRequest(); Fixture.fakePhase( PhaseId.PROCESS_ACTION ); transfers = new Transfer[] { HTMLTransfer.getInstance(), TextTransfer.getInstance() }; } @After public void tearDown() { Fixture.tearDown(); } @Test public void testHandleOperations_processesOnlyDNDOperations() { ControlOperationHandler controlHandler = mock( ControlOperationHandler.class ); getRemoteObject( sourceControl ).setHandler( controlHandler ); Fixture.fakeSetProperty( getId( display ), "cursorLocation", new JsonArray().add( 1 ).add( 2 ) ); Fixture.fakeSetProperty( getId( sourceControl ), "text", "foo" ); handleOperations(); assertEquals( new Point( 0, 0 ), display.getCursorLocation() ); verify( controlHandler, never() ).handleSet( new JsonObject().add( "text", "foo" ) ); } @Test public void testDragDetectEvent() { createDragSource( DND.DROP_MOVE ); DragDetectListener listener = mock( DragDetectListener.class ); sourceControl.addDragDetectListener( listener ); fakeDragSourceEvent( "DragStart", 1 ); Fixture.executeLifeCycleFromServerThread(); verify( listener, times( 1 ) ).dragDetected( any( DragDetectEvent.class ) ); } @Test public void testDragStartEvent() { createDragSource( DND.DROP_MOVE ); DragSourceListener listener = mock( DragSourceListener.class ); dragSource.addDragListener( listener ); fakeDragSourceEvent( "DragStart", 1 ); Fixture.executeLifeCycleFromServerThread(); verify( listener, times( 1 ) ).dragStart( any( DragSourceEvent.class ) ); } @Test public void testCancelStart() { createDragSource( DND.DROP_MOVE ); dragSource.addDragListener( new DragSourceAdapter() { @Override public void dragStart( DragSourceEvent event ) { event.doit = false; } } ); fakeDragSourceEvent( "DragStart", 1 ); Fixture.executeLifeCycleFromServerThread(); assertNotNull( getProtocolMessage().findCallOperation( dragSource, "cancel" ) ); } @Test public void testDragDetectAndDragStartOrder() { createDragSource( DND.DROP_MOVE ); addLogger( dragSource ); sourceControl.addDragDetectListener( new DragDetectListener() { public void dragDetected( DragDetectEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( SWT.DragDetect ) ); } } ); fakeDragSourceEvent( "DragStart", 1 ); Fixture.executeLifeCycleFromServerThread(); int[] expected = new int[]{ SWT.DragDetect, DND.DragStart }; assertTrue( Arrays.equals( expected, getEventOrder() ) ); } @Test public void testDragStartCoordinates() { shell.setLocation( 5, 5 ); sourceControl.setLocation( 10, 20 ); createDragSource( DND.DROP_MOVE ); new DropTarget( targetControl, DND.DROP_MOVE ); dragSource.addDragListener( new DragSourceAdapter() { @Override public void dragStart( DragSourceEvent event ) { events.add( event ); } } ); Fixture.fakeNewRequest(); createDragSourceEvent( "DragStart", 20, 30, "move", 1 ); Fixture.executeLifeCycleFromServerThread(); DragSourceEvent dragSourceEvent = ( DragSourceEvent )events.get( 0 ); assertEquals( 4, dragSourceEvent.x ); assertEquals( 4, dragSourceEvent.y ); } @Test public void testDropTargetLeaveBeforeEnter() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); fakeDropTargetEvent( "DragEnter", 1 ); Fixture.executeLifeCycleFromServerThread(); addLogger( dropTarget ); Fixture.fakeNewRequest(); fakeDropTargetEvent( "DragLeave", 2 ); fakeDropTargetEvent( "DragEnter", 3 ); fakeDropTargetEvent( "DragOver", 4 ); Fixture.executeLifeCycleFromServerThread(); int[] expected = new int[]{ DND.DragLeave, DND.DragEnter, DND.DragOver }; assertTrue( Arrays.equals( expected, getEventOrder() ) ); } @Test public void testDropOverValidTarget() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); addLogger( dragSource ); addLogger( dropTarget ); addSetDragDataListener( dragSource, "text" ); fakeDropTargetEvent( "DropAccept", 1 ); fakeDragSourceEvent( "DragEnd", 2 ); Fixture.readDataAndProcessAction( display ); int[] expected = new int[]{ DND.DragLeave, DND.DropAccept, DND.DragSetData, DND.Drop, DND.DragEnd }; assertTrue( Arrays.equals( expected, getEventOrder() ) ); } @Test public void testDataTransferOnDrop() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); addLogger( dragSource ); addLogger( dropTarget ); addSetDragDataListener( dragSource, "Hello World!" ); createDropTargetEvent( "DropAccept", 0, 0, "move", getTextType(), 1 ); Fixture.readDataAndProcessAction( display ); DragSourceEvent dragSetDataEvent = getDragSourceEvent( 2 ); DropTargetEvent dropEvent = getDropTargetEvent( 3 ); assertEquals( dragSetDataEvent.dataType, dropEvent.currentDataType ); assertEquals( "Hello World!", dropEvent.data ); } @Test public void testInvalidDataOnDragSetData() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); addLogger( dragSource ); addLogger( dropTarget ); addSetDragDataListener( dragSource, new Date() ); SWTException exception = null; fakeDropTargetEvent( "DropAccept", 1 ); try { Fixture.executeLifeCycleFromServerThread(); fail(); } catch( SWTException e ) { exception = e; } int[] expected = new int[]{ DND.DragLeave, DND.DropAccept, DND.DragSetData }; assertTrue( Arrays.equals( expected, getEventOrder() ) ); assertEquals( DND.ERROR_INVALID_DATA, exception.code ); } @Test public void testChangeDataTypeOnDrop() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); final TransferData[] originalType = new TransferData[ 1 ]; dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dropAccept( DropTargetEvent event ) { originalType[ 0 ] = event.currentDataType; boolean isFirstType = event.currentDataType.type == getType( transfers[ 0 ] ).type; event.currentDataType = getType( transfers[ isFirstType ? 1 : 0 ] ); } @Override public void drop( DropTargetEvent event ) { events.add( event ); } } ); addLogger( dragSource ); addSetDragDataListener( dragSource, "data" ); fakeDropTargetEvent( "DropAccept", 1 ); Fixture.readDataAndProcessAction( display ); DragSourceEvent dragSetDataEvent = getDragSourceEvent( 0 ); DropTargetEvent dropEvent = getDropTargetEvent( 1 ); assertTrue( dragSetDataEvent.dataType.type != originalType[ 0 ].type ); assertTrue( dragSetDataEvent.dataType.type == dropEvent.currentDataType.type ); } @Test public void testChangeDataTypeInvalidOnDrop() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dropAccept( DropTargetEvent event ) { RTFTransfer rtfTransfer = RTFTransfer.getInstance(); event.currentDataType = rtfTransfer.getSupportedTypes()[ 0 ]; } } ); addLogger( dragSource ); addLogger( dropTarget ); fakeDropTargetEvent( "DropAccept", 1 ); Fixture.readDataAndProcessAction( display ); int[] expected = new int[]{ DND.DragLeave, DND.DropAccept }; assertTrue( Arrays.equals( expected, getEventOrder() ) ); } @Test public void testNoDropAfterDropAcceptEvent() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dropAccept( DropTargetEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.DropAccept ) ); event.detail = DND.DROP_NONE; } @Override public void drop( DropTargetEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.Drop ) ); } } ); addLogger( dragSource ); fakeDropTargetEvent( "DropAccept", 1 ); fakeDragSourceEvent( "DragEnd", 2 ); Fixture.readDataAndProcessAction( display ); int[] expected = new int[]{ DND.DropAccept, DND.DragEnd }; assertTrue( Arrays.equals( expected, getEventOrder() ) ); assertTrue( getDragSourceEvent( 1 ).doit ); // Actual SWT behavior } @Test public void testDropOverNonTarget() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); addLogger( dragSource ); addLogger( dropTarget ); fakeDragSourceEvent( "DragEnd", 1 ); Fixture.readDataAndProcessAction( display ); assertEquals( 1, events.size() ); DragSourceEvent event = getDragSourceEvent( 0 ); assertEquals( DND.DragEnd, getEventType( 0 ) ); assertTrue( event.doit ); // Actual SWT behavior } @Test public void testChangeDetailInDropAccept() { createDragSource( DND.DROP_MOVE | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_COPY ); addLogger( dragSource ); addSetDragDataListener( dragSource, "text Data" ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dropAccept( DropTargetEvent event ) { events.add( event ); event.detail = DND.DROP_COPY; } @Override public void drop( DropTargetEvent event ) { events.add( event ); } } ); fakeDropTargetEvent( "DropAccept", 1 ); fakeDragSourceEvent( "DragEnd", 2 ); Fixture.readDataAndProcessAction( display ); assertEquals( DND.DROP_COPY, getDropTargetEvent( 0 ).detail ); assertEquals( DND.DROP_NONE, getDragSourceEvent( 1 ).detail ); assertEquals( DND.DROP_COPY, getDropTargetEvent( 2 ).detail ); assertEquals( DND.DROP_COPY, getDragSourceEvent( 3 ).detail ); assertTrue( getDragSourceEvent( 3 ).doit ); } @Test public void testChangeDetailInvalidInDropAccept() { createDragSource( DND.DROP_MOVE | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE ); addLogger( dragSource ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dropAccept( DropTargetEvent event ) { event.detail = DND.DROP_COPY; } } ); fakeDropTargetEvent( "DropAccept", 1 ); fakeDragSourceEvent( "DragEnd", 2 ); Fixture.readDataAndProcessAction( display ); assertTrue( getDragSourceEvent( 0 ).doit ); // This is still true in SWT/Win assertEquals( DND.DROP_NONE, getDragSourceEvent( 0 ).detail ); } @Test public void testDragSetDataDoitIsFalse() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); addLogger( dragSource ); addLogger( dropTarget ); dragSource.addDragListener( new DragSourceAdapter() { @Override public void dragSetData( DragSourceEvent event ) { event.data = "TestData"; event.doit = false; } } ); fakeDropTargetEvent( "DropAccept", 1 ); fakeDragSourceEvent( "DragEnd", 2 ); Fixture.readDataAndProcessAction( display ); int[] expected = new int[]{ DND.DragLeave, DND.DropAccept, DND.DragSetData, DND.Drop, DND.DragEnd }; assertTrue( Arrays.equals( expected, getEventOrder() ) ); // NOTE: This is not the behavior documented for SWT, but how SWT behaves in Windows (SWT bug?) assertNull( getDropTargetEvent( 3 ).data ); assertTrue( getDragSourceEvent( 4 ).doit ); } @Test public void testDragSetDataDataType() { createDragSource( DND.DROP_MOVE ); createDropTarget( DND.DROP_MOVE ); addSetDragDataListener( dragSource, "string" ); addLogger( dropTarget ); addLogger( dragSource ); fakeDropTargetEvent( "DropAccept", 0 ); Fixture.readDataAndProcessAction( display ); DragSourceEvent setDataEvent = getDragSourceEvent( 2 ); DropTargetEvent dropEvent = getDropTargetEvent( 3 ); assertNotNull( setDataEvent.dataType ); assertEquals( setDataEvent.data, dropEvent.data ); assertTrue( TransferData.sameType( setDataEvent.dataType, dropEvent.currentDataType ) ); } @Test public void testResponseNoDetailChange() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTargetEvent( "DragEnter", 10, 10, "copy", getTextType(), 1 ); createDropTargetEvent( "DragOver", 10, 10, "copy", getTextType(), 2 ); Fixture.executeLifeCycleFromServerThread(); TestMessage message = Fixture.getProtocolMessage(); assertNull( message.findSetOperation( dragSource, "changeDetail" ) ); } @Test public void testResponseDetailChangedOnEnter() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragEnter( DropTargetEvent event ) { event.detail = DND.DROP_LINK; } } ); fakeDropTargetEvent( "DragEnter", 1 ); fakeDropTargetEvent( "DragOver", 2 ); Fixture.executeLifeCycleFromServerThread(); TestMessage message = Fixture.getProtocolMessage(); CallOperation call = message.findCallOperation( dropTarget, "changeDetail" ); assertEquals( "DROP_LINK", call.getParameters().get( "detail" ).asString() ); } @Test public void testResponseDetailChangedOnOver() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragOver( DropTargetEvent event ) { event.detail = DND.DROP_LINK; } } ); createDropTargetEvent( "DragEnter", 10, 10, "move", getTextType(), 1 ); createDropTargetEvent( "DragOver", 10, 10, "copy", getTextType(), 2 ); Fixture.executeLifeCycleFromServerThread(); TestMessage message = Fixture.getProtocolMessage(); CallOperation call = message.findCallOperation( dropTarget, "changeDetail" ); assertEquals( "DROP_LINK", call.getParameters().get( "detail" ).asString() ); } @Test public void testDropAcceptWithDetailChangedOnEnter() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); addSetDragDataListener( dragSource, "some data" ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragEnter( DropTargetEvent event ) { event.detail = DND.DROP_COPY; } } ); addLogger( dropTarget ); Fixture.executeLifeCycleFromServerThread(); // clear pending message operations Fixture.fakeNewRequest(); fakeDropTargetEvent( "DragEnter", 1 ); fakeDropTargetEvent( "DragOver", 2 ); fakeDropTargetEvent( "DropAccept", 3 ); fakeDragSourceEvent( "DragEnd", 3 ); Fixture.executeLifeCycleFromServerThread(); TestMessage message = Fixture.getProtocolMessage(); assertEquals( 0, message.getOperationCount() ); assertEquals( DND.DROP_COPY, getDropTargetEvent( 0 ).detail ); assertEquals( DND.DROP_COPY, getDropTargetEvent( 1 ).detail ); assertEquals( DND.DROP_COPY, getDropTargetEvent( 2 ).detail ); assertEquals( DND.DROP_COPY, getDropTargetEvent( 3 ).detail ); assertEquals( DND.DROP_COPY, getDropTargetEvent( 4 ).detail ); } @Test public void testResponseFeedbackChangedOnEnter() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragEnter( DropTargetEvent event ) { event.feedback = DND.FEEDBACK_SELECT; } } ); Fixture.executeLifeCycleFromServerThread(); // clear message Fixture.fakeNewRequest(); fakeDropTargetEvent( "DragEnter", 1 ); fakeDropTargetEvent( "DragOver", 2 ); Fixture.executeLifeCycleFromServerThread(); TestMessage message = Fixture.getProtocolMessage(); CallOperation call = message.findCallOperation( dropTarget, "changeFeedback" ); assertEquals( DND.FEEDBACK_SELECT, call.getParameters().get( "flags" ).asInt() ); JsonArray feedbackArr = call.getParameters().get( "feedback" ).asArray(); assertEquals( 1, feedbackArr.size() ); assertEquals( "FEEDBACK_SELECT", feedbackArr.get( 0 ).asString() ); } @Test public void testResponseFeedbackChangedOnOver() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragOver( DropTargetEvent event ) { event.feedback = DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL; } } ); Fixture.executeLifeCycleFromServerThread(); // clear message Fixture.fakeNewRequest(); fakeDropTargetEvent( "DragEnter", 1 ); fakeDropTargetEvent( "DragOver", 2 ); Fixture.executeLifeCycleFromServerThread(); TestMessage message = Fixture.getProtocolMessage(); CallOperation call = message.findCallOperation( dropTarget, "changeFeedback" ); assertEquals( DND.FEEDBACK_SCROLL | DND.FEEDBACK_EXPAND, call.getParameters().get( "flags" ).asInt() ); JsonArray feedbackArr = call.getParameters().get( "feedback" ).asArray(); assertEquals( 2, feedbackArr.size() ); assertEquals( "FEEDBACK_EXPAND", feedbackArr.get( 0 ).asString() ); assertEquals( "FEEDBACK_SCROLL", feedbackArr.get( 1 ).asString() ); } @Test public void testResponseInitDataType() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); Transfer[] types = new Transfer[] { TextTransfer.getInstance(), RTFTransfer.getInstance() }; dragSource.setTransfer( types ); dropTarget.setTransfer( types ); Fixture.executeLifeCycleFromServerThread(); Fixture.fakeNewRequest(); fakeDropTargetEvent( "DragEnter", 1 ); Fixture.executeLifeCycleFromServerThread(); TestMessage message = Fixture.getProtocolMessage(); assertNotNull( message.findCallOperation( dropTarget, "changeDataType" ) ); } @Test public void testResponseChangeDataTypeOnOver() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); addLogger( dropTarget ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragOver( DropTargetEvent event ) { event.currentDataType = TextTransfer.getInstance().getSupportedTypes()[ 0 ]; } } ); Fixture.executeLifeCycleFromServerThread(); Fixture.fakeNewRequest(); fakeDropTargetEvent( "DragEnter", 1 ); fakeDropTargetEvent( "DragOver", 2 ); Fixture.executeLifeCycleFromServerThread(); DropTargetEvent dragEnter = getDropTargetEvent( 0 ); assertTrue( HTMLTransfer.getInstance().isSupportedType( dragEnter.currentDataType ) ); TestMessage message = Fixture.getProtocolMessage(); CallOperation call = message.findCallOperation( dropTarget, "changeDataType" ); assertEquals( getTextType(), call.getParameters().get( "dataType" ).asInt() ); } @Test public void testResponseChangeDataTypeOnEnter() { int operations = DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY; createDragSource( operations ); createDropTarget( operations ); addLogger( dropTarget ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragEnter( DropTargetEvent event ) { event.currentDataType = TextTransfer.getInstance().getSupportedTypes()[ 0 ]; } } ); Fixture.executeLifeCycleFromServerThread(); Fixture.fakeNewRequest(); fakeDropTargetEvent( "DragEnter", 1 ); fakeDropTargetEvent( "DragOver", 2 ); Fixture.executeLifeCycleFromServerThread(); DropTargetEvent dragOver = getDropTargetEvent( 1 ); assertTrue( TextTransfer.getInstance().isSupportedType( dragOver.currentDataType ) ); TestMessage message = Fixture.getProtocolMessage(); CallOperation call = message.findCallOperation( dropTarget, "changeDataType" ); int expectedType = TextTransfer.getInstance().getSupportedTypes()[ 0 ].type; assertEquals( expectedType, call.getParameters().get( "dataType" ).asInt() ); } @Test public void testResponseChangeDataTypeInvalid() { // NOTE : Setting an invalid value on currentDataType reverts the field // back to the next-best valid value. This is NOT SWT-like behavior! // SWT would set null and display the DROP_NONE cursor. createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); dragSource.setTransfer( new Transfer[] { TextTransfer.getInstance() } ); dropTarget.setTransfer( new Transfer[] { TextTransfer.getInstance() } ); dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragOver( DropTargetEvent event ) { event.currentDataType = RTFTransfer.getInstance().getSupportedTypes()[ 0 ]; } } ); Fixture.executeLifeCycleFromServerThread(); Fixture.fakeNewRequest(); fakeDropTargetEvent( "DragOver", 1 ); Fixture.executeLifeCycleFromServerThread(); TestMessage message = Fixture.getProtocolMessage(); CallOperation call = message.findCallOperation( dropTarget, "changeDataType" ); assertEquals( getTextType(), call.getParameters().get( "dataType" ).asInt() ); } @Test public void testOperationChangedEvent() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_COPY ); addLogger( dropTarget ); fakeDropTargetEvent( "DragEnter", 2 ); createDropTargetEvent( "DragOperationChanged", 0, 0, "copy", getTextType(), 3 ); fakeDropTargetEvent( "DragOver", 5 ); Fixture.executeLifeCycleFromServerThread(); DropTargetEvent dragOperationChanged = getDropTargetEvent( 1 ); assertEquals( DND.DragOperationChanged, getEventType( 1 ) ); assertTrue( ( dragOperationChanged.detail & DND.DROP_COPY ) != 0 ); assertEquals( DND.DragOver, getEventType( 2 ) ); } @Test public void testOperationsField() { createDragSource( DND.DROP_MOVE | DND.DROP_LINK ); createDropTarget( DND.DROP_MOVE | DND.DROP_LINK ); dragSource.addDragListener( new DragSourceAdapter(){ @Override public void dragSetData( DragSourceEvent event ) { event.data = "text"; } } ); addLogger( dropTarget ); fakeDropTargetEvent( "DragEnter", 2 ); fakeDropTargetEvent( "DragOver", 5 ); fakeDropTargetEvent( "DragOperationChanged", 7 ); fakeDropTargetEvent( "DropAccept", 8 ); Fixture.readDataAndProcessAction( display ); assertEquals( 6, events.size() ); assertEquals( DND.DROP_MOVE | DND.DROP_LINK, getDropTargetEvent( 0 ).operations ); assertEquals( DND.DROP_MOVE | DND.DROP_LINK, getDropTargetEvent( 1 ).operations ); assertEquals( DND.DROP_MOVE | DND.DROP_LINK, getDropTargetEvent( 2 ).operations ); assertEquals( 0, getDropTargetEvent( 3 ).operations ); assertEquals( DND.DROP_MOVE | DND.DROP_LINK, getDropTargetEvent( 4 ).operations ); assertEquals( DND.DROP_MOVE | DND.DROP_LINK, getDropTargetEvent( 5 ).operations ); } private void fakeDragSourceEvent( String eventType, int time ) { createDragSourceEvent( eventType, 0, 0, "move", time ); } private void createDragSourceEvent( String eventType, int x, int y, String operation, int time ) { JsonObject parameters = new JsonObject().add( "x", x ).add( "y", y ).add( "time", time ); Fixture.fakeNotifyOperation( getId( dragSource ), eventType, parameters ); } private void fakeDropTargetEvent( String eventType, int time ) { createDropTargetEvent( eventType, 0, 0, "move", getTextType(), time ); } private void createDropTargetEvent( String eventType, int x, int y, String operation, int dataType, int time ) { JsonObject parameters = new JsonObject() .add( "x", x ) .add( "y", y ) .add( "time", time ) .add( "operation", operation ) .add( "feedback", 0 ) .add( "source", getId( sourceControl ) ) .add( "dataType", dataType ); Fixture.fakeNotifyOperation( getId( dropTarget ), eventType, parameters ); } private void createDropTarget( int style ) { dropTarget = new DropTarget( targetControl, style ); dropTarget.setTransfer( transfers ); getRemoteObject( dropTarget ).setHandler( new DropTargetOperationHandler( dropTarget ) ); Fixture.markInitialized( dropTarget ); } private void createDragSource( int style ) { dragSource = new DragSource( sourceControl, style ); dragSource.setTransfer( transfers ); getRemoteObject( dragSource ).setHandler( new DragSourceOperationHandler( dragSource ) ); Fixture.markInitialized( dragSource ); } TransferData getType( Transfer transfer ) { return transfer.getSupportedTypes()[ 0 ]; } private int getTextType() { return getType( TextTransfer.getInstance()).type; } private void addLogger( DragSource dragSource ) { dragSource.addDragListener( new DragSourceListener() { public void dragStart( DragSourceEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.DragStart ) ); } public void dragSetData( DragSourceEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.DragSetData ) ); } public void dragFinished( DragSourceEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.DragEnd ) ); } } ); } private void addLogger( DropTarget dropTarget ) { dropTarget.addDropListener( new LoggingDropTargetListener() ); } private int[] getEventOrder() { int[] result = new int[ eventTypes.size() ]; for( int i = 0; i < result.length; i++ ) { result[ i ] = eventTypes.get( i ).intValue(); } return result; } private void addSetDragDataListener( DragSource dragSource, final Object data ) { dragSource.addDragListener( new DragSourceAdapter() { @Override public void dragSetData( DragSourceEvent event ) { event.data = data; } } ); } private int getEventType( int index ) { return eventTypes.get( index ).intValue(); } private DropTargetEvent getDropTargetEvent( int index ) { return ( DropTargetEvent )events.get( index ); } private DragSourceEvent getDragSourceEvent( int index ) { return ( DragSourceEvent )events.get( index ); } private class LoggingDropTargetListener implements DropTargetListener { public void dragEnter( DropTargetEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.DragEnter ) ); } public void dragLeave( DropTargetEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.DragLeave ) ); } public void dragOperationChanged( DropTargetEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.DragOperationChanged ) ); } public void dragOver( DropTargetEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.DragOver ) ); } public void drop( DropTargetEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.Drop ) ); } public void dropAccept( DropTargetEvent event ) { events.add( event ); eventTypes.add( Integer.valueOf( DND.DropAccept ) ); } } }