1/*
2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24import java.awt.Dialog;
25import java.awt.Frame;
26import java.awt.Point;
27import java.awt.Robot;
28import java.awt.Window;
29import java.awt.datatransfer.DataFlavor;
30import java.awt.datatransfer.Transferable;
31import java.awt.dnd.DnDConstants;
32import java.awt.dnd.DragGestureEvent;
33import java.awt.dnd.DragGestureListener;
34import java.awt.dnd.DragSource;
35import java.awt.dnd.DropTarget;
36import java.awt.dnd.DropTargetDragEvent;
37import java.awt.dnd.DropTargetDropEvent;
38import java.awt.dnd.DropTargetEvent;
39import java.awt.dnd.DropTargetListener;
40import java.awt.event.InputEvent;
41import java.awt.event.MouseAdapter;
42import java.awt.event.MouseEvent;
43
44/*
45 * @test
46 * @key headful
47 * @bug 8134917
48 * @summary [macosx] JOptionPane doesn't receive mouse events when opened from a drop event
49 * @author Alexandr Scherbatiy
50 */
51public class MissingEventsOnModalDialogTest {
52
53    private static volatile boolean passed = false;
54
55    public static void main(String[] args) throws Exception {
56        Frame sourceFrame = createFrame("Source Frame", 0, 0);
57        Frame targetFrame = createFrame("Target Frame", 250, 250);
58
59        DragSource defaultDragSource
60                = DragSource.getDefaultDragSource();
61        defaultDragSource.createDefaultDragGestureRecognizer(sourceFrame,
62                DnDConstants.ACTION_COPY_OR_MOVE,
63                new TestDragGestureListener());
64        new DropTarget(targetFrame, DnDConstants.ACTION_COPY_OR_MOVE,
65                new TestDropTargetListener(targetFrame));
66
67        Robot robot = new Robot();
68        robot.setAutoDelay(50);
69
70        sourceFrame.toFront();
71        robot.waitForIdle();
72
73        Point point = getCenterPoint(sourceFrame);
74        robot.mouseMove(point.x, point.y);
75        robot.waitForIdle();
76
77        mouseDragAndDrop(robot, point, getCenterPoint(targetFrame));
78
79        long time = System.currentTimeMillis() + 1000;
80
81        while (!passed) {
82            if (time < System.currentTimeMillis()) {
83                sourceFrame.dispose();
84                targetFrame.dispose();
85                throw new RuntimeException("Mouse clicked event is lost!");
86            }
87            Thread.sleep(10);
88        }
89        sourceFrame.dispose();
90        targetFrame.dispose();
91    }
92
93    private static Frame createFrame(String title, int x, int y) {
94        Frame frame = new Frame();
95        frame.setSize(200, 200);
96        frame.setLocation(x, y);
97        frame.setTitle(title);
98        frame.setVisible(true);
99        return frame;
100    }
101
102    private static Point getCenterPoint(Window window) {
103        Point centerPoint = window.getLocationOnScreen();
104        centerPoint.translate(window.getWidth() / 2, window.getHeight() / 2);
105        return centerPoint;
106    }
107
108    public static void mouseDragAndDrop(Robot robot, Point from, Point to) {
109        mouseDND(robot, from.x, from.y, to.x, to.y);
110    }
111
112    public static void mouseDND(Robot robot, int x1, int y1, int x2, int y2) {
113
114        int N = 20;
115        int x = x1;
116        int y = y1;
117        int dx = (x2 - x1) / N;
118        int dy = (y2 - y1) / N;
119
120        robot.mousePress(InputEvent.BUTTON1_MASK);
121
122        for (int i = 0; i < N; i++) {
123            robot.mouseMove(x += dx, y += dy);
124        }
125
126        robot.mouseRelease(InputEvent.BUTTON1_MASK);
127    }
128
129    private static class TestDragGestureListener implements DragGestureListener {
130
131        public void dragGestureRecognized(DragGestureEvent dge) {
132            dge.startDrag(null, new StringTransferable());
133        }
134    }
135
136    static class StringTransferable implements Transferable {
137
138        @Override
139        public DataFlavor[] getTransferDataFlavors() {
140            return new DataFlavor[]{DataFlavor.stringFlavor};
141        }
142
143        @Override
144        public boolean isDataFlavorSupported(DataFlavor flavor) {
145            return flavor.equals(DataFlavor.stringFlavor);
146        }
147
148        @Override
149        public Object getTransferData(DataFlavor flavor) {
150            return "Hello World!";
151        }
152    }
153
154    private static class TestDropTargetListener implements DropTargetListener {
155
156        private final Frame targetFrame;
157
158        public TestDropTargetListener(Frame targetFrame) {
159            this.targetFrame = targetFrame;
160        }
161
162        @Override
163        public void dragEnter(DropTargetDragEvent dtde) {
164            dtde.acceptDrag(dtde.getDropAction());
165        }
166
167        @Override
168        public void dragOver(DropTargetDragEvent dtde) {
169            dtde.acceptDrag(dtde.getDropAction());
170        }
171
172        @Override
173        public void dropActionChanged(DropTargetDragEvent dtde) {
174            dtde.acceptDrag(dtde.getDropAction());
175        }
176
177        @Override
178        public void dragExit(DropTargetEvent dte) {
179        }
180
181        @Override
182        public void drop(DropTargetDropEvent dtde) {
183            dtde.acceptDrop(dtde.getDropAction());
184            showModalDialog(targetFrame);
185            dtde.dropComplete(true);
186        }
187    }
188
189    private static void showModalDialog(Frame targetFrame) {
190
191        Dialog dialog = new Dialog(targetFrame, true);
192
193        dialog.addMouseListener(new MouseAdapter() {
194
195            @Override
196            public void mouseClicked(MouseEvent e) {
197                passed = true;
198                dialog.dispose();
199            }
200        });
201
202        dialog.setSize(400, 300);
203        dialog.setTitle("Modal Dialog!");
204
205        clickOnModalDialog(dialog);
206        dialog.setVisible(true);
207    }
208
209    private static void clickOnModalDialog(Dialog dialog) {
210        new Thread(() -> {
211            clickOnDialog(dialog);
212        }).start();
213    }
214
215    private static void clickOnDialog(Dialog dialog) {
216        try {
217            long time = System.currentTimeMillis() + 200;
218
219            while (!dialog.isVisible()) {
220                if (time < System.currentTimeMillis()) {
221                    throw new RuntimeException("Dialog is not visible!");
222                }
223                Thread.sleep(10);
224            }
225            Robot robot = new Robot();
226            robot.setAutoDelay(50);
227            robot.waitForIdle();
228            robot.delay(200);
229
230            Point point = getCenterPoint(dialog);
231
232            robot.mouseMove(point.x, point.y);
233            robot.mousePress(InputEvent.BUTTON1_MASK);
234            robot.mouseRelease(InputEvent.BUTTON1_MASK);
235
236        } catch (Exception e) {
237            throw new RuntimeException(e);
238        }
239    }
240}
241