summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarolyn MacLeod <carolyn>2008-01-31 16:28:05 +0000
committerCarolyn MacLeod <carolyn>2008-01-31 16:28:05 +0000
commit7f3d866c4140cd4f8ccd06beca69339b6dfdde1e (patch)
tree85e76f04eb718297017548595bb42d4ded026d6a
parent57bc9da816b78e8225c369df2233b6334cde29f9 (diff)
downloadeclipse.platform.swt-7f3d866c4140cd4f8ccd06beca69339b6dfdde1e.tar.gz
eclipse.platform.swt-7f3d866c4140cd4f8ccd06beca69339b6dfdde1e.tar.xz
eclipse.platform.swt-7f3d866c4140cd4f8ccd06beca69339b6dfdde1e.zip
initial - copy of carbon
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/ByteArrayTransfer.java182
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Clipboard.java567
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/DragSource.java521
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/DropTarget.java769
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/FileTransfer.java196
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/HTMLTransfer.java103
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/ImageTransfer.java210
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/RTFTransfer.java129
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TableDragSourceEffect.java42
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TableDropTargetEffect.java196
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TextTransfer.java154
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Transfer.java154
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TransferData.java69
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TreeDragSourceEffect.java41
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TreeDropTargetEffect.java265
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/URLTransfer.java1
16 files changed, 3599 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/ByteArrayTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/ByteArrayTransfer.java
new file mode 100644
index 0000000000..c138c1c0e8
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/ByteArrayTransfer.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+/**
+ * The class <code>ByteArrayTransfer</code> provides a platform specific
+ * mechanism for converting a java <code>byte[]</code> to a platform
+ * specific representation of the byte array and vice versa. See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p><code>ByteArrayTransfer</code> is never used directly but is sub-classed
+ * by transfer agents that convert between data in a java format such as a
+ * <code>String</code> and a platform specific byte array.
+ *
+ * <p>If the data you are converting <b>does not</b> map to a
+ * <code>byte[]</code>, you should sub-class <code>Transfer</code> directly
+ * and do your own mapping to a platform data type.</p>
+ *
+ * <p>The following snippet shows a subclass of ByteArrayTransfer that transfers
+ * data defined by the class <code>MyType</code>.</p>
+ *
+ * <pre><code>
+ * public class MyType {
+ * public String fileName;
+ * public long fileLength;
+ * public long lastModified;
+ * }
+ * </code></pre>
+ *
+ * <pre><code>
+ * public class MyTypeTransfer extends ByteArrayTransfer {
+ *
+ * private static final String MYTYPENAME = "my_type_name";
+ * private static final int MYTYPEID = registerType(MYTYPENAME);
+ * private static MyTypeTransfer _instance = new MyTypeTransfer();
+ *
+ * private MyTypeTransfer() {}
+ *
+ * public static MyTypeTransfer getInstance () {
+ * return _instance;
+ * }
+ * public void javaToNative (Object object, TransferData transferData) {
+ * if (object == null || !(object instanceof MyType[])) return;
+ *
+ * if (isSupportedType(transferData)) {
+ * MyType[] myTypes = (MyType[]) object;
+ * try {
+ * // write data to a byte array and then ask super to convert to pMedium
+ * ByteArrayOutputStream out = new ByteArrayOutputStream();
+ * DataOutputStream writeOut = new DataOutputStream(out);
+ * for (int i = 0, length = myTypes.length; i &lt; length; i++){
+ * byte[] buffer = myTypes[i].fileName.getBytes();
+ * writeOut.writeInt(buffer.length);
+ * writeOut.write(buffer);
+ * writeOut.writeLong(myTypes[i].fileLength);
+ * writeOut.writeLong(myTypes[i].lastModified);
+ * }
+ * byte[] buffer = out.toByteArray();
+ * writeOut.close();
+ *
+ * super.javaToNative(buffer, transferData);
+ *
+ * } catch (IOException e) {
+ * }
+ * }
+ * }
+ * public Object nativeToJava(TransferData transferData){
+ *
+ * if (isSupportedType(transferData)) {
+ *
+ * byte[] buffer = (byte[])super.nativeToJava(transferData);
+ * if (buffer == null) return null;
+ *
+ * MyType[] myData = new MyType[0];
+ * try {
+ * ByteArrayInputStream in = new ByteArrayInputStream(buffer);
+ * DataInputStream readIn = new DataInputStream(in);
+ * while(readIn.available() > 20) {
+ * MyType datum = new MyType();
+ * int size = readIn.readInt();
+ * byte[] name = new byte[size];
+ * readIn.read(name);
+ * datum.fileName = new String(name);
+ * datum.fileLength = readIn.readLong();
+ * datum.lastModified = readIn.readLong();
+ * MyType[] newMyData = new MyType[myData.length + 1];
+ * System.arraycopy(myData, 0, newMyData, 0, myData.length);
+ * newMyData[myData.length] = datum;
+ * myData = newMyData;
+ * }
+ * readIn.close();
+ * } catch (IOException ex) {
+ * return null;
+ * }
+ * return myData;
+ * }
+ *
+ * return null;
+ * }
+ * protected String[] getTypeNames(){
+ * return new String[]{MYTYPENAME};
+ * }
+ * protected int[] getTypeIds(){
+ * return new int[] {MYTYPEID};
+ * }
+ * }
+ * </code></pre>
+ */
+public abstract class ByteArrayTransfer extends Transfer {
+
+public TransferData[] getSupportedTypes() {
+ int[] types = getTypeIds();
+ TransferData[] data = new TransferData[types.length];
+ for (int i = 0; i < types.length; i++) {
+ data[i] = new TransferData();
+ data[i].type = types[i];
+ }
+ return data;
+}
+
+public boolean isSupportedType(TransferData transferData){
+ if (transferData == null) return false;
+ int[] types = getTypeIds();
+ for (int i = 0; i < types.length; i++) {
+ if (transferData.type == types[i]) return true;
+ }
+ return false;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts a java
+ * <code>byte[]</code> to a platform specific representation. For additional
+ * information see <code>Transfer#javaToNative</code>.
+ *
+ * @see Transfer#javaToNative
+ *
+ * @param object a java <code>byte[]</code> containing the data to be converted
+ * @param transferData an empty <code>TransferData</code> object; this
+ * object will be filled in on return with the platform specific format of the data
+ */
+protected void javaToNative (Object object, TransferData transferData) {
+ if (!checkByteArray(object) && !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ byte[] orig = (byte[])object;
+ byte[] buffer = new byte[orig.length];
+ System.arraycopy(orig, 0, buffer, 0, orig.length);
+ transferData.data = new byte[1][];
+ transferData.data[0] = buffer;
+ transferData.result = 0;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of a byte array to a java <code>byte[]</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @see Transfer#nativeToJava
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>byte[]</code> containing the converted data if the
+ * conversion was successful; otherwise null
+ */
+protected Object nativeToJava(TransferData transferData) {
+ if (!isSupportedType(transferData) || transferData.data == null) return null;
+ if (transferData.data.length == 0 || transferData.data[0].length == 0) return null;
+ return transferData.data[0];
+}
+boolean checkByteArray(Object object) {
+ return (object != null && object instanceof byte[] && ((byte[])object).length > 0);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Clipboard.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Clipboard.java
new file mode 100644
index 0000000000..fc4839d51b
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Clipboard.java
@@ -0,0 +1,567 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.swt.internal.carbon.OS;
+
+/**
+ * The <code>Clipboard</code> provides a mechanism for transferring data from one
+ * application to another or within an application.
+ *
+ * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
+ */
+public class Clipboard {
+
+ Display display;
+ int scrap = 0;
+
+/**
+ * Constructs a new instance of this class. Creating an instance of a Clipboard
+ * may cause system resources to be allocated depending on the platform. It is therefore
+ * mandatory that the Clipboard instance be disposed when no longer required.
+ *
+ * @param display the display on which to allocate the clipboard
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ *
+ * @see Clipboard#dispose
+ * @see Clipboard#checkSubclass
+ */
+public Clipboard(Display display) {
+ checkSubclass ();
+ if (display == null) {
+ display = Display.getCurrent();
+ if (display == null) {
+ display = Display.getDefault();
+ }
+ }
+ if (display.getThread() != Thread.currentThread()) {
+ DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
+ }
+ this.display = display;
+}
+
+/**
+ * Checks that this class can be subclassed.
+ * <p>
+ * The SWT class library is intended to be subclassed
+ * only at specific, controlled points. This method enforces this
+ * rule unless it is overridden.
+ * </p><p>
+ * <em>IMPORTANT:</em> By providing an implementation of this
+ * method that allows a subclass of a class which does not
+ * normally allow subclassing to be created, the implementer
+ * agrees to be fully responsible for the fact that any such
+ * subclass will likely fail between SWT releases and will be
+ * strongly platform specific. No support is provided for
+ * user-written classes which are implemented in this fashion.
+ * </p><p>
+ * The ability to subclass outside of the allowed SWT classes
+ * is intended purely to enable those not on the SWT development
+ * team to implement patches in order to get around specific
+ * limitations in advance of when those limitations can be
+ * addressed by the team. Subclassing should not be attempted
+ * without an intimate and detailed understanding of the hierarchy.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ */
+protected void checkSubclass () {
+ String name = getClass().getName ();
+ String validName = Clipboard.class.getName();
+ if (!validName.equals(name)) {
+ DND.error (SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+/**
+ * Throws an <code>SWTException</code> if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method <em>should</em> be called by
+ * widget implementors to enforce the standard SWT invariants.
+ * <p>
+ * Currently, it is an error to invoke any method (other than
+ * <code>isDisposed()</code>) on a widget that has had its
+ * <code>dispose()</code> method called. It is also an error
+ * to call widget methods from any thread that is different
+ * from the thread that created the widget.
+ * </p><p>
+ * In future releases of SWT, there may be more or fewer error
+ * checks and exceptions may be thrown for different reasons.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+protected void checkWidget () {
+ Display display = this.display;
+ if (display == null) DND.error (SWT.ERROR_WIDGET_DISPOSED);
+ if (display.getThread() != Thread.currentThread ()) DND.error (SWT.ERROR_THREAD_INVALID_ACCESS);
+ if (display.isDisposed()) DND.error(SWT.ERROR_WIDGET_DISPOSED);
+}
+
+/**
+ * If this clipboard is currently the owner of the data on the system clipboard,
+ * clear the contents. If this clipboard is not the owner, then nothing is done.
+ * Note that there are clipboard assistant applications that take ownership of
+ * data or make copies of data when it is placed on the clipboard. In these
+ * cases, it may not be possible to clear the clipboard.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void clearContents() {
+ clearContents(DND.CLIPBOARD);
+}
+
+/**
+ * If this clipboard is currently the owner of the data on the specified
+ * clipboard, clear the contents. If this clipboard is not the owner, then
+ * nothing is done.
+ *
+ * <p>Note that there are clipboard assistant applications that take ownership
+ * of data or make copies of data when it is placed on the clipboard. In these
+ * cases, it may not be possible to clear the clipboard.</p>
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * @param clipboards to be cleared
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public void clearContents(int clipboards) {
+ checkWidget();
+ if ((clipboards & DND.CLIPBOARD) == 0 || scrap == 0) return;
+ int oldScrap = scrap;
+ scrap = 0;
+ int[] currentScrap = new int[1];
+ if (OS.GetCurrentScrap(currentScrap) != OS.noErr) return;
+ if (currentScrap[0] == oldScrap) {
+ OS.ClearCurrentScrap();
+ }
+}
+
+/**
+ * Disposes of the operating system resources associated with the clipboard.
+ * The data will still be available on the system clipboard after the dispose
+ * method is called.
+ *
+ * <p>NOTE: On some platforms the data will not be available once the application
+ * has exited or the display has been disposed.</p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ */
+public void dispose () {
+ if (isDisposed()) return;
+ if (display.getThread() != Thread.currentThread()) DND.error(SWT.ERROR_THREAD_INVALID_ACCESS);
+ display = null;
+}
+
+/**
+ * Retrieve the data of the specified type currently available on the system
+ * clipboard. Refer to the specific subclass of <code>Transfer</code> to
+ * determine the type of object returned.
+ *
+ * <p>The following snippet shows text and RTF text being retrieved from the
+ * clipboard:</p>
+ *
+ * <code><pre>
+ * Clipboard clipboard = new Clipboard(display);
+ * TextTransfer textTransfer = TextTransfer.getInstance();
+ * String textData = (String)clipboard.getContents(textTransfer);
+ * if (textData != null) System.out.println("Text is "+textData);
+ * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ * String rtfData = (String)clipboard.getContents(rtfTransfer);
+ * if (rtfData != null) System.out.println("RTF Text is "+rtfData);
+ * clipboard.dispose();
+ * </code></pre>
+ *
+ * @param transfer the transfer agent for the type of data being requested
+ * @return the data obtained from the clipboard or null if no data of this type is available
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
+ * </ul>
+ *
+ * @see Transfer
+ */
+public Object getContents(Transfer transfer) {
+ return getContents(transfer, DND.CLIPBOARD);
+}
+
+/**
+ * Retrieve the data of the specified type currently available on the specified
+ * clipboard. Refer to the specific subclass of <code>Transfer</code> to
+ * determine the type of object returned.
+ *
+ * <p>The following snippet shows text and RTF text being retrieved from the
+ * clipboard:</p>
+ *
+ * <code><pre>
+ * Clipboard clipboard = new Clipboard(display);
+ * TextTransfer textTransfer = TextTransfer.getInstance();
+ * String textData = (String)clipboard.getContents(textTransfer);
+ * if (textData != null) System.out.println("Text is "+textData);
+ * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ * String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD);
+ * if (rtfData != null) System.out.println("RTF Text is "+rtfData);
+ * clipboard.dispose();
+ * </code></pre>
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * @param transfer the transfer agent for the type of data being requested
+ * @param clipboards on which to look for data
+ *
+ * @return the data obtained from the clipboard or null if no data of this type is available
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
+ * </ul>
+ *
+ * @see Transfer
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public Object getContents(Transfer transfer, int clipboards) {
+ checkWidget();
+ if (transfer == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
+ if ((clipboards & DND.CLIPBOARD) == 0) return null;
+ int[] scrap = new int[1];
+ if (OS.GetCurrentScrap(scrap) != OS.noErr) return null;
+ int[] typeIds = transfer.getTypeIds();
+ int[] size = new int[1];
+ // get data from system clipboard
+ for (int i=0; i<typeIds.length; i++) {
+ int type = typeIds[i];
+ size[0] = 0;
+ if (OS.GetScrapFlavorSize(scrap[0], type, size) == OS.noErr && size[0] > 0) {
+ byte[] buffer = new byte[size[0]];
+ if (OS.GetScrapFlavorData(scrap[0], type, size, buffer) == OS.noErr) {
+ TransferData tdata = new TransferData();
+ tdata.type = type;
+ tdata.data = new byte[1][];
+ tdata.data[0] = buffer;
+ return transfer.nativeToJava(tdata);
+ }
+ }
+ }
+ return null; // No data available for this transfer
+}
+
+/**
+ * Returns <code>true</code> if the clipboard has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the clipboard.
+ * When a clipboard has been disposed, it is an error to
+ * invoke any other method using the clipboard.
+ * </p>
+ *
+ * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
+ *
+ * @since 3.0
+ */
+public boolean isDisposed () {
+ return (display == null);
+}
+
+/**
+ * Place data of the specified type on the system clipboard. More than one type
+ * of data can be placed on the system clipboard at the same time. Setting the
+ * data clears any previous data from the system clipboard, regardless of type.
+ *
+ * <p>NOTE: On some platforms, the data is immediately copied to the system
+ * clipboard but on other platforms it is provided upon request. As a result,
+ * if the application modifies the data object it has set on the clipboard, that
+ * modification may or may not be available when the data is subsequently
+ * requested.</p>
+ *
+ * <p>The following snippet shows text and RTF text being set on the copy/paste
+ * clipboard:
+ * </p>
+ *
+ * <code><pre>
+ * Clipboard clipboard = new Clipboard(display);
+ * String textData = "Hello World";
+ * String rtfData = "{\\rtf1\\b\\i Hello World}";
+ * TextTransfer textTransfer = TextTransfer.getInstance();
+ * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
+ * Object[] data = new Object[]{textData, rtfData};
+ * clipboard.setContents(data, transfers);
+ * clipboard.dispose();
+ * </code></pre>
+ *
+ * @param data the data to be set in the clipboard
+ * @param dataTypes the transfer agents that will convert the data to its
+ * platform specific format; each entry in the data array must have a
+ * corresponding dataType
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
+ * or the length of data is not the same as the length of dataTypes</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ */
+public void setContents(Object[] data, Transfer[] dataTypes) {
+ setContents(data, dataTypes, DND.CLIPBOARD);
+}
+
+/**
+ * Place data of the specified type on the specified clipboard. More than one
+ * type of data can be placed on the specified clipboard at the same time.
+ * Setting the data clears any previous data from the specified
+ * clipboard, regardless of type.
+ *
+ * <p>NOTE: On some platforms, the data is immediately copied to the specified
+ * clipboard but on other platforms it is provided upon request. As a result,
+ * if the application modifies the data object it has set on the clipboard, that
+ * modification may or may not be available when the data is subsequently
+ * requested.</p>
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * <p>The following snippet shows text and RTF text being set on the copy/paste
+ * clipboard:
+ * </p>
+ *
+ * <code><pre>
+ * Clipboard clipboard = new Clipboard(display);
+ * String textData = "Hello World";
+ * String rtfData = "{\\rtf1\\b\\i Hello World}";
+ * TextTransfer textTransfer = TextTransfer.getInstance();
+ * RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ * Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
+ * Object[] data = new Object[]{textData, rtfData};
+ * clipboard.setContents(data, transfers, DND.CLIPBOARD);
+ * clipboard.dispose();
+ * </code></pre>
+ *
+ * @param data the data to be set in the clipboard
+ * @param dataTypes the transfer agents that will convert the data to its
+ * platform specific format; each entry in the data array must have a
+ * corresponding dataType
+ * @param clipboards on which to set the data
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
+ * or the length of data is not the same as the length of dataTypes</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an SWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ *
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) {
+ checkWidget();
+ if (data == null || dataTypes == null || data.length != dataTypes.length || data.length == 0) {
+ DND.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] == null || dataTypes[i] == null || !dataTypes[i].validate(data[i])) {
+ DND.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ if ((clipboards & DND.CLIPBOARD) == 0) return;
+ if (OS.ClearCurrentScrap() != OS.noErr) {
+ DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
+ }
+ scrap = 0;
+ int[] currentScrap = new int[1];
+ if (OS.GetCurrentScrap(currentScrap) != OS.noErr) {
+ DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
+ }
+ scrap = currentScrap[0];
+ // copy data directly over to System clipboard (not deferred)
+ for (int i=0; i<dataTypes.length; i++) {
+ int[] typeIds = dataTypes[i].getTypeIds();
+ for (int j=0; j<typeIds.length; j++) {
+ TransferData transferData = new TransferData();
+ transferData.type = typeIds[j];
+ dataTypes[i].javaToNative(data[i], transferData);
+ if (transferData.result != OS.noErr) {
+ DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
+ }
+ //Drag and Drop can handle multiple items in one transfer but the
+ //Clipboard can not.
+ byte[] datum = transferData.data[0];
+ if (OS.PutScrapFlavor(scrap, transferData.type, 0, datum.length, datum) != OS.noErr){
+ DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
+ }
+ }
+ }
+}
+
+/**
+ * Returns an array of the data types currently available on the system
+ * clipboard. Use with Transfer.isSupportedType.
+ *
+ * @return array of data types currently available on the system clipboard
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see Transfer#isSupportedType
+ *
+ * @since 3.0
+ */
+public TransferData[] getAvailableTypes() {
+ return getAvailableTypes(DND.CLIPBOARD);
+}
+
+/**
+ * Returns an array of the data types currently available on the specified
+ * clipboard. Use with Transfer.isSupportedType.
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * @param clipboards from which to get the data types
+ * @return array of data types currently available on the specified clipboard
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see Transfer#isSupportedType
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public TransferData[] getAvailableTypes(int clipboards) {
+ checkWidget();
+ if ((clipboards & DND.CLIPBOARD) == 0) return new TransferData[0];
+ int[] types = _getAvailableTypes();
+ TransferData[] result = new TransferData[types.length];
+ for (int i = 0; i < types.length; i++) {
+ result[i] = new TransferData();
+ result[i].type = types[i];
+ }
+ return result;
+}
+
+/**
+ * Returns a platform specific list of the data types currently available on the
+ * system clipboard.
+ *
+ * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer
+ * sub-class. It should NOT be used within an application because it provides
+ * platform specific information.</p>
+ *
+ * @return a platform specific list of the data types currently available on the
+ * system clipboard
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public String[] getAvailableTypeNames() {
+ checkWidget();
+ int[] types = _getAvailableTypes();
+ String[] names = new String[types.length];
+ for (int i = 0; i < types.length; i++) {
+ int type = types[i];
+ StringBuffer sb = new StringBuffer();
+ sb.append((char)((type & 0xff000000) >> 24));
+ sb.append((char)((type & 0x00ff0000) >> 16));
+ sb.append((char)((type & 0x0000ff00) >> 8));
+ sb.append((char)((type & 0x000000ff) >> 0));
+ names[i] = sb.toString();
+ }
+ return names;
+}
+
+int[] _getAvailableTypes() {
+ int[] types = new int[0];
+ int[] scrap = new int[1];
+ if (OS.GetCurrentScrap(scrap) != OS.noErr) return types;
+ int[] count = new int[1];
+ if (OS.GetScrapFlavorCount(scrap[0], count) != OS.noErr || count[0] == 0) return types;
+ int[] info = new int[count[0] * 2];
+ if (OS.GetScrapFlavorInfoList(scrap[0], count, info) != OS.noErr) return types;
+ types = new int[count[0]];
+ for (int i= 0; i < count [0]; i++) {
+ types[i] = info[i*2];
+ }
+ return types;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/DragSource.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/DragSource.java
new file mode 100644
index 0000000000..cd00d4444d
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/DragSource.java
@@ -0,0 +1,521 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.swt.internal.Callback;
+import org.eclipse.swt.internal.carbon.CGPoint;
+import org.eclipse.swt.internal.carbon.EventRecord;
+import org.eclipse.swt.internal.carbon.OS;
+import org.eclipse.swt.internal.carbon.Point;
+
+/**
+ *
+ * <code>DragSource</code> defines the source object for a drag and drop transfer.
+ *
+ * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
+ *
+ * <p>A drag source is the object which originates a drag and drop operation. For the specified widget,
+ * it defines the type of data that is available for dragging and the set of operations that can
+ * be performed on that data. The operations can be any bit-wise combination of DND.MOVE, DND.COPY or
+ * DND.LINK. The type of data that can be transferred is specified by subclasses of Transfer such as
+ * TextTransfer or FileTransfer. The type of data transferred can be a predefined system type or it
+ * can be a type defined by the application. For instructions on how to define your own transfer type,
+ * refer to <code>ByteArrayTransfer</code>.</p>
+ *
+ * <p>You may have several DragSources in an application but you can only have one DragSource
+ * per Control. Data dragged from this DragSource can be dropped on a site within this application
+ * or it can be dropped on another application such as an external Text editor.</p>
+ *
+ * <p>The application supplies the content of the data being transferred by implementing the
+ * <code>DragSourceListener</code> and associating it with the DragSource via DragSource#addDragListener.</p>
+ *
+ * <p>When a successful move operation occurs, the application is required to take the appropriate
+ * action to remove the data from its display and remove any associated operating system resources or
+ * internal references. Typically in a move operation, the drop target makes a copy of the data
+ * and the drag source deletes the original. However, sometimes copying the data can take a long
+ * time (such as copying a large file). Therefore, on some platforms, the drop target may actually
+ * move the data in the operating system rather than make a copy. This is usually only done in
+ * file transfers. In this case, the drag source is informed in the DragEnd event that a
+ * DROP_TARGET_MOVE was performed. It is the responsibility of the drag source at this point to clean
+ * up its displayed information. No action needs to be taken on the operating system resources.</p>
+ *
+ * <p> The following example shows a Label widget that allows text to be dragged from it.</p>
+ *
+ * <code><pre>
+ * // Enable a label as a Drag Source
+ * Label label = new Label(shell, SWT.NONE);
+ * // This example will allow text to be dragged
+ * Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
+ * // This example will allow the text to be copied or moved to the drop target
+ * int operations = DND.DROP_MOVE | DND.DROP_COPY;
+ *
+ * DragSource source = new DragSource(label, operations);
+ * source.setTransfer(types);
+ * source.addDragListener(new DragSourceListener() {
+ * public void dragStart(DragSourceEvent e) {
+ * // Only start the drag if there is actually text in the
+ * // label - this text will be what is dropped on the target.
+ * if (label.getText().length() == 0) {
+ * event.doit = false;
+ * }
+ * };
+ * public void dragSetData(DragSourceEvent event) {
+ * // A drop has been performed, so provide the data of the
+ * // requested type.
+ * // (Checking the type of the requested data is only
+ * // necessary if the drag source supports more than
+ * // one data type but is shown here as an example).
+ * if (TextTransfer.getInstance().isSupportedType(event.dataType)){
+ * event.data = label.getText();
+ * }
+ * }
+ * public void dragFinished(DragSourceEvent event) {
+ * // A Move operation has been performed so remove the data
+ * // from the source
+ * if (event.detail == DND.DROP_MOVE)
+ * label.setText("");
+ * }
+ * });
+ * </pre></code>
+ *
+ *
+ * <dl>
+ * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
+ * <dt><b>Events</b></dt> <dd>DND.DragStart, DND.DragSetData, DND.DragEnd</dd>
+ * </dl>
+ */
+public class DragSource extends Widget {
+
+ // info for registering as a drag source
+ Control control;
+ Listener controlListener;
+ Transfer[] transferAgents = new Transfer[0];
+ DragSourceEffect dragEffect;
+
+ static final String DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$
+ static Callback DragSendDataProc;
+
+ static {
+ DragSendDataProc = new Callback(DragSource.class, "DragSendDataProc", 4); //$NON-NLS-1$
+ int dragSendDataProcAddress = DragSendDataProc.getAddress();
+ if (dragSendDataProcAddress == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ }
+
+/**
+ * Creates a new <code>DragSource</code> to handle dragging from the specified <code>Control</code>.
+ * Creating an instance of a DragSource may cause system resources to be allocated depending on the platform.
+ * It is therefore mandatory that the DragSource instance be disposed when no longer required.
+ *
+ * @param control the <code>Control</code> that the user clicks on to initiate the drag
+ * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
+ * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_CANNOT_INIT_DRAG - unable to initiate drag source; this will occur if more than one
+ * drag source is created for a control or if the operating system will not allow the creation
+ * of the drag source</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_INIT_DRAG should be an SWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ *
+ * @see Widget#dispose
+ * @see DragSource#checkSubclass
+ * @see DND#DROP_NONE
+ * @see DND#DROP_COPY
+ * @see DND#DROP_MOVE
+ * @see DND#DROP_LINK
+ */
+public DragSource(Control control, int style) {
+ super (control, checkStyle(style));
+ this.control = control;
+ if (control.getData(DND.DRAG_SOURCE_KEY) != null) {
+ DND.error(DND.ERROR_CANNOT_INIT_DRAG);
+ }
+ control.setData(DND.DRAG_SOURCE_KEY, this);
+
+ controlListener = new Listener () {
+ public void handleEvent (Event event) {
+ if (event.type == SWT.Dispose) {
+ if (!DragSource.this.isDisposed()) {
+ DragSource.this.dispose();
+ }
+ }
+ if (event.type == SWT.DragDetect) {
+ if (!DragSource.this.isDisposed()) {
+ DragSource.this.drag(event);
+ }
+ }
+ }
+ };
+ control.addListener (SWT.Dispose, controlListener);
+ control.addListener (SWT.DragDetect, controlListener);
+
+ this.addListener(SWT.Dispose, new Listener() {
+ public void handleEvent(Event e) {
+ onDispose();
+ }
+ });
+
+ Object effect = control.getData(DEFAULT_DRAG_SOURCE_EFFECT);
+ if (effect instanceof DragSourceEffect) {
+ dragEffect = (DragSourceEffect) effect;
+ } else if (control instanceof Tree) {
+ dragEffect = new TreeDragSourceEffect((Tree) control);
+ } else if (control instanceof Table) {
+ dragEffect = new TableDragSourceEffect((Table) control);
+ }
+}
+
+static int checkStyle (int style) {
+ if (style == SWT.NONE) return DND.DROP_MOVE;
+ return style;
+}
+
+static int DragSendDataProc(int theType, int dragSendRefCon, int theItemRef, int theDrag) {
+ DragSource source = FindDragSource(dragSendRefCon, theDrag);
+ if (source == null) return OS.cantGetFlavorErr;
+ return source.dragSendDataProc(theType, dragSendRefCon, theItemRef, theDrag);
+}
+
+static DragSource FindDragSource(int dragSendRefCon, int theDrag) {
+ if (dragSendRefCon == 0) return null;
+ Display display = Display.findDisplay(Thread.currentThread());
+ if (display == null || display.isDisposed()) return null;
+ Widget widget = display.findWidget(dragSendRefCon);
+ if (widget == null) return null;
+ return (DragSource)widget.getData(DND.DRAG_SOURCE_KEY);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when a drag and drop operation is in progress, by sending
+ * it one of the messages defined in the <code>DragSourceListener</code>
+ * interface.
+ *
+ * <p><ul>
+ * <li><code>dragStart</code> is called when the user has begun the actions required to drag the widget.
+ * This event gives the application the chance to decide if a drag should be started.
+ * <li><code>dragSetData</code> is called when the data is required from the drag source.
+ * <li><code>dragFinished</code> is called when the drop has successfully completed (mouse up
+ * over a valid target) or has been terminated (such as hitting the ESC key). Perform cleanup
+ * such as removing data from the source side on a successful move operation.
+ * </ul></p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DragSourceListener
+ * @see #removeDragListener
+ * @see DragSourceEvent
+ */
+public void addDragListener(DragSourceListener listener) {
+ if (listener == null) DND.error (SWT.ERROR_NULL_ARGUMENT);
+ DNDListener typedListener = new DNDListener (listener);
+ typedListener.dndWidget = this;
+ addListener (DND.DragStart, typedListener);
+ addListener (DND.DragSetData, typedListener);
+ addListener (DND.DragEnd, typedListener);
+}
+
+protected void checkSubclass () {
+ String name = getClass().getName ();
+ String validName = DragSource.class.getName();
+ if (!validName.equals(name)) {
+ DND.error (SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+
+void drag(Event dragEvent) {
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.x = dragEvent.x;
+ event.y = dragEvent.y;
+ event.time = dragEvent.time;
+ event.doit = true;
+ notifyListeners(DND.DragStart, event);
+ if (!event.doit || transferAgents == null || transferAgents.length == 0) return;
+
+ int[] theDrag = new int[1];
+ if (OS.NewDrag(theDrag) != OS.noErr) {
+ event = new DNDEvent();
+ event.widget = this;
+ event.time = (int)System.currentTimeMillis();
+ event.doit = false;
+ event.detail = DND.DROP_NONE;
+ notifyListeners(DND.DragEnd, event);
+ return;
+ }
+
+ Point pt = new Point();
+ OS.GetGlobalMouse (pt);
+
+ for (int i = 0; i < transferAgents.length; i++) {
+ Transfer transfer = transferAgents[i];
+ if (transfer != null) {
+ int[] types = transfer.getTypeIds();
+ if (transfer instanceof FileTransfer) {
+ TransferData transferData = new TransferData();
+ transferData.type = types[0];
+ DNDEvent event2 = new DNDEvent();
+ event2.widget = this;
+ event2.time = (int)System.currentTimeMillis();
+ event2.dataType = transferData;
+ notifyListeners(DND.DragSetData, event2);
+ if (event2.data != null) {
+ for (int j = 0; j < types.length; j++) {
+ transferData.type = types[j];
+ transfer.javaToNative(event2.data, transferData);
+ if (transferData.result == OS.noErr) {
+ for (int k = 0; k < transferData.data.length; k++) {
+ byte[] datum = transferData.data[k];
+ OS.AddDragItemFlavor(theDrag[0], 1 + k, types[j], datum, datum.length, 0);
+ }
+ }
+ }
+ }
+ } else {
+ for (int j = 0; j < types.length; j++) {
+ OS.AddDragItemFlavor(theDrag[0], 1, types[j], null, 0, 0);
+ }
+ }
+ }
+ }
+
+ OS.SetDragSendProc(theDrag[0], DragSendDataProc.getAddress(), control.handle);
+
+ int theRegion = 0;
+ Image newImage = null;
+ try {
+ theRegion = OS.NewRgn();
+ OS.SetRectRgn(theRegion, (short)(pt.h), (short)(pt.v), (short)(pt.h+20), (short)(pt.v+20));
+
+ int operations = opToOsOp(getStyle());
+ //set operations twice - local and not local
+ OS.SetDragAllowableActions(theDrag[0], operations, true);
+ OS.SetDragAllowableActions(theDrag[0], operations, false);
+
+ Image image = event.image;
+ if (image != null) {
+ CGPoint imageOffsetPt = new CGPoint();
+ imageOffsetPt.x = 0;
+ imageOffsetPt.y = 0;
+ /*
+ * Bug in the Macintosh. For some reason, it seems that SetDragImageWithCGImage()
+ * expects an image with the alpha, otherwise the image does not draw. The fix is
+ * to make sure that the image has an alpha by creating a new image with alpha
+ * when necessary.
+ */
+ if (OS.CGImageGetAlphaInfo(image.handle) == OS.kCGImageAlphaNoneSkipFirst) {
+ ImageData data = image.getImageData();
+ data.alpha = 0xFF;
+ newImage = new Image(image.getDevice(), data);
+ image = newImage;
+ }
+ OS.SetDragImageWithCGImage(theDrag[0], image.handle, imageOffsetPt, 0);
+ }
+ EventRecord theEvent = new EventRecord();
+ theEvent.message = OS.kEventMouseMoved;
+ theEvent.modifiers = (short)OS.GetCurrentEventKeyModifiers();
+ theEvent.what = (short)OS.osEvt;
+ theEvent.where_h = pt.h;
+ theEvent.where_v = pt.v;
+ int result = OS.TrackDrag(theDrag[0], theEvent, theRegion);
+ int operation = DND.DROP_NONE;
+ if (result == OS.noErr) {
+ int[] outAction = new int[1];
+ OS.GetDragDropAction(theDrag[0], outAction);
+ operation = osOpToOp(outAction[0]);
+ }
+ event = new DNDEvent();
+ event.widget = this;
+ event.time = (int)System.currentTimeMillis();
+ event.doit = result == OS.noErr;
+ event.detail = operation;
+ notifyListeners(DND.DragEnd, event);
+ } finally {
+ if (theRegion != 0) OS.DisposeRgn(theRegion);
+ if (newImage != null) newImage.dispose();
+ }
+ OS.DisposeDrag(theDrag[0]);
+}
+
+int dragSendDataProc(int theType, int dragSendRefCon, int theItemRef, int theDrag) {
+ if (theType == 0) return OS.badDragFlavorErr;
+ TransferData transferData = new TransferData();
+ transferData.type = theType;
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.time = (int)System.currentTimeMillis();
+ event.dataType = transferData;
+ notifyListeners(DND.DragSetData, event);
+ Transfer transfer = null;
+ for (int i = 0; i < transferAgents.length; i++) {
+ Transfer transferAgent = transferAgents[i];
+ if (transferAgent != null && transferAgent.isSupportedType(transferData)) {
+ transfer = transferAgent;
+ break;
+ }
+ }
+ if (transfer == null) return OS.badDragFlavorErr;
+ transfer.javaToNative(event.data, transferData);
+ if (transferData.result != OS.noErr) return transferData.result;
+ // Except for FileTransfer (see #drag), only one item can be transferred
+ // in a Drag operation
+ byte[] datum = transferData.data[0];
+ if (datum == null) return OS.cantGetFlavorErr;
+ return OS.SetDragItemFlavorData(theDrag, theItemRef, theType, datum, datum.length, 0);
+}
+
+/**
+ * Returns the Control which is registered for this DragSource. This is the control that the
+ * user clicks in to initiate dragging.
+ *
+ * @return the Control which is registered for this DragSource
+ */
+public Control getControl () {
+ return control;
+}
+
+/**
+ * Returns the drag effect that is registered for this DragSource. This drag
+ * effect will be used during a drag and drop operation.
+ *
+ * @return the drag effect that is registered for this DragSource
+ *
+ * @since 3.3
+ */
+public DragSourceEffect getDragSourceEffect() {
+ return dragEffect;
+}
+
+/**
+ * Returns the list of data types that can be transferred by this DragSource.
+ *
+ * @return the list of data types that can be transferred by this DragSource
+ */
+public Transfer[] getTransfer(){
+ return transferAgents;
+}
+
+void onDispose() {
+ if (control == null)
+ return;
+ if (controlListener != null) {
+ control.removeListener(SWT.Dispose, controlListener);
+ control.removeListener(SWT.DragDetect, controlListener);
+ }
+ controlListener = null;
+ control.setData(DND.DRAG_SOURCE_KEY, null);
+ control = null;
+ transferAgents = null;
+}
+
+int opToOsOp(int operation) {
+ int osOperation = 0;
+ if ((operation & DND.DROP_COPY) != 0){
+ osOperation |= OS.kDragActionCopy;
+ }
+ if ((operation & DND.DROP_LINK) != 0) {
+ osOperation |= OS.kDragActionAlias;
+ }
+ if ((operation & DND.DROP_MOVE) != 0) {
+ osOperation |= OS.kDragActionMove;
+ }
+ if ((operation & DND.DROP_TARGET_MOVE) != 0) {
+ osOperation |= OS.kDragActionDelete;
+ }
+ return osOperation;
+}
+
+int osOpToOp(int osOperation){
+ int operation = 0;
+ if ((osOperation & OS.kDragActionCopy) != 0){
+ operation |= DND.DROP_COPY;
+ }
+ if ((osOperation & OS.kDragActionAlias) != 0) {
+ operation |= DND.DROP_LINK;
+ }
+ if ((osOperation & OS.kDragActionDelete) != 0) {
+ operation |= DND.DROP_TARGET_MOVE;
+ }
+ if ((osOperation & OS.kDragActionMove) != 0) {
+ operation |= DND.DROP_MOVE;
+ }
+ if (osOperation == OS.kDragActionAll) {
+ operation = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
+ }
+ return operation;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a drag and drop operation is in progress.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DragSourceListener
+ * @see #addDragListener
+ */
+public void removeDragListener(DragSourceListener listener) {
+ if (listener == null) DND.error (SWT.ERROR_NULL_ARGUMENT);
+ removeListener (DND.DragStart, listener);
+ removeListener (DND.DragSetData, listener);
+ removeListener (DND.DragEnd, listener);
+}
+
+/**
+ * Specifies the drag effect for this DragSource. This drag effect will be
+ * used during a drag and drop operation.
+ *
+ * @param effect the drag effect that is registered for this DragSource
+ *
+ * @since 3.3
+ */
+public void setDragSourceEffect(DragSourceEffect effect) {
+ dragEffect = effect;
+}
+/**
+ * Specifies the list of data types that can be transferred by this DragSource.
+ * The application must be able to provide data to match each of these types when
+ * a successful drop has occurred.
+ *
+ * @param transferAgents a list of Transfer objects which define the types of data that can be
+ * dragged from this source
+ */
+public void setTransfer(Transfer[] transferAgents){
+ this.transferAgents = transferAgents;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/DropTarget.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/DropTarget.java
new file mode 100644
index 0000000000..24918055dd
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/DropTarget.java
@@ -0,0 +1,769 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.carbon.*;
+
+/**
+ *
+ * Class <code>DropTarget</code> defines the target object for a drag and drop transfer.
+ *
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ *
+ * <p>This class identifies the <code>Control</code> over which the user must position the cursor
+ * in order to drop the data being transferred. It also specifies what data types can be dropped on
+ * this control and what operations can be performed. You may have several DropTragets in an
+ * application but there can only be a one to one mapping between a <code>Control</code> and a <code>DropTarget</code>.
+ * The DropTarget can receive data from within the same application or from other applications
+ * (such as text dragged from a text editor like Word).</p>
+ *
+ * <code><pre>
+ * int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
+ * Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
+ * DropTarget target = new DropTarget(label, operations);
+ * target.setTransfer(types);
+ * </code></pre>
+ *
+ * <p>The application is notified of data being dragged over this control and of when a drop occurs by
+ * implementing the interface <code>DropTargetListener</code> which uses the class
+ * <code>DropTargetEvent</code>. The application can modify the type of drag being performed
+ * on this Control at any stage of the drag by modifying the <code>event.detail</code> field or the
+ * <code>event.currentDataType</code> field. When the data is dropped, it is the responsibility of
+ * the application to copy this data for its own purposes.
+ *
+ * <code><pre>
+ * target.addDropListener (new DropTargetListener() {
+ * public void dragEnter(DropTargetEvent event) {};
+ * public void dragOver(DropTargetEvent event) {};
+ * public void dragLeave(DropTargetEvent event) {};
+ * public void dragOperationChanged(DropTargetEvent event) {};
+ * public void dropAccept(DropTargetEvent event) {}
+ * public void drop(DropTargetEvent event) {
+ * // A drop has occurred, copy over the data
+ * if (event.data == null) { // no data to copy, indicate failure in event.detail
+ * event.detail = DND.DROP_NONE;
+ * return;
+ * }
+ * label.setText ((String) event.data); // data copied to label text
+ * }
+ * });
+ * </pre></code>
+ *
+ * <dl>
+ * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
+ * <dt><b>Events</b></dt> <dd>DND.DragEnter, DND.DragLeave, DND.DragOver, DND.DragOperationChanged,
+ * DND.DropAccept, DND.Drop </dd>
+ * </dl>
+ */
+public class DropTarget extends Widget {
+
+ Control control;
+ Listener controlListener;
+ Transfer[] transferAgents = new Transfer[0];
+ DropTargetEffect dropEffect;
+ int feedback = DND.FEEDBACK_NONE;
+
+ // Track application selections
+ TransferData selectedDataType;
+ int selectedOperation;
+
+ // workaround - There is no event for "operation changed" so track operation based on key state
+ int keyOperation = -1;
+
+ // workaround - Simulate events when mouse is not moving
+ long dragOverStart;
+ Runnable dragOverHeartbeat;
+ DNDEvent dragOverEvent;
+
+ // workaround - OS events are relative to the application, not the control.
+ // Track which control is the current target to determine when drag and
+ // drop enters or leaves a widget.
+ static DropTarget CurrentDropTarget = null;
+
+ static final String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$
+ static final int DRAGOVER_HYSTERESIS = 50;
+
+ static Callback DragTrackingHandler;
+ static Callback DragReceiveHandler;
+
+ static {
+ DragTrackingHandler = new Callback(DropTarget.class, "DragTrackingHandler", 4); //$NON-NLS-1$
+ int dragTrackingHandlerAddress = DragTrackingHandler.getAddress();
+ if (dragTrackingHandlerAddress == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ DragReceiveHandler = new Callback(DropTarget.class, "DragReceiveHandler", 3); //$NON-NLS-1$
+ int dragReceiveHandlerAddress = DragReceiveHandler.getAddress();
+ if (dragReceiveHandlerAddress == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ OS.InstallTrackingHandler(dragTrackingHandlerAddress, 0, null);
+ OS.InstallReceiveHandler(dragReceiveHandlerAddress, 0, null);
+ }
+
+/**
+ * Creates a new <code>DropTarget</code> to allow data to be dropped on the specified
+ * <code>Control</code>.
+ * Creating an instance of a DropTarget may cause system resources to be allocated
+ * depending on the platform. It is therefore mandatory that the DropTarget instance
+ * be disposed when no longer required.
+ *
+ * @param control the <code>Control</code> over which the user positions the cursor to drop the data
+ * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
+ * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_CANNOT_INIT_DROP - unable to initiate drop target; this will occur if more than one
+ * drop target is created for a control or if the operating system will not allow the creation
+ * of the drop target</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_INIT_DROP should be an SWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ *
+ * @see Widget#dispose
+ * @see DropTarget#checkSubclass
+ * @see DND#DROP_NONE
+ * @see DND#DROP_COPY
+ * @see DND#DROP_MOVE
+ * @see DND#DROP_LINK
+ */
+public DropTarget(Control control, int style) {
+ super(control, checkStyle(style));
+ this.control = control;
+ if (DragTrackingHandler == null || DragTrackingHandler == null) {
+ DND.error(DND.ERROR_CANNOT_INIT_DROP);
+ }
+ if (control.getData(DND.DROP_TARGET_KEY) != null) {
+ DND.error(DND.ERROR_CANNOT_INIT_DROP);
+ }
+ control.setData(DND.DROP_TARGET_KEY, this);
+
+ controlListener = new Listener () {
+ public void handleEvent (Event event) {
+ if (!DropTarget.this.isDisposed()) {
+ DropTarget.this.dispose();
+ }
+ }
+ };
+ control.addListener (SWT.Dispose, controlListener);
+
+ this.addListener(SWT.Dispose, new Listener() {
+ public void handleEvent (Event event) {
+ onDispose();
+ }
+ });
+
+ Object effect = control.getData(DEFAULT_DROP_TARGET_EFFECT);
+ if (effect instanceof DropTargetEffect) {
+ dropEffect = (DropTargetEffect) effect;
+ } else if (control instanceof Table) {
+ dropEffect = new TableDropTargetEffect((Table) control);
+ } else if (control instanceof Tree) {
+ dropEffect = new TreeDropTargetEffect((Tree) control);
+ }
+
+ dragOverHeartbeat = new Runnable() {
+ public void run() {
+ Control control = DropTarget.this.control;
+ if (control == null || control.isDisposed() || dragOverStart == 0) return;
+ long time = System.currentTimeMillis();
+ int delay = DRAGOVER_HYSTERESIS;
+ if (time < dragOverStart) {
+ delay = (int)(dragOverStart - time);
+ } else {
+ int allowedOperations = dragOverEvent.operations;
+ TransferData[] allowedTypes = dragOverEvent.dataTypes;
+ //pass a copy of data types in to listeners in case application modifies it
+ TransferData[] dataTypes = new TransferData[allowedTypes.length];
+ System.arraycopy(allowedTypes, 0, dataTypes, 0, dataTypes.length);
+
+ DNDEvent event = new DNDEvent();
+ event.widget = dragOverEvent.widget;
+ event.x = dragOverEvent.x;
+ event.y = dragOverEvent.y;
+ event.time = (int)time;
+ event.feedback = DND.FEEDBACK_SELECT;
+ event.dataTypes = dataTypes;
+ event.dataType = selectedDataType;
+ event.operations = dragOverEvent.operations;
+ event.detail = selectedOperation;
+ if (dropEffect != null) {
+ event.item = dropEffect.getItem(event.x, event.y);
+ }
+ selectedDataType = null;
+ selectedOperation = DND.DROP_NONE;
+ notifyListeners(DND.DragOver, event);
+ if (event.dataType != null) {
+ for (int i = 0; i < allowedTypes.length; i++) {
+ if (allowedTypes[i].type == event.dataType.type) {
+ selectedDataType = event.dataType;
+ break;
+ }
+ }
+ }
+ if (selectedDataType != null && (event.detail & allowedOperations) != 0) {
+ selectedOperation = event.detail;
+ }
+ }
+ control = DropTarget.this.control;
+ if (control == null || control.isDisposed()) return;
+ control.getDisplay().timerExec(delay, dragOverHeartbeat);
+ }
+ };
+}
+
+static int checkStyle (int style) {
+ if (style == SWT.NONE) return DND.DROP_MOVE;
+ return style;
+}
+
+static int DragReceiveHandler(int theWindow, int handlerRefCon, int theDrag) {
+ DropTarget target = FindDropTarget(theWindow, theDrag);
+ if (target == null) return OS.noErr;
+ return target.dragReceiveHandler(theWindow, handlerRefCon, theDrag);
+}
+
+static int DragTrackingHandler(int message, int theWindow, int handlerRefCon, int theDrag) {
+ if (message == OS.kDragTrackingLeaveHandler || message == OS.kDragTrackingEnterHandler) {
+ CurrentDropTarget = null;
+ return OS.noErr;
+ }
+ DropTarget target = FindDropTarget(theWindow, theDrag);
+ if (CurrentDropTarget != null) {
+ if (target == null || CurrentDropTarget.control.handle != target.control.handle) {
+ CurrentDropTarget.dragTrackingHandler(OS.kDragTrackingLeaveWindow, theWindow, handlerRefCon, theDrag);
+ CurrentDropTarget = target;
+ message = OS.kDragTrackingEnterWindow;
+ }
+ } else {
+ CurrentDropTarget = target;
+ message = OS.kDragTrackingEnterWindow;
+ }
+ if (target == null) return OS.noErr;
+ return target.dragTrackingHandler(message, theWindow, handlerRefCon, theDrag);
+}
+
+static DropTarget FindDropTarget(int theWindow, int theDrag) {
+ Display display = Display.findDisplay(Thread.currentThread());
+ if (display == null || display.isDisposed()) return null;
+ Point mouse = new Point();
+ OS.GetDragMouse(theDrag, mouse, null);
+ int[] theRoot = new int[1];
+ OS.GetRootControl(theWindow, theRoot);
+ int[] theControl = new int[1];
+ Rect rect = new Rect();
+ OS.GetWindowBounds (theWindow, (short) OS.kWindowContentRgn, rect);
+ CGPoint inPoint = new CGPoint();
+ inPoint.x = mouse.h - rect.left;
+ inPoint.y = mouse.v - rect.top;
+ OS.HIViewGetSubviewHit(theRoot[0], inPoint, true, theControl);
+ if (!OS.IsControlEnabled(theControl[0])) return null;
+ Widget widget = display.findWidget(theControl[0]);
+ if (widget == null) return null;
+ return (DropTarget)widget.getData(DND.DROP_TARGET_KEY);
+}
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when a drag and drop operation is in progress, by sending
+ * it one of the messages defined in the <code>DropTargetListener</code>
+ * interface.
+ *
+ * <p><ul>
+ * <li><code>dragEnter</code> is called when the cursor has entered the drop target boundaries
+ * <li><code>dragLeave</code> is called when the cursor has left the drop target boundaries and just before
+ * the drop occurs or is cancelled.
+ * <li><code>dragOperationChanged</code> is called when the operation being performed has changed
+ * (usually due to the user changing the selected modifier key(s) while dragging)
+ * <li><code>dragOver</code> is called when the cursor is moving over the drop target
+ * <li><code>dropAccept</code> is called just before the drop is performed. The drop target is given
+ * the chance to change the nature of the drop or veto the drop by setting the <code>event.detail</code> field
+ * <li><code>drop</code> is called when the data is being dropped
+ * </ul></p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DropTargetListener
+ * @see #removeDropListener
+ * @see DropTargetEvent
+ */
+public void addDropListener(DropTargetListener listener) {
+ if (listener == null) DND.error (SWT.ERROR_NULL_ARGUMENT);
+ DNDListener typedListener = new DNDListener (listener);
+ typedListener.dndWidget = this;
+ addListener (DND.DragEnter, typedListener);
+ addListener (DND.DragLeave, typedListener);
+ addListener (DND.DragOver, typedListener);
+ addListener (DND.DragOperationChanged, typedListener);
+ addListener (DND.Drop, typedListener);
+ addListener (DND.DropAccept, typedListener);
+}
+
+protected void checkSubclass () {
+ String name = getClass().getName ();
+ String validName = DropTarget.class.getName();
+ if (!validName.equals(name)) {
+ DND.error (SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+
+int dragReceiveHandler(int theWindow, int handlerRefCon, int theDrag) {
+ updateDragOverHover(0, null);
+ if (keyOperation == -1) return OS.dragNotAcceptedErr;
+
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.time = (int)System.currentTimeMillis();
+ event.detail = DND.DROP_NONE;
+ notifyListeners(DND.DragLeave, event);
+
+ event = new DNDEvent();
+ if (!setEventData(theDrag, event)) {
+ return OS.dragNotAcceptedErr;
+ }
+
+ keyOperation = -1;
+ int allowedOperations = event.operations;
+ TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+ System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, event.dataTypes.length);
+ event.dataType = selectedDataType;
+ event.detail = selectedOperation;
+ selectedDataType = null;
+ selectedOperation = DND.DROP_NONE;
+ notifyListeners(DND.DropAccept, event);
+
+ if (event.dataType != null) {
+ for (int i = 0; i < allowedDataTypes.length; i++) {
+ if (allowedDataTypes[i].type == event.dataType.type) {
+ selectedDataType = allowedDataTypes[i];
+ break;
+ }
+ }
+ }
+ if (selectedDataType != null && (event.detail & allowedOperations) != 0) {
+ selectedOperation = event.detail;
+ }
+ if (selectedOperation == DND.DROP_NONE) {
+ // this was not a successful drop
+ return OS.dragNotAcceptedErr;
+ }
+ // ask drag source for dropped data
+ byte[][] data = new byte[0][];
+ // locate all the items with data of the desired type
+ short[] numItems = new short[1];
+ OS.CountDragItems(theDrag, numItems);
+ for (short i = 0; i < numItems[0]; i++) {
+ int[] theItemRef = new int[1];
+ OS.GetDragItemReferenceNumber(theDrag, (short) (i+1), theItemRef);
+ int[] size = new int[1];
+ OS.GetFlavorDataSize(theDrag, theItemRef[0], selectedDataType.type, size);
+ if (size[0] > 0) {
+ byte[] buffer = new byte[size[0]];
+ OS.GetFlavorData(theDrag, theItemRef[0], selectedDataType.type, buffer, size, 0);
+ byte[][] newData = new byte[data.length + 1][];
+ System.arraycopy(data, 0, newData, 0, data.length);
+ newData[data.length] = buffer;
+ data = newData;
+ }
+ }
+ // Get Data in a Java format
+ Object object = null;
+ for (int i = 0; i < transferAgents.length; i++) {
+ Transfer transfer = transferAgents[i];
+ if (transfer != null && transfer.isSupportedType(selectedDataType)) {
+ selectedDataType.data = data;
+ object = transfer.nativeToJava(selectedDataType);
+ break;
+ }
+ }
+
+ if (object == null) {
+ selectedOperation = DND.DROP_NONE;
+ }
+
+ event.dataType = selectedDataType;
+ event.detail = selectedOperation;
+ event.data = object;
+ notifyListeners(DND.Drop, event);
+ selectedOperation = DND.DROP_NONE;
+ if ((allowedOperations & event.detail) == event.detail) {
+ selectedOperation = event.detail;
+ }
+ //notify source of action taken
+ int action = opToOsOp(selectedOperation);
+ OS.SetDragDropAction(theDrag, action);
+ return (selectedOperation == DND.DROP_NONE) ? OS.dragNotAcceptedErr : OS.noErr;
+}
+
+int dragTrackingHandler(int message, int theWindow, int handlerRefCon, int theDrag) {
+
+ if (message == OS.kDragTrackingLeaveWindow) {
+ updateDragOverHover(0, null);
+ OS.SetThemeCursor(OS.kThemeArrowCursor);
+ if (keyOperation == -1) return OS.dragNotAcceptedErr;
+ keyOperation = -1;
+
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.time = (int)System.currentTimeMillis();
+ event.detail = DND.DROP_NONE;
+ notifyListeners(DND.DragLeave, event);
+ return OS.noErr;
+ }
+
+ int oldKeyOperation = keyOperation;
+
+ if (message == OS.kDragTrackingEnterWindow) {
+ selectedDataType = null;
+ selectedOperation = 0;
+ }
+
+ DNDEvent event = new DNDEvent();
+ if (!setEventData(theDrag, event)) {
+ keyOperation = -1;
+ OS.SetThemeCursor(OS.kThemeNotAllowedCursor);
+ return OS.dragNotAcceptedErr;
+ }
+
+ int allowedOperations = event.operations;
+ TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+ System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+
+ switch (message) {
+ case OS.kDragTrackingEnterWindow:
+ event.type = DND.DragEnter;
+ break;
+ case OS.kDragTrackingInWindow:
+ if (keyOperation == oldKeyOperation) {
+ event.type = DND.DragOver;
+ event.dataType = selectedDataType;
+ event.detail = selectedOperation;
+ }else {
+ event.type = DND.DragOperationChanged;
+ event.dataType = selectedDataType;
+ }
+ break;
+ }
+
+ updateDragOverHover(DRAGOVER_HYSTERESIS, event);
+ selectedDataType = null;
+ selectedOperation = DND.DROP_NONE;
+ notifyListeners(event.type, event);
+
+ if (event.detail == DND.DROP_DEFAULT) {
+ event.detail = (allowedOperations & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+ }
+
+ if (event.dataType != null) {
+ for (int i = 0; i < allowedDataTypes.length; i++) {
+ if (allowedDataTypes[i].type == event.dataType.type) {
+ selectedDataType = allowedDataTypes[i];
+ break;
+ }
+ }
+ }
+
+ if (selectedDataType != null && (allowedOperations & event.detail) != 0) {
+ selectedOperation = event.detail;
+ }
+
+ OS.SetDragDropAction(theDrag, opToOsOp(selectedOperation));
+
+ switch (selectedOperation) {
+ case DND.DROP_COPY:
+ OS.SetThemeCursor(OS.kThemeCopyArrowCursor);
+ break;
+ case DND.DROP_LINK:
+ OS.SetThemeCursor(OS.kThemeAliasArrowCursor);
+ break;
+ case DND.DROP_MOVE:
+ OS.SetThemeCursor(OS.kThemeArrowCursor);
+ break;
+ default:
+ OS.SetThemeCursor(OS.kThemeNotAllowedCursor);
+ }
+
+ if (message == OS.kDragTrackingEnterWindow) {
+ dragOverHeartbeat.run();
+ }
+ return OS.noErr;
+}
+
+/**
+ * Returns the Control which is registered for this DropTarget. This is the control over which the
+ * user positions the cursor to drop the data.
+ *
+ * @return the Control which is registered for this DropTarget
+ */
+public Control getControl () {
+ return control;
+}
+
+/**
+ * Returns the drop effect for this DropTarget. This drop effect will be
+ * used during a drag and drop to display the drag under effect on the
+ * target widget.
+ *
+ * @return the drop effect that is registered for this DropTarget
+ *
+ * @since 3.3
+ */
+public DropTargetEffect getDropTargetEffect() {
+ return dropEffect;
+}
+
+int getOperationFromKeyState(int theDrag) {
+ short[] modifiers = new short[1];
+ OS.GetDragModifiers(theDrag, modifiers, null, null);
+ boolean option = (modifiers[0] & OS.optionKey) == OS.optionKey;
+ boolean command = (modifiers[0] & OS.cmdKey) == OS.cmdKey;
+ if (option && command) return DND.DROP_LINK;
+ if (option) return DND.DROP_COPY;
+ if (command) return DND.DROP_MOVE;
+ return DND.DROP_DEFAULT;
+}
+
+/**
+ * Returns a list of the data types that can be transferred to this DropTarget.
+ *
+ * @return a list of the data types that can be transferred to this DropTarget
+ */
+public Transfer[] getTransfer() {
+ return transferAgents;
+}
+
+void onDispose () {
+ if (control == null)
+ return;
+ if (controlListener != null)
+ control.removeListener(SWT.Dispose, controlListener);
+ controlListener = null;
+ control.setData(DND.DROP_TARGET_KEY, null);
+ transferAgents = null;
+ control = null;
+}
+
+int opToOsOp(int operation) {
+ int osOperation = 0;
+ if ((operation & DND.DROP_COPY) != 0){
+ osOperation |= OS.kDragActionCopy;
+ }
+ if ((operation & DND.DROP_LINK) != 0) {
+ osOperation |= OS.kDragActionAlias;
+ }
+ if ((operation & DND.DROP_MOVE) != 0) {
+ osOperation |= OS.kDragActionMove;
+ }
+ return osOperation;
+}
+
+int osOpToOp(int osOperation){
+ int operation = 0;
+ if ((osOperation & OS.kDragActionCopy) != 0){
+ operation |= DND.DROP_COPY;
+ }
+ if ((osOperation & OS.kDragActionAlias) != 0) {
+ operation |= DND.DROP_LINK;
+ }
+ if ((osOperation & OS.kDragActionMove) != 0) {
+ operation |= DND.DROP_MOVE;
+ }
+ if (osOperation == OS.kDragActionAll) {
+ operation = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
+ }
+ return operation;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a drag and drop operation is in progress.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DropTargetListener
+ * @see #addDropListener
+ */
+public void removeDropListener(DropTargetListener listener) {
+ if (listener == null) DND.error (SWT.ERROR_NULL_ARGUMENT);
+ removeListener (DND.DragEnter, listener);
+ removeListener (DND.DragLeave, listener);
+ removeListener (DND.DragOver, listener);
+ removeListener (DND.DragOperationChanged, listener);
+ removeListener (DND.Drop, listener);
+ removeListener (DND.DropAccept, listener);
+}
+
+/**
+ * Specifies the drop effect for this DropTarget. This drop effect will be
+ * used during a drag and drop to display the drag under effect on the
+ * target widget.
+ *
+ * @param effect the drop effect that is registered for this DropTarget
+ *
+ * @since 3.3
+ */
+public void setDropTargetEffect(DropTargetEffect effect) {
+ dropEffect = effect;
+}
+
+boolean setEventData(int theDrag, DNDEvent event) {
+ if (theDrag == 0) return false;
+
+ // get allowed operations
+ int style = getStyle();
+ int[] outActions = new int[1];
+ OS.GetDragAllowableActions(theDrag, outActions);
+ int operations = osOpToOp(outActions[0]) & style;
+ if (operations == DND.DROP_NONE) return false;
+
+ //get current operation
+ int operation = getOperationFromKeyState(theDrag);
+ keyOperation = operation;
+ if (operation == DND.DROP_DEFAULT) {
+ if ((style & DND.DROP_DEFAULT) == 0) {
+ operation = (operations & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+ }
+ } else {
+ if ((operation & operations) == 0) operation = DND.DROP_NONE;
+ }
+
+ // get allowed transfer types
+ short[] numItems = new short[1];
+ OS.CountDragItems(theDrag, numItems);
+ int[] flavors = new int[10];
+ int index = -1;
+ //Get a unique list of flavors
+ for (short i = 0; i < numItems[0]; i++) {
+ int[] theItemRef = new int[1];
+ OS.GetDragItemReferenceNumber(theDrag, (short) (i+1), theItemRef);
+ short[] numFlavors = new short[1];
+ OS.CountDragItemFlavors(theDrag, theItemRef[0], numFlavors);
+ int[] theType = new int[1];
+ for (int j = 0; j < numFlavors[0]; j++) {
+ theType[0] = 0;
+ if (OS.GetFlavorType(theDrag, theItemRef[0], (short) (j+1), theType) == OS.noErr) {
+ boolean unique = true;
+ for (int k = 0; k < flavors.length; k++) {
+ if (flavors[k] == theType[0]) {
+ unique = false;
+ break;
+ }
+ }
+ if (unique) {
+ if (index == flavors.length - 1) {
+ int[] temp = new int[flavors.length + 10];
+ System.arraycopy(flavors, 0, temp, 0, flavors.length);
+ flavors = temp;
+ }
+ flavors[++index] = theType[0];
+ }
+ }
+ }
+ }
+ if (index == -1) return false;
+
+ TransferData[] dataTypes = new TransferData[index+1];
+ index = -1;
+ for (int i = 0; i < dataTypes.length; i++) {
+ if (flavors[i] != 0) {
+ TransferData data = new TransferData();
+ data.type = flavors[i];
+ for (int j = 0; j < transferAgents.length; j++) {
+ Transfer transfer = transferAgents[j];
+ if (transfer != null && transfer.isSupportedType(data)) {
+ dataTypes[++index] = data;
+ break;
+ }
+ }
+ }
+ }
+ if (index == -1) return false;
+
+ if (index < dataTypes.length - 1) {
+ TransferData[] temp = new TransferData[index + 1];
+ System.arraycopy(dataTypes, 0, temp, 0, index + 1);
+ dataTypes = temp;
+ }
+
+ Point mouse = new Point();
+ OS.GetDragMouse(theDrag, mouse, null);
+
+ event.widget = this;
+ event.x = mouse.h;
+ event.y = mouse.v;
+ event.time = (int)System.currentTimeMillis();
+ event.feedback = DND.FEEDBACK_SELECT;
+ event.dataTypes = dataTypes;
+ event.dataType = dataTypes[0];
+ event.operations = operations;
+ event.detail = operation;
+ if (dropEffect != null) {
+ event.item = dropEffect.getItem(event.x, event.y);
+ }
+
+ return true;
+}
+
+/**
+ * Specifies the data types that can be transferred to this DropTarget. If data is
+ * being dragged that does not match one of these types, the drop target will be notified of
+ * the drag and drop operation but the currentDataType will be null and the operation
+ * will be DND.NONE.
+ *
+ * @param transferAgents a list of Transfer objects which define the types of data that can be
+ * dropped on this target
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if transferAgents is null</li>
+ * </ul>
+ */
+public void setTransfer(Transfer[] transferAgents){
+ if (transferAgents == null) DND.error(SWT.ERROR_NULL_ARGUMENT);
+ this.transferAgents = transferAgents;
+}
+
+void updateDragOverHover(long delay, DNDEvent event) {
+ if (delay == 0) {
+ dragOverStart = 0;
+ dragOverEvent = null;
+ return;
+ }
+ dragOverStart = System.currentTimeMillis() + delay;
+ if (dragOverEvent == null) dragOverEvent = new DNDEvent();
+ dragOverEvent.x = event.x;
+ dragOverEvent.y = event.y;
+ dragOverEvent.dataTypes = event.dataTypes;
+ dragOverEvent.operations = event.operations;
+ dragOverEvent.dataType = event.dataType;
+ dragOverEvent.detail = event.detail;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/FileTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/FileTransfer.java
new file mode 100644
index 0000000000..91ed4251cd
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/FileTransfer.java
@@ -0,0 +1,196 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Outhink - support for typeFileURL
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import java.io.*;
+import org.eclipse.swt.internal.carbon.*;
+
+/**
+ * The class <code>FileTransfer</code> provides a platform specific mechanism
+ * for converting a list of files represented as a java <code>String[]</code> to a
+ * platform specific representation of the data and vice versa.
+ * Each <code>String</code> in the array contains the absolute path for a single
+ * file or directory.
+ * See <code>Transfer</code> for additional information.
+ *
+ * <p>An example of a java <code>String[]</code> containing a list of files is shown
+ * below:</p>
+ *
+ * <code><pre>
+ * File file1 = new File("C:\temp\file1");
+ * File file2 = new File("C:\temp\file2");
+ * String[] fileData = new String[2];
+ * fileData[0] = file1.getAbsolutePath();
+ * fileData[1] = file2.getAbsolutePath();
+ * </code></pre>
+ */
+public class FileTransfer extends ByteArrayTransfer {
+
+ static FileTransfer _instance = new FileTransfer();
+ static final String HFS = "hfs "; //$NON-NLS-1$
+ static final String FURL = "furl"; //$NON-NLS-1$
+ static final int HFSID = registerType(HFS);
+ static final int FURLID = registerType(FURL);
+
+FileTransfer() {}
+
+/**
+ * Returns the singleton instance of the FileTransfer class.
+ *
+ * @return the singleton instance of the FileTransfer class
+ */
+public static FileTransfer getInstance () {
+ return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts a list of file names
+ * represented by a java <code>String[]</code> to a platform specific representation.
+ * Each <code>String</code> in the array contains the absolute path for a single
+ * file or directory. For additional information see
+ * <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>String[]</code> containing the file names to be
+ * converted
+ * @param transferData an empty <code>TransferData</code> object; this
+ * object will be filled in on return with the platform specific format of the data
+ */
+public void javaToNative(Object object, TransferData transferData) {
+ if (!checkFile(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ String[] files = (String[])object;
+ transferData.result = -1;
+ byte[][] data = new byte[files.length][];
+ for (int i = 0; i < data.length; i++) {
+ File file = new File(files[i]);
+ boolean isDirectory = file.isDirectory();
+ String fileName = files[i];
+ char [] chars = new char [fileName.length ()];
+ fileName.getChars (0, chars.length, chars, 0);
+ int cfstring = OS.CFStringCreateWithCharacters (OS.kCFAllocatorDefault, chars, chars.length);
+ if (cfstring == 0) return;
+ try {
+ int url = OS.CFURLCreateWithFileSystemPath(OS.kCFAllocatorDefault, cfstring, OS.kCFURLPOSIXPathStyle, isDirectory);
+ if (url == 0) return;
+ try {
+ if (transferData.type == HFSID) {
+ byte[] fsRef = new byte[80];
+ if (!OS.CFURLGetFSRef(url, fsRef)) return;
+ byte[] fsSpec = new byte[70];
+ if (OS.FSGetCatalogInfo(fsRef, 0, null, null, fsSpec, null) != OS.noErr) return;
+ byte[] hfsflavor = new byte[10 + fsSpec.length];
+ byte[] finfo = new byte[16];
+ OS.FSpGetFInfo(fsSpec, finfo);
+ System.arraycopy(finfo, 0, hfsflavor, 0, 10);
+ System.arraycopy(fsSpec, 0, hfsflavor, 10, fsSpec.length);
+ data[i] = hfsflavor;
+ }
+ if (transferData.type == FURLID) {
+ int encoding = OS.CFStringGetSystemEncoding();
+ int theData = OS.CFURLCreateData(OS.kCFAllocatorDefault, url, encoding, true);
+ if (theData == 0) return;
+ try {
+ int length = OS.CFDataGetLength(theData);
+ byte[] buffer = new byte[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFDataGetBytes(theData, range, buffer);
+ data[i] = buffer;
+ } finally {
+ OS.CFRelease(theData);
+ }
+ }
+ } finally {
+ OS.CFRelease(url);
+ }
+ } finally {
+ OS.CFRelease(cfstring);
+ }
+ }
+ transferData.data = data;
+ transferData.result = 0;
+}
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of a list of file names to a java <code>String[]</code>.
+ * Each String in the array contains the absolute path for a single file or directory.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String[]</code> containing a list of file names if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData) {
+ if (!isSupportedType(transferData) || transferData.data == null) return null;
+ if (transferData.data.length == 0) return null;
+ int count = transferData.data.length;
+ String[] fileNames = new String[count];
+ for (int i=0; i<count; i++) {
+ byte[] data = transferData.data[i];
+ int url = 0;
+ if (transferData.type == HFSID) {
+ byte[] fsspec = new byte[data.length - 10];
+ System.arraycopy(data, 10, fsspec, 0, fsspec.length);
+ byte[] fsRef = new byte[80];
+ if (OS.FSpMakeFSRef(fsspec, fsRef) != OS.noErr) return null;
+ url = OS.CFURLCreateFromFSRef(OS.kCFAllocatorDefault, fsRef);
+ if (url == 0) return null;
+ }
+ if (transferData.type == FURLID) {
+ int encoding = OS.kCFStringEncodingUTF8;
+ url = OS.CFURLCreateWithBytes(OS.kCFAllocatorDefault, data, data.length, encoding, 0);
+ if (url == 0) return null;
+ }
+ try {
+ int path = OS.CFURLCopyFileSystemPath(url, OS.kCFURLPOSIXPathStyle);
+ if (path == 0) return null;
+ try {
+ int length = OS.CFStringGetLength(path);
+ if (length == 0) return null;
+ char[] buffer= new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(path, range, buffer);
+ fileNames[i] = new String(buffer);
+ } finally {
+ OS.CFRelease(path);
+ }
+ } finally {
+ OS.CFRelease(url);
+ }
+ }
+ return fileNames;
+}
+
+protected int[] getTypeIds(){
+ return new int[] {FURLID, HFSID};
+}
+
+protected String[] getTypeNames(){
+ return new String[] {FURL, HFS};
+}
+
+boolean checkFile(Object object) {
+ if (object == null || !(object instanceof String[]) || ((String[])object).length == 0) return false;
+ String[] strings = (String[])object;
+ for (int i = 0; i < strings.length; i++) {
+ if (strings[i] == null || strings[i].length() == 0) return false;
+ }
+ return true;
+}
+
+protected boolean validate(Object object) {
+ return checkFile(object);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/HTMLTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/HTMLTransfer.java
new file mode 100644
index 0000000000..64e81d2fbb
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/HTMLTransfer.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.internal.carbon.OS;
+
+/**
+ * The class <code>HTMLTransfer</code> provides a platform specific mechanism
+ * for converting text in HTML format represented as a java <code>String</code>
+ * to a platform specific representation of the data and vice versa. See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p>An example of a java <code>String</code> containing HTML text is shown
+ * below:</p>
+ *
+ * <code><pre>
+ * String htmlData = "<p>This is a paragraph of text.</p>";
+ * </code></pre>
+ */
+public class HTMLTransfer extends ByteArrayTransfer {
+
+ static HTMLTransfer _instance = new HTMLTransfer();
+ static final String HTML = "HTML"; //$NON-NLS-1$
+ static final int HTMLID = registerType(HTML);
+
+HTMLTransfer() {}
+
+/**
+ * Returns the singleton instance of the HTMLTransfer class.
+ *
+ * @return the singleton instance of the HTMLTransfer class
+ */
+public static HTMLTransfer getInstance () {
+ return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts HTML-formatted text
+ * represented by a java <code>String</code> to a platform specific representation.
+ * For additional information see <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>String</code> containing HTML text
+ * @param transferData an empty <code>TransferData</code> object; this
+ * object will be filled in on return with the platform specific format of the data
+ */
+public void javaToNative (Object object, TransferData transferData){
+ if (!checkHTML(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ String string = (String)object;
+ int count = string.length();
+ char[] chars = new char[count];
+ string.getChars(0, count, chars, 0);
+ byte[] buffer = new byte[chars.length * 2];
+ OS.memmove(buffer, chars, buffer.length);
+ transferData.data = new byte[1][];
+ transferData.data[0] = buffer;
+ transferData.result = OS.noErr;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of HTML text to a java <code>String</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String</code> containing HTML text if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.data == null) return null;
+ if (transferData.data.length == 0 || transferData.data[0].length == 0) return null;
+ byte[] buffer = transferData.data[0];
+ char[] chars = new char[(buffer.length + 1) / 2];
+ OS.memmove(chars, buffer, buffer.length);
+ return new String(chars);
+}
+
+protected int[] getTypeIds() {
+ return new int[] {HTMLID};
+}
+
+protected String[] getTypeNames() {
+ return new String[] {HTML};
+}
+
+boolean checkHTML(Object object) {
+ return (object != null && object instanceof String && ((String)object).length() > 0);
+}
+
+protected boolean validate(Object object) {
+ return checkHTML(object);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/ImageTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/ImageTransfer.java
new file mode 100644
index 0000000000..01add3417f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/ImageTransfer.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Outhink - support for typeFileURL
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.carbon.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * The class <code>ImageTransfer</code> provides a platform specific mechanism
+ * for converting an Image represented as a java <code>ImageData</code> to a
+ * platform specific representation of the data and vice versa. The
+ * <code>ImageData</code> contains infomration about the Image. See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p>
+ * An example of a java <code>Image</code> containing an ImageData is shown
+ * below:
+ * </p>
+ *
+ * <code><pre>
+ * Image image = new Image(display, fileName);
+ * ImageData imgData = image.getImageData();
+ * </code></pre>
+ */
+public class ImageTransfer extends ByteArrayTransfer {
+
+static ImageTransfer _instance = new ImageTransfer();
+static final String PICT = "PICT"; //$NON-NLS-1$
+static final String TIFF = "TIFF"; //$NON-NLS-1$
+static final int PICTID = registerType(PICT);
+static final int TIFFID = registerType(TIFF);
+
+ImageTransfer() {
+}
+
+/**
+ * Returns the singleton instance of the ImageTransfer class.
+ *
+ * @return the singleton instance of the ImageTransfer class
+ */
+public static ImageTransfer getInstance() {
+ return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts an ImageData
+ * object represented by a java <code>ImageData</code> to a platform
+ * specific representation. For additional information see
+ * <code>Transfer#javaToNative</code>.
+ *
+ * @param object
+ * a java <code>ImageData</code>
+ * @param transferData
+ * an empty <code>TransferData</code> object; this object will
+ * be filled in on return with the platform specific format of
+ * the data
+ */
+public void javaToNative(Object object, TransferData transferData) {
+ if (!checkImage(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ transferData.result = -1;
+
+ ImageData imgData = (ImageData) object;
+ Image image = new Image(Display.getCurrent(), imgData);
+ int handle = image.handle;
+ int width = OS.CGImageGetWidth(handle);
+ int height = OS.CGImageGetHeight(handle);
+ int alphaInfo = OS.CGImageGetAlphaInfo(handle);
+ int bpr = OS.CGImageGetBytesPerRow(handle);
+
+ Rect rect = new Rect();
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = (short) width;
+ rect.bottom = (short) height;
+
+ int[] gWorld = new int[1];
+ int format = OS.k24RGBPixelFormat;
+ if (alphaInfo != OS.kCGImageAlphaNoneSkipFirst) {
+ format = OS.k32ARGBPixelFormat;
+ }
+ OS.NewGWorldFromPtr(gWorld, format, rect, 0, 0, 0, image.data, bpr);
+ int[] curPort = new int[1];
+ int[] curGWorld = new int[1];
+ OS.GetGWorld(curPort, curGWorld);
+ OS.SetGWorld(gWorld[0], curGWorld[0]);
+ int pictHandle = OS.OpenPicture(rect);
+ int portBitMap = OS.GetPortBitMapForCopyBits(gWorld[0]);
+ OS.CopyBits(portBitMap, portBitMap, rect, rect, (short) OS.srcCopy, 0);
+ OS.ClosePicture();
+ OS.SetGWorld(curPort[0], curGWorld[0]);
+ OS.DisposeGWorld(gWorld[0]);
+ int length = OS.GetHandleSize(pictHandle);
+ OS.HLock(pictHandle);
+ int[] buffer = new int[1];
+ OS.memmove(buffer, pictHandle, 4);
+ byte[] pictData = new byte[length];
+ OS.memmove(pictData, buffer[0], length);
+ OS.HUnlock(pictHandle);
+ OS.KillPicture(pictHandle);
+ image.dispose();
+
+ transferData.data = new byte[][] { pictData };
+ transferData.result = OS.noErr;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform
+ * specific representation of an ImageData <code>ImageData</code>. For
+ * additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData
+ * the platform specific representation of the data to be been
+ * converted
+ * @return a java <code>ImageData</code> object if the conversion was
+ * successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData) {
+ if (!isSupportedType(transferData) || transferData.data == null)
+ return null;
+ if (transferData.data.length == 0)
+ return null;
+ byte[] dataArr = transferData.data[0];
+ int size = dataArr.length;
+ int pictPtr = OS.NewPtr(size);
+ OS.memmove(pictPtr, dataArr, size);
+ int dataProvider = OS.CGDataProviderCreateWithData(0, pictPtr, size, 0);
+ if (dataProvider != 0) {
+ int pictDataRef = OS.QDPictCreateWithProvider(dataProvider);
+ // get bounds for the image
+ CGRect rect = new CGRect();
+ OS.QDPictGetBounds(pictDataRef, rect);
+ int width = (int) rect.width;
+ int height = (int) rect.height;
+
+ /* Create the image */
+ int bpr = width * 4;
+ int dataSize = height * bpr;
+ int data = OS.NewPtr(dataSize);
+ if (data == 0)
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ int provider = OS
+ .CGDataProviderCreateWithData(0, data, dataSize, 0);
+ if (provider == 0) {
+ OS.DisposePtr(data);
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+ int colorspace = OS.CGColorSpaceCreateDeviceRGB();
+ if (colorspace == 0)
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ int handle = OS.CGImageCreate(width, height, 8, 32, bpr,
+ colorspace, OS.kCGImageAlphaNoneSkipFirst, provider, null,
+ true, 0);
+ OS.CGDataProviderRelease(provider);
+ if (handle == 0) {
+ OS.DisposePtr(data);
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+ int bpc = OS.CGImageGetBitsPerComponent(handle);
+ int context = OS.CGBitmapContextCreate(data, width, height, bpc,
+ bpr, colorspace, OS.kCGImageAlphaNoneSkipFirst);
+ if (context == 0) {
+ OS.CGImageRelease(handle);
+ OS.DisposePtr(data);
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+ int status = OS.QDPictDrawToCGContext(context, rect, pictDataRef);
+ ImageData imgData = null;
+ if (status == 0) {
+ Image image = Image.carbon_new(Display.getCurrent(),
+ SWT.BITMAP, handle, data);
+ imgData = image.getImageData();
+ image.dispose();
+ }
+ OS.CGContextRelease(context);
+ OS.QDPictRelease(pictDataRef);
+ return imgData;
+ }
+ return null;
+}
+
+protected int[] getTypeIds() {
+ return new int[] { PICTID };
+}
+
+protected String[] getTypeNames() {
+ return new String[] { PICT };
+}
+
+boolean checkImage(Object object) {
+ if (object == null || !(object instanceof ImageData)) return false;
+ return true;
+}
+
+protected boolean validate(Object object) {
+ return checkImage(object);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/RTFTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/RTFTransfer.java
new file mode 100644
index 0000000000..fed105d0ce
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/RTFTransfer.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.internal.carbon.OS;
+import org.eclipse.swt.internal.carbon.CFRange;
+
+/**
+ * The class <code>RTFTransfer</code> provides a platform specific mechanism
+ * for converting text in RTF format represented as a java <code>String</code>
+ * to a platform specific representation of the data and vice versa. See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p>An example of a java <code>String</code> containing RTF text is shown
+ * below:</p>
+ *
+ * <code><pre>
+ * String rtfData = "{\\rtf1{\\colortbl;\\red255\\green0\\blue0;}\\uc1\\b\\i Hello World}";
+ * </code></pre>
+ */
+public class RTFTransfer extends ByteArrayTransfer {
+
+ static RTFTransfer _instance = new RTFTransfer();
+ static final String RTF = "RTF "; //$NON-NLS-1$
+ static final int RTFID = registerType(RTF);
+
+RTFTransfer() {}
+
+/**
+ * Returns the singleton instance of the RTFTransfer class.
+ *
+ * @return the singleton instance of the RTFTransfer class
+ */
+public static RTFTransfer getInstance () {
+ return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts RTF-formatted text
+ * represented by a java <code>String</code> to a platform specific representation.
+ * For additional information see <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>String</code> containing RTF text
+ * @param transferData an empty <code>TransferData</code> object; this
+ * object will be filled in on return with the platform specific format of the data
+ */
+public void javaToNative (Object object, TransferData transferData){
+ if (!checkRTF(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ transferData.result = -1;
+ String string = (String)object;
+ int count = string.length();
+ char[] chars = new char[count];
+ string.getChars(0, count, chars, 0);
+ int cfstring = OS.CFStringCreateWithCharacters(OS.kCFAllocatorDefault, chars, count);
+ if (cfstring == 0) return;
+ try {
+ CFRange range = new CFRange();
+ range.length = chars.length;
+ int encoding = OS.CFStringGetSystemEncoding();
+ int[] size = new int[1];
+ int numChars = OS.CFStringGetBytes(cfstring, range, encoding, (byte)'?', true, null, 0, size);
+ if (numChars == 0 || size[0] == 0) return;
+ byte[] buffer = new byte[size[0]];
+ numChars = OS.CFStringGetBytes(cfstring, range, encoding, (byte)'?', true, buffer, size [0], size);
+ if (numChars == 0) return;
+ transferData.data = new byte[1][];
+ transferData.data[0] = buffer;
+ transferData.result = 0;
+ } finally {
+ OS.CFRelease(cfstring);
+ }
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of RTF text to a java <code>String</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String</code> containing RTF text if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.data == null) return null;
+ if (transferData.data.length == 0 || transferData.data[0].length == 0) return null;
+ byte[] buffer = transferData.data[0];
+ int encoding = OS.CFStringGetSystemEncoding();
+ int cfstring = OS.CFStringCreateWithBytes(OS.kCFAllocatorDefault, buffer, buffer.length, encoding, true);
+ if (cfstring == 0) return null;
+ try {
+ int length = OS.CFStringGetLength(cfstring);
+ if (length == 0) return null;
+ char[] chars = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(cfstring, range, chars);
+ return new String(chars);
+ } finally {
+ OS.CFRelease(cfstring);
+ }
+}
+
+protected int[] getTypeIds() {
+ return new int[] {RTFID};
+}
+
+protected String[] getTypeNames() {
+ return new String[] {RTF};
+}
+
+boolean checkRTF(Object object) {
+ return (object != null && object instanceof String && ((String)object).length() > 0);
+}
+
+protected boolean validate(Object object) {
+ return checkRTF(object);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TableDragSourceEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TableDragSourceEffect.java
new file mode 100644
index 0000000000..416864d6f5
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TableDragSourceEffect.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides default implementations to display a source image
+ * when a drag is initiated from a <code>Table</code>.
+ *
+ * <p>Classes that wish to provide their own source image for a <code>Table</code> can
+ * extend the <code>TableDragSourceEffect</code> class, override the
+ * <code>TableDragSourceEffect.dragStart</code> method and set the field
+ * <code>DragSourceEvent.image</code> with their own image.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag source effect implementation.
+ *
+ * @see DragSourceEffect
+ * @see DragSourceEvent
+ *
+ * @since 3.3
+ */
+public class TableDragSourceEffect extends DragSourceEffect {
+ /**
+ * Creates a new <code>TableDragSourceEffect</code> to handle drag effect
+ * from the specified <code>Table</code>.
+ *
+ * @param table the <code>Table</code> that the user clicks on to initiate the drag
+ */
+ public TableDragSourceEffect(Table table) {
+ super(table);
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TableDropTargetEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TableDropTargetEffect.java
new file mode 100644
index 0000000000..1f8f804902
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TableDropTargetEffect.java
@@ -0,0 +1,196 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.Callback;
+import org.eclipse.swt.internal.carbon.DataBrowserCallbacks;
+import org.eclipse.swt.internal.carbon.OS;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides a default drag under effect (eg. select, insert and scroll)
+ * when a drag occurs over a <code>Table</code>.
+ *
+ * <p>Classes that wish to provide their own drag under effect for a <code>Table</code>
+ * can extend the <code>TableDropTargetEffect</code> and override any applicable methods
+ * in <code>TableDropTargetEffect</code> to display their own drag under effect.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag under effect implementation.
+ *
+ * <p>The feedback value is either one of the FEEDBACK constants defined in
+ * class <code>DND</code> which is applicable to instances of this class,
+ * or it must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> effect constants.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Feedback:</b></dt>
+ * <dd>FEEDBACK_SELECT, FEEDBACK_SCROLL</dd>
+ * </dl>
+ * </p>
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ *
+ * @since 3.3
+ */
+public class TableDropTargetEffect extends DropTargetEffect {
+ static final int SCROLL_HYSTERESIS = 150; // milli seconds
+
+ TableItem scrollItem;
+ long scrollBeginTime;
+ DataBrowserCallbacks callbacks = null;
+
+ static Callback AcceptDragProc;
+ static {
+ AcceptDragProc = new Callback(TableDropTargetEffect.class, "AcceptDragProc", 5); //$NON-NLS-1$
+ int acceptDragProc = AcceptDragProc.getAddress();
+ if (acceptDragProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ }
+
+ static int AcceptDragProc(int theControl, int itemID, int property, int theRect, int theDrag) {
+ DropTarget target = FindDropTarget(theControl, theDrag);
+ if (target == null) return 0;
+ return (target.feedback & DND.FEEDBACK_SELECT) != 0 ? 1 : 0;
+ }
+
+ static DropTarget FindDropTarget(int theControl, int theDrag) {
+ if (theControl == 0) return null;
+ Display display = Display.findDisplay(Thread.currentThread());
+ if (display == null || display.isDisposed()) return null;
+ Widget widget = display.findWidget(theControl);
+ if (widget == null) return null;
+ return (DropTarget)widget.getData(DND.DROP_TARGET_KEY);
+ }
+
+ /**
+ * Creates a new <code>TableDropTargetEffect</code> to handle the drag under effect on the specified
+ * <code>Table</code>.
+ *
+ * @param table the <code>Table</code> over which the user positions the cursor to drop the data
+ */
+ public TableDropTargetEffect(Table table) {
+ super(table);
+ }
+
+ int checkEffect(int effect) {
+ // Some effects are mutually exclusive. Make sure that only one of the mutually exclusive effects has been specified.
+ if ((effect & DND.FEEDBACK_SELECT) != 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE;
+ if ((effect & DND.FEEDBACK_INSERT_BEFORE) != 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER;
+ return effect;
+ }
+
+ /**
+ * This implementation of <code>dragEnter</code> provides a default drag under effect
+ * for the feedback specified in <code>event.feedback</code>.
+ *
+ * For additional information see <code>DropTargetAdapter.dragEnter</code>.
+ *
+ * Subclasses that override this method should call <code>super.dragEnter(event)</code>
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag enter event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ public void dragEnter(DropTargetEvent event) {
+ if (callbacks == null) {
+ Table table = (Table) control;
+ DataBrowserCallbacks callbacks = new DataBrowserCallbacks ();
+ OS.GetDataBrowserCallbacks (table.handle, callbacks);
+ callbacks.v1_acceptDragCallback = AcceptDragProc.getAddress();
+ OS.SetDataBrowserCallbacks(table.handle, callbacks);
+ }
+ scrollBeginTime = 0;
+ scrollItem = null;
+ }
+
+ /**
+ * This implementation of <code>dragLeave</code> provides a default drag under effect
+ * for the feedback specified in <code>event.feedback</code>.
+ *
+ * For additional information see <code>DropTargetAdapter.dragLeave</code>.
+ *
+ * Subclasses that override this method should call <code>super.dragLeave(event)</code>
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag leave event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ public void dragLeave(DropTargetEvent event) {
+ scrollBeginTime = 0;
+ scrollItem = null;
+ }
+
+ /**
+ * This implementation of <code>dragOver</code> provides a default drag under effect
+ * for the feedback specified in <code>event.feedback</code>. The class description
+ * lists the FEEDBACK constants that are applicable to the class.
+ *
+ * For additional information see <code>DropTargetAdapter.dragOver</code>.
+ *
+ * Subclasses that override this method should call <code>super.dragOver(event)</code>
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag over event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ * @see DND#FEEDBACK_SELECT
+ * @see DND#FEEDBACK_SCROLL
+ */
+ public void dragOver(DropTargetEvent event) {
+ Table table = (Table) control;
+ int effect = checkEffect(event.feedback);
+
+ TableItem item = (TableItem)getItem(table, event.x, event.y);
+
+ if ((effect & DND.FEEDBACK_SCROLL) == 0) {
+ scrollBeginTime = 0;
+ scrollItem = null;
+ } else {
+ if (item != null && item.equals(scrollItem) && scrollBeginTime != 0) {
+ if (System.currentTimeMillis() >= scrollBeginTime) {
+ Rectangle area = table.getClientArea();
+ int headerHeight = table.getHeaderHeight();
+ int itemHeight= table.getItemHeight();
+ Point pt = new Point(event.x, event.y);
+ pt = table.getDisplay().map(null, table, pt);
+ TableItem nextItem = null;
+ if (pt.y < area.y + headerHeight + 2 * itemHeight) {
+ int index = Math.max(0, table.indexOf(item)-1);
+ nextItem = table.getItem(index);
+ }
+ if (pt.y > area.y + area.height - 2 * itemHeight) {
+ int index = Math.min(table.getItemCount()-1, table.indexOf(item)+1);
+ nextItem = table.getItem(index);
+ }
+ if (nextItem != null) table.showItem(nextItem);
+ scrollBeginTime = 0;
+ scrollItem = null;
+ }
+ } else {
+ scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+ scrollItem = item;
+ }
+ }
+
+ // store current effect for selection feedback
+ ((DropTarget)event.widget).feedback = effect;
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TextTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TextTransfer.java
new file mode 100644
index 0000000000..e2caaee2bc
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TextTransfer.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.internal.carbon.CFRange;
+import org.eclipse.swt.internal.carbon.OS;
+
+/**
+ * The class <code>TextTransfer</code> provides a platform specific mechanism
+ * for converting plain text represented as a java <code>String</code>
+ * to a platform specific representation of the data and vice versa.
+ *
+ * <p>An example of a java <code>String</code> containing plain text is shown
+ * below:</p>
+ *
+ * <code><pre>
+ * String textData = "Hello World";
+ * </code></pre>
+ *
+ * @see Transfer
+ */
+public class TextTransfer extends ByteArrayTransfer {
+
+ static TextTransfer _instance = new TextTransfer();
+ static final String TEXT = "TEXT"; //$NON-NLS-1$
+ static final String UTEXT = "utxt"; //$NON-NLS-1$
+ static final int TEXTID = OS.kScrapFlavorTypeText;
+ static final int UTEXTID = OS.kScrapFlavorTypeUnicode;
+
+TextTransfer() {}
+
+/**
+ * Returns the singleton instance of the TextTransfer class.
+ *
+ * @return the singleton instance of the TextTransfer class
+ */
+public static TextTransfer getInstance () {
+ return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts plain text
+ * represented by a java <code>String</code> to a platform specific representation.
+ *
+ * @param object a java <code>String</code> containing text
+ * @param transferData an empty <code>TransferData</code> object; this object
+ * will be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#javaToNative
+ */
+public void javaToNative (Object object, TransferData transferData) {
+ if (!checkText(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ String string = (String)object;
+ char[] chars = new char[string.length()];
+ string.getChars (0, chars.length, chars, 0);
+ transferData.result = -1;
+ switch (transferData.type) {
+ case TEXTID: {
+ int cfstring = OS.CFStringCreateWithCharacters(OS.kCFAllocatorDefault, chars, chars.length);
+ if (cfstring == 0) return;
+ byte[] buffer = null;
+ try {
+ CFRange range = new CFRange();
+ range.length = chars.length;
+ int encoding = OS.CFStringGetSystemEncoding();
+ int[] size = new int[1];
+ int numChars = OS.CFStringGetBytes(cfstring, range, encoding, (byte)'?', true, null, 0, size);
+ if (numChars == 0) return;
+ buffer = new byte[size[0]];
+ numChars = OS.CFStringGetBytes(cfstring, range, encoding, (byte)'?', true, buffer, size [0], size);
+ if (numChars == 0) return;
+ } finally {
+ OS.CFRelease(cfstring);
+ }
+ transferData.data = new byte[1][];
+ transferData.data[0] = buffer;
+ transferData.result = OS.noErr;
+ break;
+ }
+ case UTEXTID: {
+ byte[] buffer = new byte[chars.length * 2];
+ OS.memmove(buffer, chars, buffer.length);
+ transferData.data = new byte[1][];
+ transferData.data[0] = buffer;
+ transferData.result = OS.noErr;
+ break;
+ }
+ }
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of plain text to a java <code>String</code>.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java <code>String</code> containing text if the conversion was successful; otherwise null
+ *
+ * @see Transfer#nativeToJava
+ */
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.data == null) return null;
+ if (transferData.data.length == 0 || transferData.data[0].length == 0) return null;
+ byte[] buffer = transferData.data[0];
+ switch (transferData.type) {
+ case TEXTID: {
+ int encoding = OS.CFStringGetSystemEncoding();
+ int cfstring = OS.CFStringCreateWithBytes(OS.kCFAllocatorDefault, buffer, buffer.length, encoding, true);
+ if (cfstring == 0) return null;
+ try {
+ int length = OS.CFStringGetLength(cfstring);
+ if (length == 0) return null;
+ char[] chars = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(cfstring, range, chars);
+ return new String(chars);
+ } finally {
+ OS.CFRelease(cfstring);
+ }
+ }
+ case UTEXTID: {
+ char[] chars = new char[(buffer.length + 1) / 2];
+ OS.memmove(chars, buffer, buffer.length);
+ return new String(chars);
+ }
+ }
+ return null;
+}
+
+protected int[] getTypeIds() {
+ return new int[] {UTEXTID, TEXTID};
+}
+
+protected String[] getTypeNames() {
+ return new String[] {UTEXT, TEXT};
+}
+
+boolean checkText(Object object) {
+ return (object != null && object instanceof String && ((String)object).length() > 0);
+}
+protected boolean validate(Object object) {
+ return checkText(object);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Transfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Transfer.java
new file mode 100644
index 0000000000..f5a8ee287e
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/Transfer.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+/**
+ * <code>Transfer</code> provides a mechanism for converting between a java
+ * representation of data and a platform specific representation of data and
+ * vice versa. It is used in data transfer operations such as drag and drop and
+ * clipboard copy/paste.
+ *
+ * <p>You should only need to become familiar with this class if you are
+ * implementing a Transfer subclass and you are unable to subclass the
+ * ByteArrayTransfer class.</p>
+ *
+ * @see ByteArrayTransfer
+ */
+public abstract class Transfer {
+
+/**
+ * Returns a list of the platform specific data types that can be converted using
+ * this transfer agent.
+ *
+ * <p>Only the data type fields of the <code>TransferData</code> objects are filled
+ * in.</p>
+ *
+ * @return a list of the data types that can be converted using this transfer agent
+ */
+abstract public TransferData[] getSupportedTypes();
+
+/**
+ * Returns true if the <code>TransferData</code> data type can be converted
+ * using this transfer agent, or false otherwise (including if transferData is
+ * <code>null</code>).
+ *
+ * @param transferData a platform specific description of a data type; only the data
+ * type fields of the <code>TransferData</code> object need to be filled in
+ *
+ * @return true if the transferData data type can be converted using this transfer
+ * agent
+ */
+abstract public boolean isSupportedType(TransferData transferData);
+
+/**
+ * Returns the platform specific ids of the data types that can be converted using
+ * this transfer agent.
+ *
+ * @return the platform specific ids of the data types that can be converted using
+ * this transfer agent
+ */
+abstract protected int[] getTypeIds();
+
+/**
+ * Returns the platform specific names of the data types that can be converted
+ * using this transfer agent.
+ *
+ * @return the platform specific names of the data types that can be converted
+ * using this transfer agent.
+ */
+abstract protected String[] getTypeNames();
+
+/**
+ * Converts a java representation of data to a platform specific representation of
+ * the data.
+ *
+ * <p>On a successful conversion, the transferData.result field will be set as follows:
+ * <ul>
+ * <li>Windows: COM.S_OK
+ * <li>Motif: 1
+ * <li>GTK: 1
+ * <li>Photon: 1
+ * </ul></p>
+ *
+ * <p>If this transfer agent is unable to perform the conversion, the transferData.result
+ * field will be set to a failure value as follows:
+ * <ul>
+ * <li>Windows: COM.DV_E_TYMED or COM.E_FAIL
+ * <li>Motif: 0
+ * <li>GTK: 0
+ * <li>Photon: 0
+ * </ul></p>
+ *
+ * @param object a java representation of the data to be converted; the type of
+ * Object that is passed in is dependent on the <code>Transfer</code> subclass.
+ *
+ * @param transferData an empty TransferData object; this object will be
+ * filled in on return with the platform specific representation of the data
+ *
+ * @exception org.eclipse.swt.SWTException <ul>
+ * <li>ERROR_INVALID_DATA - if object does not contain data in a valid format or is <code>null</code></li>
+ * </ul>
+ */
+abstract protected void javaToNative (Object object, TransferData transferData);
+
+/**
+ * Converts a platform specific representation of data to a java representation.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * converted
+ *
+ * @return a java representation of the converted data if the conversion was
+ * successful; otherwise null. If transferData is <code>null</code> then
+ * <code>null</code> is returned. The type of Object that is returned is
+ * dependent on the <code>Transfer</code> subclass.
+ */
+abstract protected Object nativeToJava(TransferData transferData);
+
+/**
+ * Registers a name for a data type and returns the associated unique identifier.
+ *
+ * <p>You may register the same type more than once, the same unique identifier
+ * will be returned if the type has been previously registered.</p>
+ *
+ * <p>Note: On windows, do <b>not</b> call this method with pre-defined
+ * Clipboard Format types such as CF_TEXT or CF_BITMAP because the
+ * pre-defined identifier will not be returned</p>
+ *
+ * @param formatName the name of a data type
+ *
+ * @return the unique identifier associated with this data type
+ */
+public static int registerType(String formatName) {
+ int length = formatName.length();
+ // TODO - hashcode may not be unique - need another way
+ if (length > 4) return formatName.hashCode();
+ int type = 0;
+ if (length > 0) type |= (formatName.charAt(0) & 0xff) << 24;
+ if (length > 1) type |= (formatName.charAt(1) & 0xff) << 16;
+ if (length > 2) type |= (formatName.charAt(2) & 0xff) << 8;
+ if (length > 3) type |= formatName.charAt(3) & 0xff;
+ return type;
+}
+
+/**
+ * Test that the object is of the correct format for this Transfer class.
+ *
+ * @param object a java representation of the data to be converted
+ *
+ * @return true if object is of the correct form for this transfer type
+ *
+ * @since 3.1
+ */
+protected boolean validate(Object object) {
+ return true;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TransferData.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TransferData.java
new file mode 100644
index 0000000000..cd7e4248e7
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TransferData.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+
+/**
+ * The <code>TransferData</code> class is a platform specific data structure for
+ * describing the type and the contents of data being converted by a transfer agent.
+ *
+ * <p>As an application writer, you do not need to know the specifics of
+ * TransferData. TransferData instances are passed to a subclass of Transfer
+ * and the Transfer object manages the platform specific issues.
+ * You can ask a Transfer subclass if it can handle this data by calling
+ * Transfer.isSupportedType(transferData).</p>
+ *
+ * <p>You should only need to become familiar with the fields in this class if you
+ * are implementing a Transfer subclass and you are unable to subclass the
+ * ByteArrayTransfer class.</p>
+ */
+public class TransferData {
+ /**
+ * The type is a unique identifier of a system format or user defined format.
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int type;
+
+ /**
+ * The data being transferred.
+ * The data field may contain multiple values.
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public byte[][] data;
+
+ /**
+ * The result field contains the result of converting a
+ * java data type into a platform specific value.
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ * <p>The value of result is 1 if the conversion was successful.
+ * The value of result is 0 if the conversion failed.</p>
+ */
+ public int result;
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TreeDragSourceEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TreeDragSourceEffect.java
new file mode 100644
index 0000000000..97cd46f444
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TreeDragSourceEffect.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides default implementations to display a source image
+ * when a drag is initiated from a <code>Tree</code>.
+ *
+ * <p>Classes that wish to provide their own source image for a <code>Tree</code> can
+ * extend <code>TreeDragSourceEffect</code> class and override the <code>TreeDragSourceEffect.dragStart</code>
+ * method and set the field <code>DragSourceEvent.image</code> with their own image.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag under effect implementation.
+ *
+ * @see DragSourceEffect
+ * @see DragSourceEvent
+ *
+ * @since 3.3
+ */
+public class TreeDragSourceEffect extends DragSourceEffect {
+ /**
+ * Creates a new <code>TreeDragSourceEffect</code> to handle drag effect
+ * from the specified <code>Tree</code>.
+ *
+ * @param tree the <code>Tree</code> that the user clicks on to initiate the drag
+ */
+ public TreeDragSourceEffect(Tree tree) {
+ super(tree);
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TreeDropTargetEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TreeDropTargetEffect.java
new file mode 100644
index 0000000000..400df25b27
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/TreeDropTargetEffect.java
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.dnd;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.Callback;
+import org.eclipse.swt.internal.carbon.DataBrowserCallbacks;
+import org.eclipse.swt.internal.carbon.OS;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * This class provides a default drag under effect (eg. select, insert, scroll and expand)
+ * when a drag occurs over a <code>Tree</code>.
+ *
+ * <p>Classes that wish to provide their own drag under effect for a <code>Tree</code>
+ * can extend the <code>TreeDropTargetEffect</code> class and override any applicable methods
+ * in <code>TreeDropTargetEffect</code> to display their own drag under effect.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag under effect implementation.
+ *
+ * <p>The feedback value is either one of the FEEDBACK constants defined in
+ * class <code>DND</code> which is applicable to instances of this class,
+ * or it must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> effect constants.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Feedback:</b></dt>
+ * <dd>FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE, FEEDBACK_INSERT_AFTER, FEEDBACK_EXPAND, FEEDBACK_SCROLL</dd>
+ * </dl>
+ * </p><p>
+ * Note: Only one of the styles FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE or
+ * FEEDBACK_INSERT_AFTER may be specified.
+ * </p>
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ *
+ * @since 3.3
+ */
+public class TreeDropTargetEffect extends DropTargetEffect {
+ static final int SCROLL_HYSTERESIS = 150; // milli seconds
+ static final int EXPAND_HYSTERESIS = 1000; // milli seconds
+
+ int currentEffect = DND.FEEDBACK_NONE;
+ TreeItem currentItem;
+
+ TreeItem insertItem = null;
+ boolean insertBefore = false;
+
+ TreeItem scrollItem;
+ long scrollBeginTime;
+
+ TreeItem expandItem;
+ long expandBeginTime;
+
+ DataBrowserCallbacks callbacks = null;
+
+ int acceptDragProc(int theControl, int itemID, int property, int theRect, int theDrag) {
+ return (currentEffect & DND.FEEDBACK_SELECT) != 0 ? 1 : 0;
+ }
+
+ static Callback AcceptDragProc;
+ static {
+ AcceptDragProc = new Callback(TreeDropTargetEffect.class, "AcceptDragProc", 5); //$NON-NLS-1$
+ int acceptDragProc = AcceptDragProc.getAddress();
+ if (acceptDragProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ }
+
+ static int AcceptDragProc(int theControl, int itemID, int property, int theRect, int theDrag) {
+ DropTarget target = FindDropTarget(theControl, theDrag);
+ if (target == null) return 0;
+ return (target.feedback & DND.FEEDBACK_SELECT) != 0 ? 1 : 0;
+ }
+
+ static DropTarget FindDropTarget(int theControl, int theDrag) {
+ if (theControl == 0) return null;
+ Display display = Display.findDisplay(Thread.currentThread());
+ if (display == null || display.isDisposed()) return null;
+ Widget widget = display.findWidget(theControl);
+ if (widget == null) return null;
+ return (DropTarget)widget.getData(DND.DROP_TARGET_KEY);
+ }
+
+ /**
+ * Creates a new <code>TreeDropTargetEffect</code> to handle the drag under effect on the specified
+ * <code>Tree</code>.
+ *
+ * @param tree the <code>Tree</code> over which the user positions the cursor to drop the data
+ */
+ public TreeDropTargetEffect(Tree tree) {
+ super(tree);
+ }
+
+ int checkEffect(int effect) {
+ // Some effects are mutually exclusive. Make sure that only one of the mutually exclusive effects has been specified.
+ if ((effect & DND.FEEDBACK_SELECT) != 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE;
+ if ((effect & DND.FEEDBACK_INSERT_BEFORE) != 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER;
+ return effect;
+ }
+
+ /**
+ * This implementation of <code>dragEnter</code> provides a default drag under effect
+ * for the feedback specified in <code>event.feedback</code>.
+ *
+ * For additional information see <code>DropTargetAdapter.dragEnter</code>.
+ *
+ * Subclasses that override this method should call <code>super.dragEnter(event)</code>
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag enter event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ public void dragEnter(DropTargetEvent event) {
+ if (callbacks == null) {
+ Tree table = (Tree) control;
+ DataBrowserCallbacks callbacks = new DataBrowserCallbacks ();
+ OS.GetDataBrowserCallbacks (table.handle, callbacks);
+ callbacks.v1_acceptDragCallback = AcceptDragProc.getAddress();
+ OS.SetDataBrowserCallbacks(table.handle, callbacks);
+ }
+ insertItem = null;
+ expandBeginTime = 0;
+ expandItem = null;
+ scrollBeginTime = 0;
+ scrollItem = null;
+ }
+
+ /**
+ * This implementation of <code>dragLeave</code> provides a default drag under effect
+ * for the feedback specified in <code>event.feedback</code>.
+ *
+ * For additional information see <code>DropTargetAdapter.dragLeave</code>.
+ *
+ * Subclasses that override this method should call <code>super.dragLeave(event)</code>
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag leave event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ */
+ public void dragLeave(DropTargetEvent event) {
+ Tree tree = (Tree) control;
+ if (insertItem != null) {
+ setInsertMark(tree, null, false);
+ insertItem = null;
+ }
+ expandBeginTime = 0;
+ expandItem = null;
+ scrollBeginTime = 0;
+ scrollItem = null;
+ }
+
+ /**
+ * This implementation of <code>dragOver</code> provides a default drag under effect
+ * for the feedback specified in <code>event.feedback</code>.
+ *
+ * For additional information see <code>DropTargetAdapter.dragOver</code>.
+ *
+ * Subclasses that override this method should call <code>super.dragOver(event)</code>
+ * to get the default drag under effect implementation.
+ *
+ * @param event the information associated with the drag over event
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ * @see DND#FEEDBACK_SELECT
+ * @see DND#FEEDBACK_INSERT_BEFORE
+ * @see DND#FEEDBACK_INSERT_AFTER
+ * @see DND#FEEDBACK_SCROLL
+ */
+ public void dragOver(DropTargetEvent event) {
+ Tree tree = (Tree) control;
+ TreeItem item = (TreeItem)getItem(tree, event.x, event.y);
+ int effect = checkEffect(event.feedback);
+ if ((effect & DND.FEEDBACK_EXPAND) == 0) {
+ expandBeginTime = 0;
+ expandItem = null;
+ } else {
+ if (item != null && item.equals(expandItem) && expandBeginTime != 0) {
+ if (System.currentTimeMillis() >= expandBeginTime) {
+ if (item.getItemCount() > 0 && !item.getExpanded()) {
+ Event e = new Event();
+ e.x = event.x;
+ e.y = event.y;
+ e.item = item;
+ e.time = (int) System.currentTimeMillis();
+ tree.notifyListeners(SWT.Expand, e);
+ if (item.isDisposed()) return;
+ item.setExpanded(true);
+ }
+ expandBeginTime = 0;
+ expandItem = null;
+ }
+ } else {
+ expandBeginTime = System.currentTimeMillis() + EXPAND_HYSTERESIS;
+ expandItem = item;
+ }
+ }
+
+ if ((effect & DND.FEEDBACK_SCROLL) == 0) {
+ scrollBeginTime = 0;
+ scrollItem = null;
+ } else {
+ if (item != null && item.equals(scrollItem) && scrollBeginTime != 0) {
+ if (System.currentTimeMillis() >= scrollBeginTime) {
+ Rectangle area = tree.getClientArea();
+ int headerHeight = tree.getHeaderHeight();
+ int itemHeight= tree.getItemHeight();
+ Point pt = new Point(event.x, event.y);
+ pt = tree.getDisplay().map(null, tree, pt);
+ TreeItem nextItem = null;
+ if (pt.y < area.y + headerHeight + 2 * itemHeight) {
+ nextItem = previousItem(tree, item);
+ }
+ if (pt.y > area.y + area.height - 2 * itemHeight) {
+ nextItem = nextItem(tree, item);
+ }
+ if (nextItem != null) tree.showItem(nextItem);
+ scrollBeginTime = 0;
+ scrollItem = null;
+ }
+ } else {
+ scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+ scrollItem = item;
+ }
+ }
+
+ if ((effect & DND.FEEDBACK_INSERT_AFTER) != 0 ||
+ (effect & DND.FEEDBACK_INSERT_BEFORE) != 0) {
+ if (currentItem != item ||
+ ((effect & DND.FEEDBACK_INSERT_AFTER) != (currentEffect & DND.FEEDBACK_INSERT_AFTER)) ||
+ ((effect & DND.FEEDBACK_INSERT_BEFORE) != (currentEffect & DND.FEEDBACK_INSERT_BEFORE))) {
+ setInsertMark(tree, item, (effect & DND.FEEDBACK_INSERT_BEFORE) != 0);
+ currentEffect = effect;
+ currentItem = item;
+ }
+ } else {
+ setInsertMark(tree, null, false);
+ }
+ // save current effect for selection feedback
+ ((DropTarget)event.widget).feedback = effect;
+ }
+
+ void setInsertMark(Tree tree, TreeItem item, boolean before) {
+ if (item == insertItem && before == insertBefore) return;
+ insertItem = item;
+ insertBefore = before;
+ tree.setInsertMark(item, before);
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/URLTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/URLTransfer.java
new file mode 100644
index 0000000000..0117363de9
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/cocoa/org/eclipse/swt/dnd/URLTransfer.java
@@ -0,0 +1 @@
+/******************************************************************************* * Copyright (c) 20007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.dnd; import org.eclipse.swt.internal.carbon.*; /** * The class <code>URLTransfer</code> provides a platform specific mechanism * for converting text in URL format represented as a java <code>String</code> * to a platform specific representation of the data and vice versa. See * <code>Transfer</code> for additional information. The string * must contain the fully specified url. * * <p>An example of a java <code>String[]</code> containing a URL is shown * below:</p> * * <code><pre> * String url = "http://www.eclipse.org"; * </code></pre> */ public class URLTransfer extends ByteArrayTransfer { static URLTransfer _instance = new URLTransfer(); static final String URL = "url "; //$NON-NLS-1$ static final int URL_ID = registerType(URL); static final String URLN = "urln"; //$NON-NLS-1$ static final int URLN_ID = registerType(URLN); private URLTransfer() {} /** * Returns the singleton instance of the URLTransfer class. * * @return the singleton instance of the URLTransfer class */ public static URLTransfer getInstance () { return _instance; } /** * This implementation of <code>javaToNative</code> converts a URL * represented by a java <code>String</code> to a platform specific representation. * For additional information see <code>Transfer#javaToNative</code>. * * @param object a java <code>String[]</code> containing a URL * @param transferData an empty <code>TransferData</code> object; this * object will be filled in on return with the platform specific format of the data */ public void javaToNative (Object object, TransferData transferData){ if (!checkURL(object) || !isSupportedType(transferData)) { DND.error(DND.ERROR_INVALID_DATA); } transferData.result = -1; String url = (String)object; int count = url.length(); char[] chars = new char[count]; url.getChars(0, count, chars, 0); int cfstring = OS.CFStringCreateWithCharacters(OS.kCFAllocatorDefault, chars, count); if (cfstring == 0) return; try { CFRange range = new CFRange(); range.length = chars.length; int encoding = OS.CFStringGetSystemEncoding(); int[] size = new int[1]; int numChars = OS.CFStringGetBytes(cfstring, range, encoding, (byte)'?', true, null, 0, size); if (numChars == 0 || size[0] == 0) return; byte[] buffer = new byte[size[0]]; numChars = OS.CFStringGetBytes(cfstring, range, encoding, (byte)'?', true, buffer, size [0], size); if (numChars == 0) return; transferData.data = new byte[][] {buffer}; transferData.result = 0; } finally { OS.CFRelease(cfstring); } } /** * This implementation of <code>nativeToJava</code> converts a platform specific * representation of a URL to a java <code>String</code>. * For additional information see <code>Transfer#nativeToJava</code>. * * @param transferData the platform specific representation of the data to be * converted * @return a java <code>String[]</code> containing a URL if the * conversion was successful; otherwise null */ public Object nativeToJava(TransferData transferData){ if (!isSupportedType(transferData) || transferData.data == null) return null; if (transferData.data.length == 0) return null; byte[] buffer = transferData.data[0]; int encoding = OS.CFStringGetSystemEncoding(); int cfstring = OS.CFStringCreateWithBytes(OS.kCFAllocatorDefault, buffer, buffer.length, encoding, true); if (cfstring == 0) return null; try { int length = OS.CFStringGetLength(cfstring); if (length == 0) return null; char[] chars = new char[length]; CFRange range = new CFRange(); range.length = length; OS.CFStringGetCharacters(cfstring, range, chars); return new String(chars); } finally { OS.CFRelease(cfstring); } } protected int[] getTypeIds(){ return new int[] {URL_ID, URLN_ID}; } protected String[] getTypeNames(){ return new String[] {URL, URLN}; } boolean checkURL(Object object) { return object != null && (object instanceof String) && ((String)object).length() > 0; } protected boolean validate(Object object) { return checkURL(object); } } \ No newline at end of file