From 4c01944af6e46be5bf42025de2e6f07085abfa18 Mon Sep 17 00:00:00 2001 From: duke Date: Wed, 2 Apr 2025 19:41:57 +0000 Subject: [PATCH] Backport 32f817a46068b61d599b714a4480e3ea5d6e9050 --- test/jdk/ProblemList.txt | 1 + .../java/awt/dnd/CustomDragCursorTest.java | 289 ++++++++++++++++++ .../DnDAcceptanceTest/DnDAcceptanceTest.java | 87 ++++++ .../awt/dnd/DnDAcceptanceTest/DnDSource.java | 155 ++++++++++ .../awt/dnd/DnDAcceptanceTest/DnDTarget.java | 115 +++++++ 5 files changed, 647 insertions(+) create mode 100644 test/jdk/java/awt/dnd/CustomDragCursorTest.java create mode 100644 test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java create mode 100644 test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java create mode 100644 test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index fe34cc1935c..226fe932e28 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -129,6 +129,7 @@ java/awt/dnd/MissingEventsOnModalDialog/MissingEventsOnModalDialogTest.java 8164 java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java 8171510 macosx-all java/awt/dnd/DragExitBeforeDropTest.java 8242805 macosx-all java/awt/dnd/DragThresholdTest.java 8076299 macosx-all +java/awt/dnd/CustomDragCursorTest.java 8242805 macosx-all java/awt/Focus/ChoiceFocus/ChoiceFocus.java 8169103 windows-all,macosx-all java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java 8198618 macosx-all java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java 6986252 macosx-all diff --git a/test/jdk/java/awt/dnd/CustomDragCursorTest.java b/test/jdk/java/awt/dnd/CustomDragCursorTest.java new file mode 100644 index 00000000000..9e5e006b31c --- /dev/null +++ b/test/jdk/java/awt/dnd/CustomDragCursorTest.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2001, 2024, 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.Cursor; +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.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/* + * @test + * @bug 4451328 + * @summary tests that a custom drag cursor is not changed + to the default drag cursor + * @key headful + * @run main CustomDragCursorTest + */ + +public class CustomDragCursorTest { + private static Frame frame; + private static final DragSourcePanel dragSourcePanel = new DragSourcePanel(); + private static final DropTargetPanel dropTargetPanel = new DropTargetPanel(); + + private static volatile Point srcPoint; + private static volatile Point dstPoint; + private static volatile boolean passed = true; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + EventQueue.invokeAndWait(CustomDragCursorTest::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point p = dragSourcePanel.getLocationOnScreen(); + Dimension d = dragSourcePanel.getSize(); + p.translate(d.width / 2, d.height / 2); + srcPoint = p; + + p = dropTargetPanel.getLocationOnScreen(); + d = dropTargetPanel.getSize(); + p.translate(d.width / 2, d.height / 2); + dstPoint = p; + }); + + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_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); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(1000); + + if (!passed) { + throw new RuntimeException("Custom drag cursor changed to default."); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new Frame("CustomDragCursorTest"); + frame.setLayout(new GridLayout(2, 1)); + frame.add(dragSourcePanel); + frame.add(dropTargetPanel); + frame.setLocationRelativeTo(null); + frame.setSize(300, 400); + frame.setVisible(true); + } + + public static void failed() { + passed = false; + } + + private static int sign(int n) { + return Integer.compare(n, 0); + } + + private static class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private final DataFlavor dataflavor = + new DataFlavor(Button.class, "DragSourceButton"); + private final Cursor dragCursor = new Cursor(Cursor.HAND_CURSOR); + + 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(dragCursor, this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dragExit(DragSourceEvent dse) { + if (!dragCursor.equals(dse.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dragOver(DragSourceDragEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + if (!dragCursor.equals(dsde.getDragSourceContext().getCursor())) { + CustomDragCursorTest.failed(); + } + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + Object retObj; + + 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); + } + } + + private static class DragSourcePanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DragSourcePanel() { + setLayout(new GridLayout(1, 1)); + add(new DragSourceButton()); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + } + + private static class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 100); + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) {} + + public void dragExit(DropTargetEvent dte) {} + + 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/DnDAcceptanceTest/DnDAcceptanceTest.java b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java new file mode 100644 index 00000000000..700187f9dce --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDAcceptanceTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999, 2024, 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.Color; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Panel; + +/* + * @test + * @bug 4166541 4225247 4297663 + * @summary Tests Basic DnD functionality + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DnDAcceptanceTest + */ + +public class DnDAcceptanceTest { + private static final String INSTRUCTIONS = """ + When test runs a Frame which contains a yellow button labeled + "Drag ME!" and a RED Panel will appear. + + Click on the button and drag to the red panel. + When the mouse enters the red panel + during the drag the panel should turn yellow. + + Release the mouse button, panel should turn red again and + a yellow button labeled Drag ME! should appear inside the panel. + You should be able to repeat this operation multiple times. + + If above is true press PASS, else press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(38) + .testUI(DnDAcceptanceTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame("DnDAcceptanceTest"); + Panel mainPanel; + Component dragSource, dropTarget; + + frame.setSize(400, 400); + frame.setLayout(new BorderLayout()); + + mainPanel = new Panel(); + mainPanel.setLayout(new BorderLayout()); + + mainPanel.setBackground(Color.BLACK); + + dropTarget = new DnDTarget(Color.RED, Color.YELLOW); + dragSource = new DnDSource("Drag ME!"); + + mainPanel.add(dragSource, "North"); + mainPanel.add(dropTarget, "Center"); + frame.add(mainPanel, BorderLayout.CENTER); + frame.setAlwaysOnTop(true); + return frame; + } +} diff --git a/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java new file mode 100644 index 00000000000..a35ccd9ee12 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDSource.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1999, 2024, 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.Color; +import java.awt.Container; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.MouseDragGestureRecognizer; +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.InvalidDnDOperationException; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +class DnDSource extends Button implements Transferable, + DragGestureListener, + DragSourceListener { + private DataFlavor df; + private transient int dropAction; + + DnDSource(String label) { + super(label); + Toolkit.getDefaultToolkit().createDragGestureRecognizer(MouseDragGestureRecognizer.class, + DragSource.getDefaultDragSource(), + this, DnDConstants.ACTION_COPY, this); + setBackground(Color.yellow); + setForeground(Color.blue); + df = new DataFlavor(DnDSource.class, "DnDSource"); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + System.err.println("starting Drag"); + try { + dge.startDrag(null, this, this); + } catch (InvalidDnDOperationException e) { + e.printStackTrace(); + } + } + + public void dragEnter(DragSourceDragEvent dsde) { + System.err.println("[Source] dragEnter"); + dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyDrop); + } + + public void dragOver(DragSourceDragEvent dsde) { + System.err.println("[Source] dragOver"); + dropAction = dsde.getDropAction(); + System.out.println("dropAction = " + dropAction); + } + + public void dragGestureChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dragGestureChanged"); + dropAction = dsde.getDropAction(); + System.out.println("dropAction = " + dropAction); + } + + public void dragExit(DragSourceEvent dsde) { + System.err.println("[Source] dragExit"); + dsde.getDragSourceContext().setCursor(null); + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + System.err.println("[Source] dragDropEnd"); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dropActionChanged"); + dropAction = dsde.getDropAction(); + System.out.println("dropAction = " + dropAction); + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] {df}; + } + + public boolean isDataFlavorSupported(DataFlavor sdf) { + return df.equals(sdf); + } + + public Object getTransferData(DataFlavor tdf) throws UnsupportedFlavorException, IOException { + + Object copy = null; + + if (!df.equals(tdf)) { + throw new UnsupportedFlavorException(tdf); + } + Container parent = getParent(); + switch (dropAction) { + case DnDConstants.ACTION_COPY: + try { + copy = this.clone(); + } catch (CloneNotSupportedException e) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + + oos.writeObject(this); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + try { + copy = ois.readObject(); + } catch (ClassNotFoundException cnfe) { + // do nothing + } + } + + parent.add(this); + return copy; + + case DnDConstants.ACTION_MOVE: + synchronized(this) { + if (parent != null) parent.remove(this); + } + return this; + + case DnDConstants.ACTION_LINK: + return this; + + default: + //throw new IOException("bad operation"); + return this; // workaround for: 4135456 getDropAction() always return 0 + } + } +} diff --git a/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java new file mode 100644 index 00000000000..d147741f0d2 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAcceptanceTest/DnDTarget.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1999, 2024, 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.Color; +import java.awt.Panel; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +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.io.IOException; + +class DnDTarget extends Panel implements DropTargetListener { + Color bgColor; + Color htColor; + + DnDTarget(Color bgColor, Color htColor) { + super(); + this.bgColor = bgColor; + this.htColor = htColor; + setBackground(bgColor); + setDropTarget(new DropTarget(this, this)); + } + + public void dragEnter(DropTargetDragEvent e) { + System.err.println("[Target] dragEnter"); + e.acceptDrag(DnDConstants.ACTION_COPY); + setBackground(htColor); + repaint(); + } + + public void dragOver(DropTargetDragEvent e) { + System.err.println("[Target] dragOver"); + e.acceptDrag(DnDConstants.ACTION_COPY); + } + + public void dragExit(DropTargetEvent e) { + System.err.println("[Target] dragExit"); + setBackground(bgColor); + repaint(); + } + + public void drop(DropTargetDropEvent dtde) { + System.err.println("[Target] drop"); + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + return; + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + if (dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + Object obj; + try { + obj = transfer.getTransferData(dfs[0]); + } catch (IOException | UnsupportedFlavorException ex) { + System.err.println(ex.getMessage()); + dtc.dropComplete(false); + return; + } + + if (obj != null) { + Button button; + try { + button = (Button) obj; + } catch (Exception e) { + System.err.println(e.getMessage()); + dtc.dropComplete(false); + return; + } + add(button); + repaint(); + } + } + setBackground(bgColor); + invalidate(); + validate(); + repaint(); + dtc.dropComplete(true); + } + + public void dropActionChanged(DropTargetDragEvent e) { + System.err.println("[Target] dropActionChanged"); + } +}