1 /* 2 * Copyright (c) 2014, 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 24 /* @test 25 * @bug 8024061 26 * @summary Checks that no exception is thrown if dragGestureRecognized 27 * takes a while to complete. 28 */ 29 import sun.awt.OSInfo; 30 import sun.awt.OSInfo.OSType; 31 import sun.awt.SunToolkit; 32 33 import java.awt.*; 34 import java.awt.datatransfer.DataFlavor; 35 import java.awt.datatransfer.Transferable; 36 import java.awt.datatransfer.UnsupportedFlavorException; 37 import java.awt.dnd.DnDConstants; 38 import java.awt.dnd.DragGestureEvent; 39 import java.awt.dnd.DragGestureListener; 40 import java.awt.dnd.DragSource; 41 import java.awt.dnd.DragSourceDragEvent; 42 import java.awt.dnd.DragSourceDropEvent; 43 import java.awt.dnd.DragSourceEvent; 44 import java.awt.dnd.DragSourceListener; 45 import java.awt.dnd.DropTarget; 46 import java.awt.dnd.DropTargetDragEvent; 47 import java.awt.dnd.DropTargetDropEvent; 48 import java.awt.dnd.DropTargetEvent; 49 import java.awt.dnd.DropTargetListener; 50 import java.awt.event.InputEvent; 51 52 import java.io.IOException; 53 import java.lang.reflect.InvocationTargetException; 54 import java.util.concurrent.CountDownLatch; 55 import java.util.concurrent.TimeUnit; 56 57 import javax.swing.*; 58 59 /** 60 * If dragGestureRecognized() takes a while to complete and if user performs a drag quickly, 61 * an exception is thrown from DropTargetListener.dragEnter when it calls 62 * DropTargetDragEvent.getTransferable(). 63 * <p> 64 * This class introduces a delay in dragGestureRecognized() to cause the exception. 65 */ 66 public class bug8024061 { 67 private static final DataFlavor DropObjectFlavor; 68 private static final int DELAY = 1000; 69 70 private final DnDPanel panel1 = new DnDPanel(Color.yellow); 71 private final DnDPanel panel2 = new DnDPanel(Color.pink); 72 private final JFrame frame; 73 74 private static final CountDownLatch lock = new CountDownLatch(1); 75 private static volatile Exception dragEnterException = null; 76 77 static { 78 DataFlavor flavor = null; 79 try { 80 flavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType); 81 } catch (ClassNotFoundException e) { 82 e.printStackTrace(); 83 } 84 DropObjectFlavor = flavor; 85 } 86 87 bug8024061() { 88 frame = new JFrame("DnDWithRobot"); 89 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 90 91 Dimension d = new Dimension(100, 100); 92 93 panel1.setPreferredSize(d); 94 panel2.setPreferredSize(d); 95 96 Container content = frame.getContentPane(); 97 content.setLayout(new GridLayout(1, 2, 5, 5)); 98 content.add(panel1); 99 content.add(panel2); 100 101 frame.pack(); 102 103 DropObject drop = new DropObject(); 104 drop.place(panel1, new Point(10, 10)); 105 frame.setVisible(true); 106 } 107 108 public static void main(String[] args) throws AWTException, InvocationTargetException, InterruptedException { 109 OSType type = OSInfo.getOSType(); 110 if (type != OSType.LINUX && type != OSType.SOLARIS) { 111 System.out.println("This test is for Linux and Solaris only... " + 112 "skipping!"); 113 return; 114 } 115 116 final bug8024061[] dnd = {null}; 117 SwingUtilities.invokeAndWait(new Runnable() { 118 @Override 119 public void run() { 120 dnd[0] = new bug8024061(); 121 } 122 }); 123 final Robot robot = new Robot(); 124 robot.setAutoDelay(10); 125 SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); 126 toolkit.realSync(); 127 128 JFrame frame = dnd[0].frame; 129 Point point = frame.getLocationOnScreen(); 130 Point here = new Point(point.x + 35, point.y + 45); 131 Point there = new Point(point.x + 120, point.y + 45); 132 here.x += 25; 133 robot.mouseMove(here.x, here.y); 134 robot.mousePress(InputEvent.BUTTON1_MASK); 135 while (here.x < there.x) { 136 here.x += 20; 137 robot.mouseMove(here.x, here.y); 138 System.out.println("x = " + here.x); 139 } 140 robot.mouseRelease(InputEvent.BUTTON1_MASK); 141 toolkit.realSync(); 142 robot.mousePress(InputEvent.BUTTON1_MASK); 143 robot.mouseRelease(InputEvent.BUTTON1_MASK); 144 System.out.println("finished"); 145 146 try { 147 if (lock.await(5, TimeUnit.SECONDS)) { 148 if (dragEnterException == null) { 149 System.out.println("Test passed."); 150 } else { 151 System.out.println("Test failed."); 152 dragEnterException.printStackTrace(); 153 throw new RuntimeException(dragEnterException); 154 } 155 } else { 156 System.out.println("Test failed. Timeout reached"); 157 throw new RuntimeException("Timed out waiting for dragEnter()"); 158 } 159 } finally { 160 frame.dispose(); 161 } 162 } 163 164 class DropObject implements Transferable { 165 DnDPanel panel; 166 Color color = Color.CYAN; 167 int width = 50; 168 int height = 50; 169 int x; 170 int y; 171 172 void draw(Graphics2D g) { 173 Color savedColor = g.getColor(); 174 g.setColor(color); 175 g.fillRect(x, y, width, height); 176 g.setColor(Color.lightGray); 177 g.drawRect(x, y, width, height); 178 g.setColor(savedColor); 179 } 180 181 boolean contains(int x, int y) { 182 return (x > this.x && x < this.x + width) 183 && (y > this.y && y < this.y + height); 184 } 185 186 @Override 187 public DataFlavor[] getTransferDataFlavors() { 188 return new DataFlavor[]{DropObjectFlavor}; 189 } 190 191 void place(DnDPanel panel, Point location) { 192 if (panel != this.panel) { 193 x = location.x; 194 y = location.y; 195 if (this.panel != null) { 196 this.panel.setDropObject(null); 197 this.panel.repaint(); 198 } 199 this.panel = panel; 200 this.panel.setDropObject(this); 201 this.panel.repaint(); 202 } 203 } 204 205 @Override 206 public boolean isDataFlavorSupported(DataFlavor flavor) { 207 return DropObjectFlavor.equals(flavor); 208 } 209 210 @Override 211 public Object getTransferData(DataFlavor flavor) 212 throws UnsupportedFlavorException, IOException { 213 if (isDataFlavorSupported(flavor)) { 214 return this; 215 } else { 216 throw new UnsupportedFlavorException(flavor); 217 } 218 } 219 } 220 221 class DnDPanel extends JPanel { 222 DropObject dropObject; 223 final DragSource dragSource; 224 final DropTarget dropTarget; 225 final Color color; 226 final DragGestureListener dgListener; 227 final DragSourceListener dsListener; 228 final DropTargetListener dtListener; 229 230 DnDPanel(Color color) { 231 this.color = color; 232 this.dragSource = DragSource.getDefaultDragSource(); 233 dgListener = new DragGestureListener() { 234 @Override 235 public void dragGestureRecognized(DragGestureEvent dge) { 236 Point location = dge.getDragOrigin(); 237 if (dropObject != null && dropObject.contains(location.x, location.y)) { 238 dragSource.startDrag(dge, DragSource.DefaultCopyNoDrop, dropObject, dsListener); 239 try { 240 Thread.sleep(DELAY); 241 } catch (InterruptedException e) { 242 } 243 } 244 } 245 }; 246 247 dsListener = new DragSourceListener() { 248 @Override 249 public void dragEnter(DragSourceDragEvent dsde) { 250 } 251 252 @Override 253 public void dragOver(DragSourceDragEvent dsde) { 254 } 255 256 @Override 257 public void dropActionChanged(DragSourceDragEvent dsde) { 258 } 259 260 @Override 261 public void dragExit(DragSourceEvent dse) { 262 } 263 264 @Override 265 public void dragDropEnd(DragSourceDropEvent dsde) { 266 } 267 }; 268 269 dtListener = new DropTargetListener() { 270 @Override 271 public void dragEnter(DropTargetDragEvent dtde) { 272 if (dropObject != null) { 273 dtde.rejectDrag(); 274 return; 275 } 276 dtde.acceptDrag(DnDConstants.ACTION_MOVE); 277 try { 278 Transferable t = dtde.getTransferable(); 279 Object data = t.getTransferData(DropObjectFlavor); 280 } catch (Exception e) { 281 dragEnterException = e; 282 e.printStackTrace(); 283 } finally { 284 lock.countDown(); 285 } 286 } 287 288 @Override 289 public void dragOver(DropTargetDragEvent dtde) { 290 if (dropObject != null) { 291 dtde.rejectDrag(); 292 return; 293 } 294 dtde.acceptDrag(DnDConstants.ACTION_MOVE); 295 } 296 297 @Override 298 public void dropActionChanged(DropTargetDragEvent dtde) { 299 } 300 301 @Override 302 public void dragExit(DropTargetEvent dte) { 303 } 304 305 @Override 306 public void drop(DropTargetDropEvent dtde) { 307 if (dropObject != null) { 308 dtde.rejectDrop(); 309 return; 310 } 311 try { 312 dtde.acceptDrop(DnDConstants.ACTION_MOVE); 313 Transferable t = dtde.getTransferable(); 314 DropObject dropObject = (DropObject) t.getTransferData(DropObjectFlavor); 315 Point location = dtde.getLocation(); 316 dropObject.place(DnDPanel.this, location); 317 dtde.dropComplete(true); 318 } catch (Exception e) { 319 e.printStackTrace(); 320 } 321 322 } 323 }; 324 325 dragSource.createDefaultDragGestureRecognizer(this, 326 DnDConstants.ACTION_MOVE, dgListener); 327 328 dropTarget = new DropTarget(this, DnDConstants.ACTION_MOVE, dtListener, true); 329 330 } 331 332 public void paintComponent(Graphics g) { 333 super.paintComponent(g); 334 Color savedColor = g.getColor(); 335 g.setColor(color); 336 g.fillRect(0, 0, getWidth(), getHeight()); 337 g.setColor(savedColor); 338 if (dropObject != null) { 339 dropObject.draw((Graphics2D) g); 340 } 341 } 342 343 void setDropObject(DropObject dropObject) { 344 this.dropObject = dropObject; 345 } 346 347 DropObject findDropObject(int x, int y) { 348 if (dropObject != null && dropObject.contains(x, y)) { 349 return dropObject; 350 } 351 return null; 352 } 353 } 354 }