/******************************************************************************* * Copyright (c) 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.dnd.droptargetkit; import static org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil.getId; import static org.eclipse.swt.internal.dnd.DNDUtil.getDetailChangedValue; import static org.eclipse.swt.internal.dnd.DNDUtil.hasDataTypeChanged; import static org.eclipse.swt.internal.dnd.DNDUtil.hasDetailChanged; import static org.eclipse.swt.internal.dnd.DNDUtil.hasFeedbackChanged; import static org.eclipse.swt.internal.dnd.droptargetkit.DropTargetOperationHandler.determineDataTypes; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.rap.json.JsonObject; import org.eclipse.rap.rwt.dnd.ClientFileTransfer; import org.eclipse.rap.rwt.internal.client.ClientFileImpl; import org.eclipse.rap.rwt.internal.lifecycle.PhaseId; import org.eclipse.rap.rwt.testfixture.internal.Fixture; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSource; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.DropTargetEvent; 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.internal.dnd.DNDEvent; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; public class DropTargetOperationHandler_Test { private Table sourceControl; private Item item; private DragSource dragSource; private Control targetControl; private DropTarget dropTarget; private DropTargetOperationHandler handler; private Transfer[] transfers; @Before public void setUp() { Fixture.setUp(); Display display = new Display(); Shell shell = new Shell( display, SWT.NONE ); transfers = new Transfer[] { HTMLTransfer.getInstance(), TextTransfer.getInstance() }; sourceControl = new Table( shell, SWT.NONE ); item = new TableItem( sourceControl, SWT.NONE ); dragSource = spy( new DragSource( sourceControl, DND.DROP_MOVE | DND.DROP_COPY ) ); dragSource.setTransfer( transfers ); sourceControl.setData( DND.DRAG_SOURCE_KEY, dragSource ); targetControl = new Label( shell, SWT.NONE ); dropTarget = spy( new DropTarget( targetControl, DND.DROP_MOVE | DND.DROP_COPY ) ); dropTarget.setTransfer( transfers ); handler = new DropTargetOperationHandler( dropTarget ); Fixture.fakePhase( PhaseId.PROCESS_ACTION ); } @After public void tearDown() { Fixture.tearDown(); } @Test public void testHandleNotifyDragEnter_notifiesListeners() { JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "feedback", DND.FEEDBACK_INSERT_AFTER ) .add( "item", getId( item ) ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DragEnter", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.DragEnter ), captor.capture() ); DNDEvent event = captor.getValue(); assertEquals( 10, event.x ); assertEquals( 20, event.y ); assertEquals( 3, event.time ); assertEquals( DND.DROP_MOVE, event.detail ); assertEquals( DND.FEEDBACK_INSERT_AFTER, event.feedback ); assertEquals( DND.DROP_MOVE | DND.DROP_COPY, event.operations ); assertSame( item, event.item ); assertEquals( 2, event.dataTypes.length ); assertEquals( getHTMLTransferDataType(), event.dataType.type ); } @Test public void testHandleNotifyDragEnter_notifiesListeners_nullItem() { JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "feedback", DND.FEEDBACK_INSERT_AFTER ) .add( "item", JsonObject.NULL ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DragEnter", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.DragEnter ), captor.capture() ); DNDEvent event = captor.getValue(); assertNull( event.item ); } @Test public void testHandleNotifyDragEnter_alwaysSetsDataTypeField() { JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "feedback", DND.FEEDBACK_INSERT_AFTER ) .add( "item", JsonObject.NULL ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DragEnter", properties ); assertTrue( hasDataTypeChanged() ); } @Test public void testHandleNotifyDragEnter_setsChangedEventFields() { dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragEnter( DropTargetEvent event ) { event.feedback = DND.FEEDBACK_INSERT_BEFORE; event.detail = DND.DROP_COPY; } } ); JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "feedback", DND.FEEDBACK_INSERT_AFTER ) .add( "item", JsonObject.NULL ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DragEnter", properties ); assertTrue( hasFeedbackChanged() ); assertTrue( hasDetailChanged() ); assertTrue( hasDataTypeChanged() ); } @Test public void testHandleNotifyDragOperationChanged_notifiesListeners() { JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "feedback", DND.FEEDBACK_INSERT_AFTER ) .add( "dataType", 123 ) .add( "item", getId( item ) ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DragOperationChanged", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.DragOperationChanged ), captor.capture() ); DNDEvent event = captor.getValue(); assertEquals( 10, event.x ); assertEquals( 20, event.y ); assertEquals( 3, event.time ); assertEquals( DND.DROP_MOVE, event.detail ); assertEquals( DND.FEEDBACK_INSERT_AFTER, event.feedback ); assertEquals( DND.DROP_MOVE | DND.DROP_COPY, event.operations ); assertSame( item, event.item ); assertEquals( 2, event.dataTypes.length ); assertEquals( 123, event.dataType.type ); } @Test public void testHandleNotifyDragOperationChanged_setsChangedEventFields() { dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragOperationChanged( DropTargetEvent event ) { event.feedback = DND.FEEDBACK_INSERT_BEFORE; event.detail = DND.DROP_COPY; event.currentDataType = new TransferData(); event.currentDataType.type = getTextTransferDataType(); } } ); JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "feedback", DND.FEEDBACK_INSERT_AFTER ) .add( "item", JsonObject.NULL ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DragOperationChanged", properties ); assertTrue( hasFeedbackChanged() ); assertTrue( hasDetailChanged() ); assertTrue( hasDataTypeChanged() ); } @Test public void testHandleNotifyDragOver_notifiesListeners() { JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "feedback", DND.FEEDBACK_INSERT_AFTER ) .add( "dataType", 123 ) .add( "item", getId( item ) ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DragOver", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.DragOver ), captor.capture() ); DNDEvent event = captor.getValue(); assertEquals( 10, event.x ); assertEquals( 20, event.y ); assertEquals( 3, event.time ); assertEquals( DND.DROP_MOVE, event.detail ); assertEquals( DND.FEEDBACK_INSERT_AFTER, event.feedback ); assertEquals( DND.DROP_MOVE | DND.DROP_COPY, event.operations ); assertSame( item, event.item ); assertEquals( 2, event.dataTypes.length ); assertEquals( 123, event.dataType.type ); } @Test public void testHandleNotifyDragOver_setsChangedEventFields() { dropTarget.addDropListener( new DropTargetAdapter() { @Override public void dragOver( DropTargetEvent event ) { event.feedback = DND.FEEDBACK_INSERT_BEFORE; event.detail = DND.DROP_COPY; event.currentDataType = new TransferData(); event.currentDataType.type = getTextTransferDataType(); } } ); JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "feedback", DND.FEEDBACK_INSERT_AFTER ) .add( "item", JsonObject.NULL ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DragOver", properties ); assertTrue( hasFeedbackChanged() ); assertTrue( hasDetailChanged() ); assertTrue( hasDataTypeChanged() ); } @Test public void testHandleNotifyDragLeave_notifiesListeners() { JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ); handler.handleNotify( "DragLeave", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.DragLeave ), captor.capture() ); DNDEvent event = captor.getValue(); assertEquals( 10, event.x ); assertEquals( 20, event.y ); assertEquals( 3, event.time ); assertEquals( DND.DROP_MOVE, event.detail ); } @Test public void testHandleNotifyDragAccept_notifiesListeners() { JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "dataType", 123 ) .add( "item", getId( item ) ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DropAccept", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.DropAccept ), captor.capture() ); DNDEvent event = captor.getValue(); assertEquals( 10, event.x ); assertEquals( 20, event.y ); assertEquals( 3, event.time ); assertEquals( DND.DROP_MOVE, event.detail ); assertEquals( DND.DROP_MOVE | DND.DROP_COPY, event.operations ); assertSame( item, event.item ); assertEquals( 123, event.dataType.type ); } @Test public void testHandleNotifyDragAccept_notifiesDragLeaveListeners() { JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "dataType", 123 ) .add( "item", getId( item ) ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DropAccept", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.DragLeave ), captor.capture() ); DNDEvent event = captor.getValue(); assertEquals( 10, event.x ); assertEquals( 20, event.y ); assertEquals( 3, event.time ); assertEquals( DND.DROP_MOVE, event.detail ); } @Test public void testHandleNotifyDragAccept_notifiesDragSetDataListeners() { final AtomicReference<Event> eventRef = new AtomicReference<Event>(); dragSource.addListener( DND.DragSetData, new Listener() { public void handleEvent( Event event ) { event.data = "some html"; eventRef.set( event ); } } ); JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "dataType", getHTMLTransferDataType() ) .add( "item", getId( item ) ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DropAccept", properties ); Event event = eventRef.get(); assertEquals( 10, event.x ); assertEquals( 20, event.y ); assertEquals( "some html", event.data ); } @Test public void testHandleNotifyDragAccept_notifiesDropListeners() { dragSource.addListener( DND.DragSetData, new Listener() { public void handleEvent( Event event ) { event.data = "some html"; } } ); JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "dataType", getHTMLTransferDataType() ) .add( "item", getId( item ) ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DropAccept", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.Drop ), captor.capture() ); DNDEvent event = captor.getValue(); assertEquals( 10, event.x ); assertEquals( 20, event.y ); assertEquals( DND.DROP_MOVE, event.detail ); assertEquals( DND.DROP_MOVE | DND.DROP_COPY, event.operations ); assertSame( item, event.item ); assertEquals( getHTMLTransferDataType(), event.dataType.type ); assertEquals( "some html", event.data ); } @Test public void testHandleNotifyDragAccept_setsDetailField() { dragSource.addListener( DND.DragSetData, new Listener() { public void handleEvent( Event event ) { event.data = "some html"; } } ); dropTarget.addListener( DND.Drop, new Listener() { public void handleEvent( Event event ) { event.detail = 123; } } ); JsonObject properties = new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "dataType", getHTMLTransferDataType() ) .add( "item", getId( item ) ) .add( "source", getId( sourceControl ) ); handler.handleNotify( "DropAccept", properties ); assertEquals( 123, getDetailChangedValue() ); } @Test public void testHandleNotifyDragAccept_filesPropertySetsClientFileTransfer() { JsonObject properties = createFileDropProperties(); handler.handleNotify( "DropAccept", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.DropAccept ), captor.capture() ); assertTrue( ClientFileTransfer.getInstance().isSupportedType( captor.getValue().dataType ) ); } @Test public void testHandleNotifyDragAccept_filesPropertyPreventsDragLeave() { JsonObject properties = createFileDropProperties(); handler.handleNotify( "DropAccept", properties ); verify( dropTarget, never() ).notifyListeners( eq( DND.DragLeave ), any( DNDEvent.class ) ); } @Test public void testHandleNotifyDragAccept_filesPropertyIsConvertedToClientFiles() { dropTarget.setTransfer( new Transfer[]{ ClientFileTransfer.getInstance() } ); JsonObject properties = createFileDropProperties(); handler.handleNotify( "DropAccept", properties ); ArgumentCaptor<DNDEvent> captor = ArgumentCaptor.forClass( DNDEvent.class ); verify( dropTarget ).notifyListeners( eq( DND.Drop ), captor.capture() ); ClientFileImpl[] remoteFiles = ( ClientFileImpl[] )captor.getValue().data; assertEquals( 2, remoteFiles.length ); assertEquals( "f1", remoteFiles[ 0 ].getFileId() ); assertEquals( "foo.txt", remoteFiles[ 0 ].getName() ); assertEquals( "text/plain", remoteFiles[ 0 ].getType() ); assertEquals( 9000, remoteFiles[ 0 ].getSize() ); assertEquals( "f2", remoteFiles[ 1 ].getFileId() ); assertEquals( "bar.html", remoteFiles[ 1 ].getName() ); assertEquals( "text/html", remoteFiles[ 1 ].getType() ); assertEquals( 100000000000L, remoteFiles[ 1 ].getSize() ); } private JsonObject createFileDropProperties() { JsonObject file1 = new JsonObject() .add( "name", "foo.txt" ) .add( "type", "text/plain" ) .add( "size", 9000 ); JsonObject file2 = new JsonObject() .add( "name", "bar.html" ) .add( "type", "text/html" ) .add( "size", 100000000000L ); return new JsonObject() .add( "x", 10 ) .add( "y", 20 ) .add( "time", 3 ) .add( "operation", "move" ) .add( "files", new JsonObject().add( "f1", file1 ).add( "f2", file2 ) ); } @Test public void testDetermineDataType() { dropTarget.setTransfer( new Transfer[]{ RTFTransfer.getInstance(), HTMLTransfer.getInstance() } ); TransferData[] dataTypes = determineDataTypes( dragSource, dropTarget ); assertEquals( 1, dataTypes.length ); assertTrue( HTMLTransfer.getInstance().isSupportedType( dataTypes[ 0 ] ) ); } @Test public void testDetermineDataType_withoutDragSource() { dropTarget.setTransfer( new Transfer[]{ RTFTransfer.getInstance(), HTMLTransfer.getInstance() } ); TransferData[] dataTypes = determineDataTypes( null, dropTarget ); assertEquals( 2, dataTypes.length ); assertTrue( RTFTransfer.getInstance().isSupportedType( dataTypes[ 0 ] ) ); assertTrue( HTMLTransfer.getInstance().isSupportedType( dataTypes[ 1 ] ) ); } private static int getHTMLTransferDataType() { return "html".hashCode(); } private static int getTextTransferDataType() { return "text".hashCode(); } }