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