1 /* 2 * Copyright (c) 1997, 2015, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt.dnd; 27 28 import java.awt.Component; 29 30 import java.awt.datatransfer.DataFlavor; 31 import java.awt.datatransfer.Transferable; 32 import java.awt.datatransfer.UnsupportedFlavorException; 33 34 import java.awt.dnd.peer.DropTargetContextPeer; 35 36 import java.io.IOException; 37 import java.io.Serializable; 38 39 import java.util.Arrays; 40 import java.util.List; 41 42 import sun.awt.AWTAccessor; 43 import sun.awt.AWTAccessor.DropTargetContextAccessor; 44 45 /** 46 * A <code>DropTargetContext</code> is created 47 * whenever the logical cursor associated 48 * with a Drag and Drop operation coincides with the visible geometry of 49 * a <code>Component</code> associated with a <code>DropTarget</code>. 50 * The <code>DropTargetContext</code> provides 51 * the mechanism for a potential receiver 52 * of a drop operation to both provide the end user with the appropriate 53 * drag under feedback, but also to effect the subsequent data transfer 54 * if appropriate. 55 * 56 * @since 1.2 57 */ 58 59 public class DropTargetContext implements Serializable { 60 61 private static final long serialVersionUID = -634158968993743371L; 62 63 static { 64 AWTAccessor.setDropTargetContextAccessor(new DropTargetContextAccessor() { 65 @Override 66 public void reset(DropTargetContext dtc) { 67 dtc.reset(); 68 } 69 @Override 70 public void setDropTargetContextPeer(DropTargetContext dtc, 71 DropTargetContextPeer dtcp) { 72 dtc.setDropTargetContextPeer(dtcp); 73 } 74 }); 75 } 76 /** 77 * Construct a <code>DropTargetContext</code> 78 * given a specified <code>DropTarget</code>. 79 * 80 * @param dt the DropTarget to associate with 81 */ 82 83 DropTargetContext(DropTarget dt) { 84 super(); 85 86 dropTarget = dt; 87 } 88 89 /** 90 * This method returns the <code>DropTarget</code> associated with this 91 * <code>DropTargetContext</code>. 92 * 93 * @return the <code>DropTarget</code> associated with this <code>DropTargetContext</code> 94 */ 95 96 public DropTarget getDropTarget() { return dropTarget; } 97 98 /** 99 * This method returns the <code>Component</code> associated with 100 * this <code>DropTargetContext</code>. 101 * 102 * @return the Component associated with this Context 103 */ 104 105 public Component getComponent() { return dropTarget.getComponent(); } 106 107 /** 108 * Called when disassociated with the <code>DropTargetContextPeer</code>. 109 */ 110 void reset() { 111 dropTargetContextPeer = null; 112 transferable = null; 113 } 114 115 /** 116 * This method sets the current actions acceptable to 117 * this <code>DropTarget</code>. 118 * 119 * @param actions an <code>int</code> representing the supported action(s) 120 */ 121 122 protected void setTargetActions(int actions) { 123 DropTargetContextPeer peer = getDropTargetContextPeer(); 124 if (peer != null) { 125 synchronized (peer) { 126 peer.setTargetActions(actions); 127 getDropTarget().doSetDefaultActions(actions); 128 } 129 } else { 130 getDropTarget().doSetDefaultActions(actions); 131 } 132 } 133 134 /** 135 * This method returns an <code>int</code> representing the 136 * current actions this <code>DropTarget</code> will accept. 137 * 138 * @return the current actions acceptable to this <code>DropTarget</code> 139 */ 140 141 protected int getTargetActions() { 142 DropTargetContextPeer peer = getDropTargetContextPeer(); 143 return ((peer != null) 144 ? peer.getTargetActions() 145 : dropTarget.getDefaultActions() 146 ); 147 } 148 149 /** 150 * This method signals that the drop is completed and 151 * if it was successful or not. 152 * 153 * @param success true for success, false if not 154 * 155 * @throws InvalidDnDOperationException if a drop is not outstanding/extant 156 */ 157 158 public void dropComplete(boolean success) throws InvalidDnDOperationException{ 159 DropTargetContextPeer peer = getDropTargetContextPeer(); 160 if (peer != null) { 161 peer.dropComplete(success); 162 } 163 } 164 165 /** 166 * accept the Drag. 167 * 168 * @param dragOperation the supported action(s) 169 */ 170 171 protected void acceptDrag(int dragOperation) { 172 DropTargetContextPeer peer = getDropTargetContextPeer(); 173 if (peer != null) { 174 peer.acceptDrag(dragOperation); 175 } 176 } 177 178 /** 179 * reject the Drag. 180 */ 181 182 protected void rejectDrag() { 183 DropTargetContextPeer peer = getDropTargetContextPeer(); 184 if (peer != null) { 185 peer.rejectDrag(); 186 } 187 } 188 189 /** 190 * called to signal that the drop is acceptable 191 * using the specified operation. 192 * must be called during DropTargetListener.drop method invocation. 193 * 194 * @param dropOperation the supported action(s) 195 */ 196 197 protected void acceptDrop(int dropOperation) { 198 DropTargetContextPeer peer = getDropTargetContextPeer(); 199 if (peer != null) { 200 peer.acceptDrop(dropOperation); 201 } 202 } 203 204 /** 205 * called to signal that the drop is unacceptable. 206 * must be called during DropTargetListener.drop method invocation. 207 */ 208 209 protected void rejectDrop() { 210 DropTargetContextPeer peer = getDropTargetContextPeer(); 211 if (peer != null) { 212 peer.rejectDrop(); 213 } 214 } 215 216 /** 217 * get the available DataFlavors of the 218 * <code>Transferable</code> operand of this operation. 219 * 220 * @return a <code>DataFlavor[]</code> containing the 221 * supported <code>DataFlavor</code>s of the 222 * <code>Transferable</code> operand. 223 */ 224 225 protected DataFlavor[] getCurrentDataFlavors() { 226 DropTargetContextPeer peer = getDropTargetContextPeer(); 227 return peer != null ? peer.getTransferDataFlavors() : new DataFlavor[0]; 228 } 229 230 /** 231 * This method returns a the currently available DataFlavors 232 * of the <code>Transferable</code> operand 233 * as a <code>java.util.List</code>. 234 * 235 * @return the currently available 236 * DataFlavors as a <code>java.util.List</code> 237 */ 238 239 protected List<DataFlavor> getCurrentDataFlavorsAsList() { 240 return Arrays.asList(getCurrentDataFlavors()); 241 } 242 243 /** 244 * This method returns a <code>boolean</code> 245 * indicating if the given <code>DataFlavor</code> is 246 * supported by this <code>DropTargetContext</code>. 247 * 248 * @param df the <code>DataFlavor</code> 249 * 250 * @return if the <code>DataFlavor</code> specified is supported 251 */ 252 253 protected boolean isDataFlavorSupported(DataFlavor df) { 254 return getCurrentDataFlavorsAsList().contains(df); 255 } 256 257 /** 258 * get the Transferable (proxy) operand of this operation 259 * 260 * @throws InvalidDnDOperationException if a drag is not outstanding/extant 261 * 262 * @return the <code>Transferable</code> 263 */ 264 265 protected Transferable getTransferable() throws InvalidDnDOperationException { 266 DropTargetContextPeer peer = getDropTargetContextPeer(); 267 if (peer == null) { 268 throw new InvalidDnDOperationException(); 269 } else { 270 if (transferable == null) { 271 Transferable t = peer.getTransferable(); 272 boolean isLocal = peer.isTransferableJVMLocal(); 273 synchronized (this) { 274 if (transferable == null) { 275 transferable = createTransferableProxy(t, isLocal); 276 } 277 } 278 } 279 280 return transferable; 281 } 282 } 283 284 /** 285 * Get the <code>DropTargetContextPeer</code> 286 * 287 * @return the platform peer 288 */ 289 DropTargetContextPeer getDropTargetContextPeer() { 290 return dropTargetContextPeer; 291 } 292 293 /** 294 * Sets the {@code DropTargetContextPeer} 295 */ 296 void setDropTargetContextPeer(final DropTargetContextPeer dtcp) { 297 dropTargetContextPeer = dtcp; 298 } 299 300 /** 301 * Creates a TransferableProxy to proxy for the specified 302 * Transferable. 303 * 304 * @param t the <tt>Transferable</tt> to be proxied 305 * @param local <tt>true</tt> if <tt>t</tt> represents 306 * the result of a local drag-n-drop operation. 307 * @return the new <tt>TransferableProxy</tt> instance. 308 */ 309 protected Transferable createTransferableProxy(Transferable t, boolean local) { 310 return new TransferableProxy(t, local); 311 } 312 313 /****************************************************************************/ 314 315 316 /** 317 * <code>TransferableProxy</code> is a helper inner class that implements 318 * <code>Transferable</code> interface and serves as a proxy for another 319 * <code>Transferable</code> object which represents data transfer for 320 * a particular drag-n-drop operation. 321 * <p> 322 * The proxy forwards all requests to the encapsulated transferable 323 * and automatically performs additional conversion on the data 324 * returned by the encapsulated transferable in case of local transfer. 325 */ 326 327 protected class TransferableProxy implements Transferable { 328 329 /** 330 * Constructs a <code>TransferableProxy</code> given 331 * a specified <code>Transferable</code> object representing 332 * data transfer for a particular drag-n-drop operation and 333 * a <code>boolean</code> which indicates whether the 334 * drag-n-drop operation is local (within the same JVM). 335 * 336 * @param t the <code>Transferable</code> object 337 * @param local <code>true</code>, if <code>t</code> represents 338 * the result of local drag-n-drop operation 339 */ 340 TransferableProxy(Transferable t, boolean local) { 341 proxy = new sun.awt.datatransfer.TransferableProxy(t, local); 342 transferable = t; 343 isLocal = local; 344 } 345 346 /** 347 * Returns an array of DataFlavor objects indicating the flavors 348 * the data can be provided in by the encapsulated transferable. 349 * 350 * @return an array of data flavors in which the data can be 351 * provided by the encapsulated transferable 352 */ 353 public DataFlavor[] getTransferDataFlavors() { 354 return proxy.getTransferDataFlavors(); 355 } 356 357 /** 358 * Returns whether or not the specified data flavor is supported by 359 * the encapsulated transferable. 360 * @param flavor the requested flavor for the data 361 * @return <code>true</code> if the data flavor is supported, 362 * <code>false</code> otherwise 363 */ 364 public boolean isDataFlavorSupported(DataFlavor flavor) { 365 return proxy.isDataFlavorSupported(flavor); 366 } 367 368 /** 369 * Returns an object which represents the data provided by 370 * the encapsulated transferable for the requested data flavor. 371 * <p> 372 * In case of local transfer a serialized copy of the object 373 * returned by the encapsulated transferable is provided when 374 * the data is requested in application/x-java-serialized-object 375 * data flavor. 376 * 377 * @param df the requested flavor for the data 378 * @throws IOException if the data is no longer available 379 * in the requested flavor. 380 * @throws UnsupportedFlavorException if the requested data flavor is 381 * not supported. 382 */ 383 public Object getTransferData(DataFlavor df) 384 throws UnsupportedFlavorException, IOException 385 { 386 return proxy.getTransferData(df); 387 } 388 389 /* 390 * fields 391 */ 392 393 // We don't need to worry about client code changing the values of 394 // these variables. Since TransferableProxy is a protected class, only 395 // subclasses of DropTargetContext can access it. And DropTargetContext 396 // cannot be subclassed by client code because it does not have a 397 // public constructor. 398 399 /** 400 * The encapsulated <code>Transferable</code> object. 401 */ 402 protected Transferable transferable; 403 404 /** 405 * A <code>boolean</code> indicating if the encapsulated 406 * <code>Transferable</code> object represents the result 407 * of local drag-n-drop operation (within the same JVM). 408 */ 409 protected boolean isLocal; 410 411 private sun.awt.datatransfer.TransferableProxy proxy; 412 } 413 414 /****************************************************************************/ 415 416 /* 417 * fields 418 */ 419 420 /** 421 * The DropTarget associated with this DropTargetContext. 422 * 423 * @serial 424 */ 425 private final DropTarget dropTarget; 426 427 private transient DropTargetContextPeer dropTargetContextPeer; 428 429 private transient Transferable transferable; 430 }