From 688a823747d38502505050bf395c5328b291d46c Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Wed, 5 Jul 2023 18:14:36 +0000 Subject: [PATCH] 8307299: Move more DnD tests to open Backport-of: 950c5df859c373864ab4e7cf080c38bbd501e54b --- test/jdk/java/awt/dnd/DropTargetingTest.java | 304 ++++++++++++++ test/jdk/java/awt/dnd/DroppingVMHangTest.java | 367 +++++++++++++++++ .../java/awt/dnd/HonorTargetActionTest.java | 171 ++++++++ test/jdk/java/awt/dnd/InterJVMLinkTest.java | 273 +++++++++++++ .../awt/dnd/IntraJVMGetDropSuccessTest.java | 283 +++++++++++++ test/jdk/java/awt/dnd/LinkAcceptanceTest.java | 382 ++++++++++++++++++ 6 files changed, 1780 insertions(+) create mode 100644 test/jdk/java/awt/dnd/DropTargetingTest.java create mode 100644 test/jdk/java/awt/dnd/DroppingVMHangTest.java create mode 100644 test/jdk/java/awt/dnd/HonorTargetActionTest.java create mode 100644 test/jdk/java/awt/dnd/InterJVMLinkTest.java create mode 100644 test/jdk/java/awt/dnd/IntraJVMGetDropSuccessTest.java create mode 100644 test/jdk/java/awt/dnd/LinkAcceptanceTest.java diff --git a/test/jdk/java/awt/dnd/DropTargetingTest.java b/test/jdk/java/awt/dnd/DropTargetingTest.java new file mode 100644 index 00000000000..047bc11023f --- /dev/null +++ b/test/jdk/java/awt/dnd/DropTargetingTest.java @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JButton; +import javax.swing.JFrame; +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.AWTEventListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; + +/* + @test + @bug 4426794 4435403 + @summary tests that drag notifications are targeted to the drop target + whose operable part is currently intersected by cursor's hotspot + @key headful + @run main DropTargetingTest +*/ + +public class DropTargetingTest implements AWTEventListener { + + volatile JFrame sourceFrame; + volatile JFrame targetFrame1; + volatile JFrame targetFrame2; + volatile JButton obscurer; + + volatile DragSource dragSource; + volatile Transferable transferable; + volatile DragSourceListener dragSourceListener; + volatile DragGestureListener dragGestureListener; + volatile Point srcPoint; + volatile Point dstPoint; + volatile Dimension d; + + static class TestDropTargetListener extends DropTargetAdapter { + private boolean dropRecognized = false; + public void drop(DropTargetDropEvent dtde) { + dropRecognized = true; + dtde.rejectDrop(); + synchronized (SYNC_LOCK) { + SYNC_LOCK.notifyAll(); + } + } + public void reset() { + dropRecognized = false; + } + public boolean dropRecognized() { + return dropRecognized; + } + } + volatile TestDropTargetListener dropTargetListener; + + static final Object SYNC_LOCK = new Object(); + static final int FRAME_ACTIVATION_TIMEOUT = 2000; + static final int DROP_COMPLETION_TIMEOUT = 5000; + static final int MOUSE_RELEASE_TIMEOUT = 1000; + + Component clickedComponent = null; + + public static void main(String[] args) throws Exception { + DropTargetingTest test = new DropTargetingTest(); + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(() -> { + if (test.sourceFrame != null) { + test.sourceFrame.dispose(); + } + if (test.targetFrame1 != null) { + test.targetFrame1.dispose(); + } + if (test.targetFrame2 != null) { + test.targetFrame2.dispose(); + } + }); + } + } + + public void init() { + sourceFrame = new JFrame(); + targetFrame1 = new JFrame(); + targetFrame2 = new JFrame(); + obscurer = new JButton("Obscurer"); + + dragSource = DragSource.getDefaultDragSource(); + transferable = new StringSelection("TEXT"); + dragSourceListener = new DragSourceAdapter() {}; + dragGestureListener = new DragGestureListener() { + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, transferable, dragSourceListener); + } + }; + dropTargetListener = new TestDropTargetListener(); + + sourceFrame.setTitle("DropTargetingTest Source frame"); + sourceFrame.setBounds(100, 100, 100, 100); + sourceFrame.getToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK); + dragSource.createDefaultDragGestureRecognizer(sourceFrame, DnDConstants.ACTION_COPY, + dragGestureListener); + targetFrame1.setTitle("Target frame 1"); + targetFrame1.setBounds(200, 100, 100, 100); + targetFrame1.getGlassPane().setVisible(true); + targetFrame1.getGlassPane().setDropTarget( + new DropTarget(targetFrame1.getGlassPane(), dropTargetListener)); + targetFrame2.setTitle("Target frame 2"); + targetFrame2.setBounds(300, 100, 100, 100); + targetFrame2.setDropTarget(new DropTarget(targetFrame1, dropTargetListener)); + targetFrame2.getContentPane().add(obscurer); + + sourceFrame.setVisible(true); + targetFrame1.setVisible(true); + targetFrame2.setVisible(true); + } + + public static int sign(int n) { + return n < 0 ? -1 : n == 0 ? 0 : 1; + } + + public void start() throws Exception { + Robot robot = new Robot(); + robot.delay(FRAME_ACTIVATION_TIMEOUT); + + if (!test(robot, targetFrame1)) { + throw new RuntimeException("Failed to recognize drop on a glass pane"); + } + + if (!test(robot, targetFrame2)) { + throw new RuntimeException("Failed to recognize drop on a composite component"); + } + } + + public void reset() { + clickedComponent = null; + } + + public void eventDispatched(AWTEvent e) { + if (e.getID() == MouseEvent.MOUSE_RELEASED) { + clickedComponent = (Component)e.getSource(); + synchronized (SYNC_LOCK) { + SYNC_LOCK.notifyAll(); + } + } + } + + boolean pointInComponent(Robot robot, Point p, Component comp) + throws InterruptedException { + robot.waitForIdle(); + reset(); + robot.mouseMove(p.x, p.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + synchronized (SYNC_LOCK) { + robot.mouseRelease(InputEvent.BUTTON1_MASK); + SYNC_LOCK.wait(MOUSE_RELEASE_TIMEOUT); + } + + Component c = clickedComponent; + + while (c != null && c != comp) { + c = c.getParent(); + } + + return c == comp; + } + + boolean test(Robot robot, JFrame targetFrame) throws Exception { + EventQueue.invokeAndWait(() -> { + srcPoint = sourceFrame.getLocationOnScreen(); + d = sourceFrame.getSize(); + }); + srcPoint.translate(d.width / 2, d.height / 2); + + if (!pointInComponent(robot, srcPoint, sourceFrame)) { + System.err.println("WARNING: Couldn't locate source frame."); + return true; + } + EventQueue.invokeAndWait(() -> { + dstPoint = targetFrame.getLocationOnScreen(); + d = targetFrame.getSize(); + }); + dstPoint.translate(d.width / 2, d.height / 2); + + if (!pointInComponent(robot, dstPoint, targetFrame)) { + System.err.println("WARNING: Couldn't locate target frame: " + targetFrame); + return true; + } + + dropTargetListener.reset(); + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_MASK); + for (;!srcPoint.equals(dstPoint); + srcPoint.translate(sign(dstPoint.x - srcPoint.x), + sign(dstPoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.delay(10); + } + synchronized (SYNC_LOCK) { + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + SYNC_LOCK.wait(DROP_COMPLETION_TIMEOUT); + } + + return dropTargetListener.dropRecognized(); + } +} + +class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 100); + boolean testPassed = true; + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public boolean getStatus() { + return testPassed; + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) {} + + public void dragExit(DropTargetEvent dte) { + testPassed = false; + } + + public void dragOver(DropTargetDragEvent dtde) {} + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if (dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component)transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + + add(comp); + } +} diff --git a/test/jdk/java/awt/dnd/DroppingVMHangTest.java b/test/jdk/java/awt/dnd/DroppingVMHangTest.java new file mode 100644 index 00000000000..09aba7a91bf --- /dev/null +++ b/test/jdk/java/awt/dnd/DroppingVMHangTest.java @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/* + @test + @bug 4338893 + @summary tests that dnd between two different VMs doesn't cause hang + on the dropping side. + @key headful + @run main/timeout=120 DroppingVMHangTest +*/ + +public class DroppingVMHangTest { + + public static final int CODE_NOT_RETURNED = -1; + public static final int CODE_OK = 0; + public static final int CODE_FAILURE = 1; + public static final int CODE_HANG_FAILURE = 2; + public static final int CODE_OTHER_FAILURE = 3; + public static final int CODE_TIMEOUT = 4; + + public static final int FRAME_ACTIVATION_TIMEOUT = 2000; + + private int returnCode = CODE_NOT_RETURNED; + + volatile Frame frame; + volatile Point p; + volatile Dimension d; + Robot robot = null; + + public static void main(String[] args) throws Exception { + DroppingVMHangTest test = new DroppingVMHangTest(); + if (args.length > 0) { + test.run(args); + } else { + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(() -> { + if (test.frame != null) { + test.frame.dispose(); + } + }); + } + } + } + + public void run(String[] args) { + try { + frame = new Frame(); + frame.setTitle("DroppingVMHangTest DropTarget frame"); + frame.setLocation(300, 400); + frame.add(new DropTargetPanel()); + frame.pack(); + frame.setVisible(true); + + Thread.sleep(FRAME_ACTIVATION_TIMEOUT); + + if (args.length != 2) { + throw new RuntimeException("Incorrect number of arguments for child:" + + args.length); + } + + int x = Integer.parseInt(args[0], 10); + int y = Integer.parseInt(args[1], 10); + + Point sourcePoint = new Point(x, y); + Point targetPoint = frame.getLocationOnScreen(); + Dimension d = frame.getSize(); + targetPoint.translate(d.width / 2, d.height / 2); + + robot = new Robot(); + robot.mouseMove(x, y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_MASK); + while (!sourcePoint.equals(targetPoint)) { + robot.mouseMove(sourcePoint.x, sourcePoint.y); + Thread.sleep(10); + int dx = sign(targetPoint.x - sourcePoint.x); + int dy = sign(targetPoint.y - sourcePoint.y); + sourcePoint.translate(dx, dy); + } + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + + Thread.sleep(5000); + System.exit(DroppingVMHangTest.CODE_TIMEOUT); + } catch (Throwable e) { + e.printStackTrace(); + System.exit(DroppingVMHangTest.CODE_OTHER_FAILURE); + } + } + + static int sign(int n) { + return n > 0 ? 1 : n < 0 ? -1 : 0; + } + + public void init() { + frame = new Frame(); + frame.setTitle("DragSource frame"); + frame.setLocation(10, 200); + frame.add(new DragSourcePanel()); + + frame.pack(); + frame.setVisible(true); + } + + public void start() throws Exception { + Thread.sleep(FRAME_ACTIVATION_TIMEOUT); + + EventQueue.invokeAndWait(() -> { + p = frame.getLocationOnScreen(); + d = frame.getSize(); + }); + + p.translate(d.width / 2, d.height / 2); + + String javaPath = System.getProperty("java.home", ""); + String command = javaPath + File.separator + "bin" + + File.separator + "java -cp " + System.getProperty("test.classes", ".") + + " DroppingVMHangTest" + " " + p.x + " " + p.y; + Process process = Runtime.getRuntime().exec(command); + returnCode = process.waitFor(); + + InputStream errorStream = process.getErrorStream(); + int count = errorStream.available(); + if (count > 0) { + byte[] b = new byte[count]; + errorStream.read(b); + System.err.println("========= Child VM System.err ========"); + System.err.print(new String(b)); + System.err.println("======================================"); + } + + switch (returnCode) { + case CODE_NOT_RETURNED: + System.err.println("Child VM: failed to start"); + break; + case CODE_OK: + System.err.println("Child VM: normal termination"); + break; + case CODE_FAILURE: + System.err.println("Child VM: abnormal termination"); + break; + case CODE_HANG_FAILURE: + System.err.println("Child VM: hang on drop"); + break; + case CODE_OTHER_FAILURE: + System.err.println("Child VM: other failure"); + break; + case CODE_TIMEOUT: + System.err.println("Child VM: failed to simulate drag-and-drop operation with Robot"); + break; + } + if (returnCode != CODE_OK && returnCode != CODE_TIMEOUT) { + throw new RuntimeException("The test failed."); + } + } +} + +class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private transient final DataFlavor dataflavor = + new DataFlavor(DragSourceButton.class, "DragSourceButton"); + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) {} + + public void dragExit(DragSourceEvent dse) {} + + public void dragOver(DragSourceDragEvent dsde) {} + + public void dragDropEnd(DragSourceDropEvent dsde) {} + + public void dropActionChanged(DragSourceDragEvent dsde) {} + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + Object retObj = null; + + ByteArrayOutputStream baoStream = new ByteArrayOutputStream(); + ObjectOutputStream ooStream = new ObjectOutputStream(baoStream); + ooStream.writeObject(this); + + ByteArrayInputStream baiStream = new ByteArrayInputStream(baoStream.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(baiStream); + try { + retObj = ois.readObject(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e.toString()); + } + + return retObj; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { dataflavor }; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } +} + +class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 200); + + public DragSourcePanel() { + setLayout(new GridLayout(1, 1)); + add(new DragSourceButton()); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } +} + +class DropTargetPanel extends Panel implements DropTargetListener, + Runnable { + + final Dimension preferredDimension = new Dimension(200, 200); + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + } + + public void dragExit(DropTargetEvent dte) {} + + public void dragOver(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + } + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + System.exit(DroppingVMHangTest.CODE_OTHER_FAILURE); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if (dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component)transfer.getTransferData(dfs[0]); + comp.getClass(); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + System.exit(DroppingVMHangTest.CODE_OTHER_FAILURE); + } + } + dtc.dropComplete(true); + + Thread thread = new Thread(this); + thread.start(); + + add(comp); + + System.exit(DroppingVMHangTest.CODE_OK); + } + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public void run() { + try { + Thread.sleep(60000); + } catch (InterruptedException e) { + } + Runtime.getRuntime().halt(DroppingVMHangTest.CODE_HANG_FAILURE); + } +} diff --git a/test/jdk/java/awt/dnd/HonorTargetActionTest.java b/test/jdk/java/awt/dnd/HonorTargetActionTest.java new file mode 100644 index 00000000000..94a48dedce5 --- /dev/null +++ b/test/jdk/java/awt/dnd/HonorTargetActionTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.StringSelection; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.event.InputEvent; + +/* + @test + @bug 4869264 + @summary tests that DragSourceDragEvent.getDropAction() accords to its new spec + (does not depend on the user drop action) + @key headful + @run main/othervm HonorTargetActionTest +*/ + +public class HonorTargetActionTest extends Frame { + + private static final int FRAME_ACTIVATION_TIMEOUT = 3000; + + private boolean dragOverCalled; + private int dropAction; + + volatile Frame frame; + volatile Point startPoint; + volatile Point endPoint; + + public static void main(String[] args) throws Exception { + HonorTargetActionTest test = new HonorTargetActionTest(); + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(() -> { + if (test.frame != null) { + test.frame.dispose(); + } + }); + } + } + + public void init() { + DragSourceListener dragSourceListener = new DragSourceAdapter() { + public void dragOver(DragSourceDragEvent dsde) { + dragOverCalled = true; + dropAction = dsde.getDropAction(); + } + }; + + DragGestureListener dragGestureListener = new DragGestureListener() { + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, new StringSelection("OOKK"), dragSourceListener); + } + }; + + new DragSource().createDefaultDragGestureRecognizer(frame, + DnDConstants.ACTION_COPY_OR_MOVE, dragGestureListener); + + + DropTargetAdapter dropTargetListener = new DropTargetAdapter() { + public void dragEnter(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + } + + public void dragOver(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + } + + public void drop(DropTargetDropEvent dtde) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } + }; + + new DropTarget(frame, dropTargetListener); + + dragOverCalled = false; + dropAction = 0; + frame = new Frame("Drag Test Frame"); + + setTitle("HonorTargetActionTest"); + setSize (200,200); + setLayout (new BorderLayout()); + setVisible(true); + validate(); + + frame.setBounds(100, 100, 200, 200); + frame.setVisible(true); + } + + + public void start() throws Exception { + Robot robot = new Robot(); + robot.waitForIdle(); + + Thread.sleep(FRAME_ACTIVATION_TIMEOUT); + + EventQueue.invokeAndWait(() -> { + startPoint = frame.getLocationOnScreen(); + }); + endPoint = new Point(startPoint); + robot.waitForIdle(); + + startPoint.translate(50, 50); + endPoint.translate(150, 150); + + robot.mouseMove(startPoint.x, startPoint.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + for (Point p = new Point(startPoint); !p.equals(endPoint); + p.translate(sign(endPoint.x - p.x), + sign(endPoint.y - p.y))) { + robot.mouseMove(p.x, p.y); + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + robot.mouseRelease(InputEvent.BUTTON1_MASK); + + boolean failed = dragOverCalled && dropAction != DnDConstants.ACTION_COPY; + + if (failed) { + throw new RuntimeException("test failed: dropAction=" + dropAction); + } else { + System.err.println("test passed"); + } + + } + + + public static int sign(int n) { + return n < 0 ? -1 : n == 0 ? 0 : 1; + } + +} diff --git a/test/jdk/java/awt/dnd/InterJVMLinkTest.java b/test/jdk/java/awt/dnd/InterJVMLinkTest.java new file mode 100644 index 00000000000..1ef9644c712 --- /dev/null +++ b/test/jdk/java/awt/dnd/InterJVMLinkTest.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.io.File; +import java.io.InputStream; +import java.io.Serializable; + +/* + @test + @bug 4492640 + @summary tests that inter-JVM dnd works properly for ACTION_LINK + @key headful + @run main InterJVMLinkTest +*/ + +public class InterJVMLinkTest { + + public static final int CODE_NOT_RETURNED = -1; + public static final int CODE_OK = 0; + public static final int CODE_FAILURE = 1; + public static final int FRAME_ACTIVATION_TIMEOUT = 2000; + public static final int DROP_TIMEOUT = 60000; + + private int returnCode = CODE_NOT_RETURNED; + + volatile Frame frame; + volatile DropTargetPanel panel; + volatile Robot robot = null; + volatile Point p; + volatile Dimension d; + + public static void main(String[] args) throws Exception { + InterJVMLinkTest test = new InterJVMLinkTest(); + if (args.length > 0) { + test.run(args); + } else { + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(() -> { + if (test.frame != null) { + test.frame.dispose(); + } + }); + } + } + } + + public void run(String[] args) { + try { + if (args.length != 4) { + throw new RuntimeException("Incorrect command line arguments."); + } + + int x = Integer.parseInt(args[0]); + int y = Integer.parseInt(args[1]); + int w = Integer.parseInt(args[2]); + int h = Integer.parseInt(args[3]); + + DragSourcePanel panel = new DragSourcePanel(); + frame = new Frame(); + + frame.setTitle("DragSource frame"); + frame.setLocation(300, 200); + frame.add(panel); + frame.pack(); + frame.setVisible(true); + + Thread.sleep(FRAME_ACTIVATION_TIMEOUT); + + Point sourcePoint = panel.getLocationOnScreen(); + Dimension d = panel.getSize(); + sourcePoint.translate(d.width / 2, d.height / 2); + + Point targetPoint = new Point(x + w / 2, y + h / 2); + + robot = new Robot(); + robot.mouseMove(sourcePoint.x, sourcePoint.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + for (; !sourcePoint.equals(targetPoint); + sourcePoint.translate(sign(targetPoint.x - sourcePoint.x), + sign(targetPoint.y - sourcePoint.y))) { + robot.mouseMove(sourcePoint.x, sourcePoint.y); + Thread.sleep(50); + } + robot.mouseRelease(InputEvent.BUTTON1_MASK); + + Thread.sleep(DROP_TIMEOUT); + + System.exit(InterJVMLinkTest.CODE_OK); + } catch (Throwable e) { + e.printStackTrace(); + System.exit(InterJVMLinkTest.CODE_FAILURE); + } + } + + public static int sign(int n) { + return n < 0 ? -1 : n == 0 ? 0 : 1; + } + + public void init() { + panel = new DropTargetPanel(); + + frame = new Frame(); + frame.setTitle("InterJVMLinkTest DropTarget frame"); + frame.setLocation(10, 200); + frame.add(panel); + + frame.pack(); + frame.setVisible(true); + } + + public void start() throws Exception { + Thread.sleep(FRAME_ACTIVATION_TIMEOUT); + + EventQueue.invokeAndWait(() -> { + p = panel.getLocationOnScreen(); + d = panel.getSize(); + }); + + String javaPath = System.getProperty("java.home", ""); + String command = javaPath + File.separator + "bin" + + File.separator + "java -cp " + System.getProperty("test.classes", ".") + + " InterJVMLinkTest " + + p.x + " " + p.y + " " + d.width + " " + d.height; + + Process process = Runtime.getRuntime().exec(command); + returnCode = process.waitFor(); + + InputStream errorStream = process.getErrorStream(); + int count = errorStream.available(); + if (count > 0) { + byte[] b = new byte[count]; + errorStream.read(b); + System.err.println("========= Child VM System.err ========"); + System.err.print(new String(b)); + System.err.println("======================================"); + } + + switch (returnCode) { + case CODE_NOT_RETURNED: + System.err.println("Child VM: failed to start"); + break; + case CODE_OK: + System.err.println("Child VM: normal termination"); + break; + case CODE_FAILURE: + System.err.println("Child VM: abnormal termination"); + break; + } + if (panel == null || (panel.isEntered() && !panel.isDropped())) { + throw new RuntimeException("The test failed."); + } + } +} + +class DragSourceButton extends Button implements Serializable, + DragGestureListener { + final Transferable transferable = new StringSelection("TEXT"); + final DragSourceListener dragSourceListener = new DragSourceAdapter() { + public void dragDropEnd(DragSourceDropEvent dsde) { + System.exit(InterJVMLinkTest.CODE_OK); + } + }; + + public DragSourceButton() { + super("DragSourceButton"); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_LINK, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, transferable, dragSourceListener); + } +} + +class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 200); + + public DragSourcePanel() { + setLayout(new GridLayout(1, 1)); + add(new DragSourceButton()); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } +} + +class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 200); + boolean entered = false; + boolean dropped = false; + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, DnDConstants.ACTION_LINK, this)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) { + entered = true; + } + + public void dragExit(DropTargetEvent dte) {} + + public void dragOver(DropTargetDragEvent dtde) {} + + public void drop(DropTargetDropEvent dtde) { + dtde.rejectDrop(); + dropped = true; + } + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public boolean isEntered() { + return entered; + } + + public boolean isDropped() { + return dropped; + } +} diff --git a/test/jdk/java/awt/dnd/IntraJVMGetDropSuccessTest.java b/test/jdk/java/awt/dnd/IntraJVMGetDropSuccessTest.java new file mode 100644 index 00000000000..cbd20962c51 --- /dev/null +++ b/test/jdk/java/awt/dnd/IntraJVMGetDropSuccessTest.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTEvent; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.AWTEventListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; + +/* + @test + @bug 4658741 + @summary verifies that getDropSuccess() returns correct value for intra-JVM DnD + @key headful + @run main IntraJVMGetDropSuccessTest +*/ + +public class IntraJVMGetDropSuccessTest implements AWTEventListener { + + static final Object SYNC_LOCK = new Object(); + static final int FRAME_ACTIVATION_TIMEOUT = 3000; + static final int MOUSE_RELEASE_TIMEOUT = 1000; + + static class DragSourceDropListener extends DragSourceAdapter { + private boolean finished = false; + private boolean dropSuccess = false; + + public void reset() { + finished = false; + dropSuccess = false; + } + + public boolean isDropFinished() { + return finished; + } + + public boolean getDropSuccess() { + return dropSuccess; + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + finished = true; + dropSuccess = dsde.getDropSuccess(); + synchronized (SYNC_LOCK) { + SYNC_LOCK.notifyAll(); + } + } + } + + static class ChildCanvas extends Canvas { + private final Dimension preferredDimension = new Dimension(100, 200); + + public Dimension getPreferredSize() { + return preferredDimension; + } + } + + volatile Frame frame; + volatile Canvas canvas1; + volatile Canvas canvas2; + volatile Canvas canvas3; + volatile Point p; + volatile Dimension d; + volatile Component c; + + volatile DragSourceDropListener dragSourceListener; + volatile DragSource dragSource; + volatile Transferable transferable; + volatile DragGestureListener dragGestureListener; + volatile DragGestureRecognizer dragGestureRecognizer; + volatile DropTargetListener dropTargetListener; + volatile DropTarget dropTarget; + + Component clickedComponent = null; + + public static void main(String[] args) throws Exception { + IntraJVMGetDropSuccessTest test = new IntraJVMGetDropSuccessTest(); + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(() -> { + if (test.frame != null) { + test.frame.dispose(); + } + }); + } + } + + public void init() { + frame = new Frame(); + canvas1 = new ChildCanvas(); + canvas2 = new ChildCanvas(); + canvas3 = new ChildCanvas(); + + dragSourceListener = new DragSourceDropListener(); + dragSource = DragSource.getDefaultDragSource(); + transferable = new StringSelection("TEXT"); + dragGestureListener = new DragGestureListener() { + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, transferable, dragSourceListener); + } + }; + dragGestureRecognizer = + dragSource.createDefaultDragGestureRecognizer(canvas2, DnDConstants.ACTION_COPY, + dragGestureListener); + dropTargetListener = new DropTargetAdapter() { + public void drop(DropTargetDropEvent dtde) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + dtde.dropComplete(true); + } + }; + dropTarget = new DropTarget(canvas3, dropTargetListener); + + + canvas1.setBackground(Color.red); + canvas2.setBackground(Color.yellow); + canvas3.setBackground(Color.green); + + frame.setTitle("IntraJVMGetDropSuccessTest"); + frame.setLocation(100, 100); + frame.setLayout(new GridLayout(1, 3)); + frame.getToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK); + frame.add(canvas1); + frame.add(canvas2); + frame.add(canvas3); + frame.pack(); + + frame.setVisible(true); + } + + public static int sign(int n) { + return n < 0 ? -1 : n == 0 ? 0 : 1; + } + + public void start() throws Exception { + Robot robot = new Robot(); + + robot.delay(FRAME_ACTIVATION_TIMEOUT); + + final Point srcPoint = getCenterLocationOnScreen(canvas2); + + if (!pointInComponent(robot, srcPoint, canvas2)) { + System.err.println("WARNING: Couldn't locate " + canvas2); + return; + } + + final Point dstPoint1 = getCenterLocationOnScreen(canvas1); + + if (!pointInComponent(robot, dstPoint1, canvas1)) { + System.err.println("WARNING: Couldn't locate " + canvas1); + return; + } + + final Point dstPoint2 = getCenterLocationOnScreen(canvas3); + if (!pointInComponent(robot, dstPoint2, canvas3)) { + System.err.println("WARNING: Couldn't locate " + canvas3); + return; + } + + robot.waitForIdle(); + test(robot, srcPoint, dstPoint1, false); + test(robot, srcPoint, dstPoint2, true); + test(robot, srcPoint, dstPoint1, false); + } + + public Point getCenterLocationOnScreen(Component c) throws Exception { + EventQueue.invokeAndWait(() -> { + p = c.getLocationOnScreen(); + d = c.getSize(); + }); + p.translate(d.width / 2, d.height / 2); + return p; + } + + public void test(Robot robot, Point src, Point dst, boolean success) + throws InterruptedException { + + dragSourceListener.reset(); + robot.mouseMove(src.x, src.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + + for (Point p = new Point(src); !p.equals(dst); + p.translate(sign(dst.x - p.x), + sign(dst.y - p.y))) { + robot.mouseMove(p.x, p.y); + robot.delay(50); + } + + synchronized (SYNC_LOCK) { + robot.mouseRelease(InputEvent.BUTTON1_MASK); + SYNC_LOCK.wait(); + } + + if (!dragSourceListener.isDropFinished()) { + throw new RuntimeException("Drop not finished"); + } + + if (dragSourceListener.getDropSuccess() != success) { + throw new RuntimeException("getDropSuccess() returned wrong value:" + + dragSourceListener.getDropSuccess()); + } + } + + public void reset() throws Exception { + EventQueue.invokeAndWait(() -> { + clickedComponent = null; + }); + + } + + public void eventDispatched(AWTEvent e) { + if (e.getID() == MouseEvent.MOUSE_RELEASED) { + clickedComponent = (Component)e.getSource(); + synchronized (SYNC_LOCK) { + SYNC_LOCK.notifyAll(); + } + } + } + + boolean pointInComponent(Robot robot, Point p, Component comp) + throws Exception { + robot.waitForIdle(); + reset(); + robot.mouseMove(p.x, p.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + synchronized (SYNC_LOCK) { + robot.mouseRelease(InputEvent.BUTTON1_MASK); + SYNC_LOCK.wait(MOUSE_RELEASE_TIMEOUT); + } + + EventQueue.invokeAndWait(() -> { + c = clickedComponent; + + while (c != null && c != comp) { + c = c.getParent(); + } + }); + + return c == comp; + } +} diff --git a/test/jdk/java/awt/dnd/LinkAcceptanceTest.java b/test/jdk/java/awt/dnd/LinkAcceptanceTest.java new file mode 100644 index 00000000000..2dca3ebdd33 --- /dev/null +++ b/test/jdk/java/awt/dnd/LinkAcceptanceTest.java @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.File; +import java.io.InputStream; +import java.io.Serializable; +import java.net.URL; + +/* + @test + @bug 4416788 + @summary Tests that URL can be recognized by a java drop target + @requires (os.family == "windows") + @key headful + @run main LinkAcceptanceTest +*/ + +public class LinkAcceptanceTest { + + public static final int CODE_NOT_RETURNED = -1; + public static final int CODE_OK = 0; + public static final int CODE_FAILURE = 1; + public static final int FRAME_ACTIVATION_TIMEOUT = 2000; + public static final int DROP_TIMEOUT = 12000; + public static final int DROP_COMPLETION_TIMEOUT = 4000; + + private int returnCode = CODE_NOT_RETURNED; + + volatile Frame frame; + volatile Robot robot; + volatile Panel panel; + volatile Point p; + volatile Dimension d; + + public static void main(String[] args) throws Exception { + LinkAcceptanceTest test = new LinkAcceptanceTest(); + if (args.length > 0) { + test.run(args); + } else { + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(() -> { + if (test.frame != null) { + test.frame.dispose(); + } + }); + } + } + } + + public void run(String[] args) { + try { + if (args.length != 4) { + throw new RuntimeException("Incorrect command line arguments."); + } + + int x = Integer.parseInt(args[0]); + int y = Integer.parseInt(args[1]); + int w = Integer.parseInt(args[2]); + int h = Integer.parseInt(args[3]); + + TransferableURL t = new TransferableURL(); + panel = new DragSourcePanel(t); + + frame = new Frame(); + frame.setTitle("LinkAcceptanceTest DragSource frame"); + frame.setLocation(300, 200); + frame.add(panel); + frame.pack(); + frame.setVisible(true); + + Thread.sleep(FRAME_ACTIVATION_TIMEOUT); + + Point sourcePoint = panel.getLocationOnScreen(); + Dimension d = panel.getSize(); + sourcePoint.translate(d.width / 2, d.height / 2); + + Point targetPoint = new Point(x + w / 2, y + h / 2); + + robot = new Robot(); + robot.mouseMove(sourcePoint.x, sourcePoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_MASK); + for (; !sourcePoint.equals(targetPoint); + sourcePoint.translate(sign(targetPoint.x - sourcePoint.x), + sign(targetPoint.y - sourcePoint.y))) { + robot.mouseMove(sourcePoint.x, sourcePoint.y); + Thread.sleep(10); + } + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + + synchronized (t) { + t.wait(DROP_TIMEOUT); + } + + Thread.sleep(DROP_COMPLETION_TIMEOUT); + + } catch (Throwable e) { + e.printStackTrace(); + System.exit(LinkAcceptanceTest.CODE_FAILURE); + } + + System.exit(LinkAcceptanceTest.CODE_OK); + } + + public static int sign(int n) { + return n < 0 ? -1 : n == 0 ? 0 : 1; + } + + public void init() { + panel = new DropTargetPanel(); + + frame = new Frame(); + frame.setTitle("DropTarget frame"); + frame.setLocation(10, 200); + frame.add(panel); + + frame.pack(); + frame.setVisible(true); + } + + public void start() { + try { + Thread.sleep(FRAME_ACTIVATION_TIMEOUT); + + EventQueue.invokeAndWait(() -> { + p = panel.getLocationOnScreen(); + d = panel.getSize(); + }); + + String javaPath = System.getProperty("java.home", ""); + String command = javaPath + File.separator + "bin" + + File.separator + "java -cp " + System.getProperty("test.classes", ".") + + " LinkAcceptanceTest " + + p.x + " " + p.y + " " + d.width + " " + d.height; + Process process = Runtime.getRuntime().exec(command); + returnCode = process.waitFor(); + InputStream errorStream = process.getErrorStream(); + int count = errorStream.available(); + if (count > 0) { + byte[] b = new byte[count]; + errorStream.read(b); + System.err.println("========= Child VM System.err ========"); + System.err.print(new String(b)); + System.err.println("======================================"); + } + + } catch (Throwable e) { + e.printStackTrace(); + } + switch (returnCode) { + case CODE_NOT_RETURNED: + System.err.println("Child VM: failed to start"); + break; + case CODE_OK: + System.err.println("Child VM: normal termination"); + break; + case CODE_FAILURE: + System.err.println("Child VM: abnormal termination"); + break; + } + if (returnCode != CODE_OK) { + throw new RuntimeException("The test failed."); + } + } +} + +class TransferableURL implements Transferable { + + public static String URL_STRING = "http://java.sun.com"; + public static final int NUM_DATA_FLAVORS = 3; + static DataFlavor[] supportedFlavors = new DataFlavor[NUM_DATA_FLAVORS]; + + static String[] flavorList = { "application/x-java-url;class=java.net.URL", + "text/uri-list;class=java.lang.String", + "text/plain;class=java.lang.String" }; + static { + try { + for (int i = 0; i < NUM_DATA_FLAVORS; i++) { + supportedFlavors[i] = new DataFlavor(flavorList[i]); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException("Failed to construct the flavor"); + } + } + + public DataFlavor[] getTransferDataFlavors() { + return supportedFlavors; + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + + for (int i = 0; i < NUM_DATA_FLAVORS; i++) { + if (flavor.equals(supportedFlavors[i])) { + return true; + } + } + return false; + } + + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + return new String(URL_STRING); + } +} + +class DragSourceLabel extends Label implements Serializable, + DragGestureListener, + DragSourceListener { + + final Transferable transferable; + + public DragSourceLabel(Transferable t) { + super(TransferableURL.URL_STRING); + + this.transferable = t; + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_LINK, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, transferable, this); + } + + public void dragEnter(DragSourceDragEvent dsde) {} + + public void dragExit(DragSourceEvent dse) {} + + public void dragOver(DragSourceDragEvent dsde) {} + + public void dragDropEnd(DragSourceDropEvent dsde) {} + + public void dropActionChanged(DragSourceDragEvent dsde) {} +} + + +class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 200); + + public DragSourcePanel(Transferable t) { + setLayout(new GridLayout(1, 1)); + add(new DragSourceLabel(t)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } +} + +class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 200); + + public DropTargetPanel() { + setBackground(Color.green); + setDropTarget(new DropTarget(this, this)); + setLayout(new GridLayout(1, 1)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_LINK); + } + + public void dragExit(DropTargetEvent dte) {} + + public void dragOver(DropTargetDragEvent dtde) { + dtde.acceptDrag(DnDConstants.ACTION_LINK); + } + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_LINK) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_LINK); + } else { + dtde.rejectDrop(); + return; + } + + removeAll(); + final List list = new List(); + add(list); + + Transferable t = dtde.getTransferable(); + DataFlavor[] dfs = t.getTransferDataFlavors(); + + for (int i = 0; i < dfs.length; i++) { + + DataFlavor flavor = dfs[i]; + String transferText = null; + URL transferURL = null; + + if (flavor.getRepresentationClass().equals(URL.class)) { + try { + transferURL = (URL)t.getTransferData(flavor); + } catch (Exception e) { + throw new RuntimeException("The test failed: unable to recognize " + + flavor.getMimeType()); + } + list.add(transferURL + ":" + flavor.getMimeType()); + } + + if (flavor.getRepresentationClass().equals(String.class)) { + try { + transferText = (String)t.getTransferData(flavor); + } catch (Exception e) { + throw new RuntimeException("The test failed: unable to recognize " + + flavor.getMimeType()); + } + list.add(transferText + ":" + flavor.getMimeType()); + } + } + + dtc.dropComplete(true); + validate(); + } + + public void dropActionChanged(DropTargetDragEvent dtde) {} + +}