summaryrefslogtreecommitdiffstats
path: root/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd
diff options
context:
space:
mode:
authorSilenio Quarti <silenio>2009-07-01 14:50:54 +0000
committerSilenio Quarti <silenio>2009-07-01 14:50:54 +0000
commit093c579a4ffd9551acb901bba9617e7aa776989d (patch)
tree71cf23798b651ef92f188390841a8d130908fb11 /bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd
parentf664d297f7bb009784868bf3fcf0b3e3bb9a646b (diff)
downloadeclipse.platform.swt-093c579a4ffd9551acb901bba9617e7aa776989d.tar.gz
eclipse.platform.swt-093c579a4ffd9551acb901bba9617e7aa776989d.tar.xz
eclipse.platform.swt-093c579a4ffd9551acb901bba9617e7aa776989d.zip
restore HEAD after accidental deletion by error in automated build script
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd')
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ByteArrayTransfer.java212
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/Clipboard.java796
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DragSource.java732
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DropTarget.java781
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/FileTransfer.java157
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/HTMLTransfer.java210
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ImageTransfer.java209
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/OleEnumFORMATETC.java161
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/RTFTransfer.java137
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDragSourceEffect.java199
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDropTargetEffect.java204
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TextTransfer.java184
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/Transfer.java179
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TransferData.java108
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDragSourceEffect.java193
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDropTargetEffect.java278
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/URLTransfer.java139
17 files changed, 4879 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ByteArrayTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ByteArrayTransfer.java
new file mode 100755
index 0000000000..d33f8815ae
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ByteArrayTransfer.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * 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.
+ *
+ * <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>
+ *
+ * @see Transfer
+ */
+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];
+ data[i].formatetc = new FORMATETC();
+ data[i].formatetc.cfFormat = types[i];
+ data[i].formatetc.dwAspect = COM.DVASPECT_CONTENT;
+ data[i].formatetc.lindex = -1;
+ data[i].formatetc.tymed = COM.TYMED_HGLOBAL;
+ }
+ return data;
+}
+
+public boolean isSupportedType(TransferData transferData){
+ if (transferData == null) return false;
+ int[] types = getTypeIds();
+ for (int i = 0; i < types.length; i++) {
+ FORMATETC format = transferData.formatetc;
+ if (format.cfFormat == types[i] &&
+ (format.dwAspect & COM.DVASPECT_CONTENT) == COM.DVASPECT_CONTENT &&
+ (format.tymed & COM.TYMED_HGLOBAL) == COM.TYMED_HGLOBAL )
+ return true;
+ }
+ return false;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts a java
+ * <code>byte[]</code> to a platform specific representation.
+ *
+ * @param object a java <code>byte[]</code> containing the data to be converted
+ * @param transferData an empty <code>TransferData</code> object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+protected void javaToNative (Object object, TransferData transferData) {
+ if (!checkByteArray(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ // Allocate the memory because the caller (DropTarget) has not handed it in
+ // The caller of this method must release the data when it is done with it.
+ byte[] data = (byte[])object;
+ int size = data.length;
+ int /*long*/ newPtr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, size);
+ OS.MoveMemory(newPtr, data, size);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = newPtr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of a byte array to a java <code>byte[]</code>.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java <code>byte[]</code> containing the converted data if the conversion was
+ * successful; otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+protected Object nativeToJava(TransferData transferData) {
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ FORMATETC formatetc = transferData.formatetc;
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ int /*long*/ hMem = stgmedium.unionField;
+ int size = OS.GlobalSize(hMem);
+ byte[] buffer = new byte[size];
+ int /*long*/ ptr = OS.GlobalLock(hMem);
+ OS.MoveMemory(buffer, ptr, size);
+ OS.GlobalUnlock(hMem);
+ OS.GlobalFree(hMem);
+ return buffer;
+}
+
+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/win32/org/eclipse/swt/dnd/Clipboard.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/Clipboard.java
new file mode 100755
index 0000000000..10a3126cef
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/Clipboard.java
@@ -0,0 +1,796 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.win32.*;
+import org.eclipse.swt.internal.ole.win32.*;
+
+/**
+ * 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>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#clipboard">Clipboard snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ClipboardExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class Clipboard {
+
+ private static final int RETRY_LIMIT = 10;
+ private Display display;
+
+ // ole interfaces
+ private COMObject iDataObject;
+ private int refCount;
+ private Transfer[] transferAgents = new Transfer[0];
+ private Object[] data = new Object[0];
+ private int CFSTR_PREFERREDDROPEFFECT;
+
+/**
+ * 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;
+ TCHAR chFormatName = new TCHAR(0, "Preferred DropEffect", true); //$NON-NLS-1$
+ CFSTR_PREFERREDDROPEFFECT = OS.RegisterClipboardFormat(chFormatName);
+ createCOMInterfaces();
+ this.AddRef();
+}
+
+/**
+ * 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) {
+ /* OleIsCurrentClipboard([in] pDataObject)
+ * The argument pDataObject is owned by the caller so reference count does not
+ * need to be incremented.
+ */
+ if (COM.OleIsCurrentClipboard(this.iDataObject.getAddress()) == COM.S_OK) {
+ /* OleSetClipboard([in] pDataObject)
+ * The argument pDataObject is owned by the caller so reference count does not
+ * need to be incremented.
+ */
+ COM.OleSetClipboard(0);
+ }
+ }
+}
+
+/**
+ * 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);
+ /* OleIsCurrentClipboard([in] pDataObject)
+ * The argument pDataObject is owned by the caller so reference count does not
+ * need to be incremented.
+ */
+ if (COM.OleIsCurrentClipboard(this.iDataObject.getAddress()) == COM.S_OK) {
+ COM.OleFlushClipboard();
+ }
+ this.Release();
+ 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;
+ /*
+ * Bug in Windows. When a new application takes control
+ * of the clipboard, other applications may open the
+ * clipboard to determine if they want to record the
+ * clipboard updates. When this happens, the clipboard
+ * can not be accessed until the other application is
+ * finished. To allow the other applications to release
+ * the clipboard, use PeekMessage() to enable cross thread
+ * message sends.
+ */
+ int /*long*/[] ppv = new int /*long*/[1];
+ int retryCount = 0;
+ /* OleGetClipboard([out] ppDataObject).
+ * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
+ */
+ int result = COM.OleGetClipboard(ppv);
+ while (result != COM.S_OK && retryCount++ < RETRY_LIMIT) {
+ try {Thread.sleep(50);} catch (Throwable t) {}
+ MSG msg = new MSG();
+ OS.PeekMessage(msg, 0, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
+ result = COM.OleGetClipboard(ppv);
+ }
+ if (result != COM.S_OK) return null;
+ IDataObject dataObject = new IDataObject(ppv[0]);
+ try {
+ TransferData[] allowed = transfer.getSupportedTypes();
+ for (int i = 0; i < allowed.length; i++) {
+ if (dataObject.QueryGetData(allowed[i].formatetc) == COM.S_OK) {
+ TransferData data = allowed[i];
+ data.pIDataObject = ppv[0];
+ return transfer.nativeToJava(data);
+ }
+ }
+ } finally {
+ dataObject.Release();
+ }
+ 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;
+ this.data = data;
+ this.transferAgents = dataTypes;
+ /* OleSetClipboard([in] pDataObject)
+ * The argument pDataObject is owned by the caller so the reference count does not
+ * need to be incremented.
+ */
+ int result = COM.OleSetClipboard(iDataObject.getAddress());
+
+ /*
+ * Bug in Windows. When a new application takes control
+ * of the clipboard, other applications may open the
+ * clipboard to determine if they want to record the
+ * clipboard updates. When this happens, the clipboard
+ * can not be flushed until the other application is
+ * finished. To allow other applications to get the
+ * data, use PeekMessage() to enable cross thread
+ * message sends.
+ */
+ int retryCount = 0;
+ while (result != COM.S_OK && retryCount++ < RETRY_LIMIT) {
+ try {Thread.sleep(50);} catch (Throwable t) {}
+ MSG msg = new MSG();
+ OS.PeekMessage(msg, 0, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
+ result = COM.OleSetClipboard(iDataObject.getAddress());
+ }
+ if (result != COM.S_OK) {
+ DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
+ }
+}
+private int AddRef() {
+ refCount++;
+ return refCount;
+}
+private void createCOMInterfaces() {
+ // register each of the interfaces that this object implements
+ iDataObject = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 2, 3, 2, 4, 1, 1}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return GetData(args[0], args[1]);}
+ // method4 GetDataHere - not implemented
+ public int /*long*/ method5(int /*long*/[] args) {return QueryGetData(args[0]);}
+ // method6 GetCanonicalFormatEtc - not implemented
+ // method7 SetData - not implemented
+ public int /*long*/ method8(int /*long*/[] args) {return EnumFormatEtc((int)/*64*/args[0], args[1]);}
+ // method9 DAdvise - not implemented
+ // method10 DUnadvise - not implemented
+ // method11 EnumDAdvise - not implemented
+ };
+}
+private void disposeCOMInterfaces() {
+ if (iDataObject != null)
+ iDataObject.dispose();
+ iDataObject = null;
+}
+/*
+ * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
+ * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc
+ * must be incremented before returning. Caller is responsible for releasing ppenumFormatetc.
+ */
+private int EnumFormatEtc(int dwDirection, int /*long*/ ppenumFormatetc) {
+ // only allow getting of data - SetData is not currently supported
+ if (dwDirection == COM.DATADIR_SET) return COM.E_NOTIMPL;
+ // what types have been registered?
+ TransferData[] allowedDataTypes = new TransferData[0];
+ for (int i = 0; i < transferAgents.length; i++){
+ TransferData[] formats = transferAgents[i].getSupportedTypes();
+ TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length];
+ System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length);
+ System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length);
+ allowedDataTypes = newAllowedDataTypes;
+ }
+ OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC();
+ enumFORMATETC.AddRef();
+ FORMATETC[] formats = new FORMATETC[allowedDataTypes.length + 1];
+ for (int i = 0; i < allowedDataTypes.length; i++){
+ formats[i] = allowedDataTypes[i].formatetc;
+ }
+ // include the drop effect format to specify a copy operation
+ FORMATETC dropeffect = new FORMATETC();
+ dropeffect.cfFormat = CFSTR_PREFERREDDROPEFFECT;
+ dropeffect.dwAspect = COM.DVASPECT_CONTENT;
+ dropeffect.lindex = -1;
+ dropeffect.tymed = COM.TYMED_HGLOBAL;
+ formats[formats.length -1] = dropeffect;
+ enumFORMATETC.setFormats(formats);
+ OS.MoveMemory(ppenumFormatetc, new int /*long*/[] {enumFORMATETC.getAddress()}, OS.PTR_SIZEOF);
+ return COM.S_OK;
+}
+private int GetData(int /*long*/ pFormatetc, int /*long*/ pmedium) {
+ /* Called by a data consumer to obtain data from a source data object.
+ The GetData method renders the data described in the specified FORMATETC
+ structure and transfers it through the specified STGMEDIUM structure.
+ The caller then assumes responsibility for releasing the STGMEDIUM structure.
+ */
+ if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
+ if (QueryGetData(pFormatetc) != COM.S_OK) return COM.DV_E_FORMATETC;
+
+ TransferData transferData = new TransferData();
+ transferData.formatetc = new FORMATETC();
+ COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+ transferData.type = transferData.formatetc.cfFormat;
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.E_FAIL;
+
+ if (transferData.type == CFSTR_PREFERREDDROPEFFECT) {
+ // specify that a copy operation is to be performed
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ stgmedium.unionField = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, 4);
+ //TODO - should call GlobalLock
+ OS.MoveMemory(stgmedium.unionField, new int[] {COM.DROPEFFECT_COPY}, 4);
+ stgmedium.pUnkForRelease = 0;
+ COM.MoveMemory(pmedium, stgmedium, STGMEDIUM.sizeof);
+ return COM.S_OK;
+ }
+
+ // get matching transfer agent to perform conversion
+ int transferIndex = -1;
+ for (int i = 0; i < transferAgents.length; i++){
+ if (transferAgents[i].isSupportedType(transferData)){
+ transferIndex = i;
+ break;
+ }
+ }
+ if (transferIndex == -1) return COM.DV_E_FORMATETC;
+ transferAgents[transferIndex].javaToNative(data[transferIndex], transferData);
+ COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
+ return transferData.result;
+}
+
+private int QueryGetData(int /*long*/ pFormatetc) {
+ if (transferAgents == null) return COM.E_FAIL;
+ TransferData transferData = new TransferData();
+ transferData.formatetc = new FORMATETC();
+ COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+ transferData.type = transferData.formatetc.cfFormat;
+ if (transferData.type == CFSTR_PREFERREDDROPEFFECT) return COM.S_OK;
+ // is this type supported by the transfer agent?
+ for (int i = 0; i < transferAgents.length; i++){
+ if (transferAgents[i].isSupportedType(transferData))
+ return COM.S_OK;
+ }
+
+ return COM.DV_E_FORMATETC;
+}
+/* QueryInterface([in] iid, [out] ppvObject)
+ * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
+ * must be incremented before returning. Caller is responsible for releasing ppvObject.
+ */
+private int QueryInterface(int /*long*/ riid, int /*long*/ ppvObject) {
+ if (riid == 0 || ppvObject == 0) return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+ if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDataObject) ) {
+ OS.MoveMemory(ppvObject, new int /*long*/[] {iDataObject.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ OS.MoveMemory(ppvObject, new int /*long*/[] {0}, OS.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+private int Release() {
+ refCount--;
+ if (refCount == 0) {
+ this.data = new Object[0];
+ this.transferAgents = new Transfer[0];
+ disposeCOMInterfaces();
+ COM.CoFreeUnusedLibraries();
+ }
+ return refCount;
+}
+
+/**
+ * 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];
+ FORMATETC[] types = _getAvailableTypes();
+ TransferData[] data = new TransferData[types.length];
+ for (int i = 0; i < types.length; i++) {
+ data[i] = new TransferData();
+ data[i].type = types[i].cfFormat;
+ data[i].formatetc = types[i];
+ }
+ return data;
+}
+
+/**
+ * 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();
+ FORMATETC[] types = _getAvailableTypes();
+ String[] names = new String[types.length];
+ int maxSize = 128;
+ for (int i = 0; i < types.length; i++){
+ TCHAR buffer = new TCHAR(0, maxSize);
+ int size = OS.GetClipboardFormatName(types[i].cfFormat, buffer, maxSize);
+ if (size != 0) {
+ names[i] = buffer.toString(0, size);
+ } else {
+ switch (types[i].cfFormat) {
+ case COM.CF_HDROP: names[i] = "CF_HDROP"; break; //$NON-NLS-1$
+ case COM.CF_TEXT: names[i] = "CF_TEXT"; break; //$NON-NLS-1$
+ case COM.CF_BITMAP: names[i] = "CF_BITMAP"; break; //$NON-NLS-1$
+ case COM.CF_METAFILEPICT: names[i] = "CF_METAFILEPICT"; break; //$NON-NLS-1$
+ case COM.CF_SYLK: names[i] = "CF_SYLK"; break; //$NON-NLS-1$
+ case COM.CF_DIF: names[i] = "CF_DIF"; break; //$NON-NLS-1$
+ case COM.CF_TIFF: names[i] = "CF_TIFF"; break; //$NON-NLS-1$
+ case COM.CF_OEMTEXT: names[i] = "CF_OEMTEXT"; break; //$NON-NLS-1$
+ case COM.CF_DIB: names[i] = "CF_DIB"; break; //$NON-NLS-1$
+ case COM.CF_PALETTE: names[i] = "CF_PALETTE"; break; //$NON-NLS-1$
+ case COM.CF_PENDATA: names[i] = "CF_PENDATA"; break; //$NON-NLS-1$
+ case COM.CF_RIFF: names[i] = "CF_RIFF"; break; //$NON-NLS-1$
+ case COM.CF_WAVE: names[i] = "CF_WAVE"; break; //$NON-NLS-1$
+ case COM.CF_UNICODETEXT: names[i] = "CF_UNICODETEXT"; break; //$NON-NLS-1$
+ case COM.CF_ENHMETAFILE: names[i] = "CF_ENHMETAFILE"; break; //$NON-NLS-1$
+ case COM.CF_LOCALE: names[i] = "CF_LOCALE"; break; //$NON-NLS-1$
+ case COM.CF_MAX: names[i] = "CF_MAX"; break; //$NON-NLS-1$
+ default: names[i] = "UNKNOWN"; //$NON-NLS-1$
+ }
+ }
+ }
+ return names;
+}
+
+private FORMATETC[] _getAvailableTypes() {
+ FORMATETC[] types = new FORMATETC[0];
+ int /*long*/[] ppv = new int /*long*/[1];
+ /* OleGetClipboard([out] ppDataObject).
+ * AddRef has already been called on ppDataObject by the callee and must be released by the caller.
+ */
+ if (COM.OleGetClipboard(ppv) != COM.S_OK) return types;
+ IDataObject dataObject = new IDataObject(ppv[0]);
+ int /*long*/[] ppFormatetc = new int /*long*/[1];
+ /* EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
+ * AddRef has already been called on ppenumFormatetc by the callee and must be released by the caller.
+ */
+ int rc = dataObject.EnumFormatEtc(COM.DATADIR_GET, ppFormatetc);
+ dataObject.Release();
+ if (rc != COM.S_OK)return types;
+ IEnumFORMATETC enumFormatetc = new IEnumFORMATETC(ppFormatetc[0]);
+ // Loop over enumerator and save any types that match what we are looking for
+ int /*long*/ rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof);
+ int[] pceltFetched = new int[1];
+ enumFormatetc.Reset();
+ while (enumFormatetc.Next(1, rgelt, pceltFetched) == COM.S_OK && pceltFetched[0] == 1) {
+ FORMATETC formatetc = new FORMATETC();
+ COM.MoveMemory(formatetc, rgelt, FORMATETC.sizeof);
+ FORMATETC[] newTypes = new FORMATETC[types.length + 1];
+ System.arraycopy(types, 0, newTypes, 0, types.length);
+ newTypes[types.length] = formatetc;
+ types = newTypes;
+ }
+ OS.GlobalFree(rgelt);
+ enumFormatetc.Release();
+ return types;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DragSource.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DragSource.java
new file mode 100755
index 0000000000..a7f220de1f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DragSource.java
@@ -0,0 +1,732 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ *
+ * <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>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: DNDExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class DragSource extends Widget {
+
+ // info for registering as a drag source
+ Control control;
+ Listener controlListener;
+ Transfer[] transferAgents = new Transfer[0];
+ DragSourceEffect dragEffect;
+ Composite topControl;
+ int /*long*/ hwndDrag;
+
+ // ole interfaces
+ COMObject iDropSource;
+ COMObject iDataObject;
+ int refCount;
+
+ //workaround - track the operation performed by the drop target for DragEnd event
+ int dataEffect = DND.DROP_NONE;
+
+ static final String DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$
+ static final int CFSTR_PERFORMEDDROPEFFECT = Transfer.registerType("Performed DropEffect"); //$NON-NLS-1$
+ static final TCHAR WindowClass = new TCHAR (0, "#32770", true);
+
+/**
+ * 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);
+ createCOMInterfaces();
+ this.AddRef();
+
+ 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) {
+ DragSource.this.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;
+}
+
+/**
+ * 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 #getDragListeners
+ * @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);
+}
+
+private int AddRef() {
+ refCount++;
+ return refCount;
+}
+
+private void createCOMInterfaces() {
+ // register each of the interfaces that this object implements
+ iDropSource = new COMObject(new int[]{2, 0, 0, 2, 1}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return QueryContinueDrag((int)/*64*/args[0], (int)/*64*/args[1]);}
+ public int /*long*/ method4(int /*long*/[] args) {return GiveFeedback((int)/*64*/args[0]);}
+ };
+
+ iDataObject = new COMObject(new int[]{2, 0, 0, 2, 2, 1, 2, 3, 2, 4, 1, 1}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return GetData(args[0], args[1]);}
+ // method4 GetDataHere - not implemented
+ public int /*long*/ method5(int /*long*/[] args) {return QueryGetData(args[0]);}
+ // method6 GetCanonicalFormatEtc - not implemented
+ public int /*long*/ method7(int /*long*/[] args) {return SetData(args[0], args[1], (int)/*64*/args[2]);}
+ public int /*long*/ method8(int /*long*/[] args) {return EnumFormatEtc((int)/*64*/args[0], args[1]);}
+ // method9 DAdvise - not implemented
+ // method10 DUnadvise - not implemented
+ // method11 EnumDAdvise - not implemented
+ };
+}
+
+protected void checkSubclass() {
+ String name = getClass().getName();
+ String validName = DragSource.class.getName();
+ if (!validName.equals(name)) {
+ DND.error(SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+
+private void disposeCOMInterfaces() {
+ if (iDropSource != null)
+ iDropSource.dispose();
+ iDropSource = null;
+
+ if (iDataObject != null)
+ iDataObject.dispose();
+ iDataObject = null;
+}
+
+private void drag(Event dragEvent) {
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.x = dragEvent.x;
+ event.y = dragEvent.y;
+ event.time = OS.GetMessageTime();
+ event.doit = true;
+ notifyListeners(DND.DragStart,event);
+ if (!event.doit || transferAgents == null || transferAgents.length == 0 ) return;
+
+ int[] pdwEffect = new int[1];
+ int operations = opToOs(getStyle());
+ Display display = control.getDisplay();
+ String key = "org.eclipse.swt.internal.win32.runMessagesInIdle"; //$NON-NLS-1$
+ Object oldValue = display.getData(key);
+ display.setData(key, new Boolean(true));
+ ImageList imagelist = null;
+ Image image = event.image;
+ hwndDrag = 0;
+ topControl = null;
+ if (image != null) {
+ imagelist = new ImageList(SWT.NONE);
+ imagelist.add(image);
+ topControl = control.getShell();
+ /*
+ * Bug in Windows. The image is inverted if the shell is RIGHT_TO_LEFT.
+ * The fix is to create a transparent window that covers the shell client
+ * area and use it during the drag to prevent the image from being inverted.
+ * On XP if the shell is RTL, the image is not displayed.
+ */
+ int offsetX = event.offsetX;
+ hwndDrag = topControl.handle;
+ if ((topControl.getStyle() & SWT.RIGHT_TO_LEFT) != 0) {
+ offsetX = image.getBounds().width - offsetX;
+ RECT rect = new RECT ();
+ OS.GetClientRect (topControl.handle, rect);
+ hwndDrag = OS.CreateWindowEx (
+ OS.WS_EX_TRANSPARENT | OS.WS_EX_NOINHERITLAYOUT,
+ WindowClass,
+ null,
+ OS.WS_CHILD | OS.WS_CLIPSIBLINGS,
+ 0, 0,
+ rect.right - rect.left, rect.bottom - rect.top,
+ topControl.handle,
+ 0,
+ OS.GetModuleHandle (null),
+ null);
+ OS.ShowWindow (hwndDrag, OS.SW_SHOW);
+ }
+ OS.ImageList_BeginDrag(imagelist.getHandle(), 0, offsetX, event.offsetY);
+ /*
+ * Feature in Windows. When ImageList_DragEnter() is called,
+ * it takes a snapshot of the screen If a drag is started
+ * when another window is in front, then the snapshot will
+ * contain part of the other window, causing pixel corruption.
+ * The fix is to force all paints to be delivered before
+ * calling ImageList_DragEnter().
+ */
+ if (OS.IsWinCE) {
+ OS.UpdateWindow (topControl.handle);
+ } else {
+ int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
+ OS.RedrawWindow (topControl.handle, null, 0, flags);
+ }
+ POINT pt = new POINT ();
+ pt.x = dragEvent.x;
+ pt.y = dragEvent.y;
+ OS.MapWindowPoints (control.handle, 0, pt, 1);
+ RECT rect = new RECT ();
+ OS.GetWindowRect (hwndDrag, rect);
+ OS.ImageList_DragEnter(hwndDrag, pt.x - rect.left, pt.y - rect.top);
+ }
+ int result = COM.DRAGDROP_S_CANCEL;
+ try {
+ result = COM.DoDragDrop(iDataObject.getAddress(), iDropSource.getAddress(), operations, pdwEffect);
+ } finally {
+ // ensure that we don't leave transparent window around
+ if (hwndDrag != 0) {
+ OS.ImageList_DragLeave(hwndDrag);
+ OS.ImageList_EndDrag();
+ imagelist.dispose();
+ if (hwndDrag != topControl.handle) OS.DestroyWindow(hwndDrag);
+ hwndDrag = 0;
+ topControl = null;
+ }
+ display.setData(key, oldValue);
+ }
+ int operation = osToOp(pdwEffect[0]);
+ if (dataEffect == DND.DROP_MOVE) {
+ operation = (operation == DND.DROP_NONE || operation == DND.DROP_COPY) ? DND.DROP_TARGET_MOVE : DND.DROP_MOVE;
+ } else {
+ if (dataEffect != DND.DROP_NONE) {
+ operation = dataEffect;
+ }
+ }
+ event = new DNDEvent();
+ event.widget = this;
+ event.time = OS.GetMessageTime();
+ event.doit = (result == COM.DRAGDROP_S_DROP);
+ event.detail = operation;
+ notifyListeners(DND.DragEnd,event);
+ dataEffect = DND.DROP_NONE;
+}
+/*
+ * EnumFormatEtc([in] dwDirection, [out] ppenumFormatetc)
+ * Ownership of ppenumFormatetc transfers from callee to caller so reference count on ppenumFormatetc
+ * must be incremented before returning. Caller is responsible for releasing ppenumFormatetc.
+ */
+private int EnumFormatEtc(int dwDirection, int /*long*/ ppenumFormatetc) {
+ // only allow getting of data - SetData is not currently supported
+ if (dwDirection == COM.DATADIR_SET) return COM.E_NOTIMPL;
+
+ // what types have been registered?
+ TransferData[] allowedDataTypes = new TransferData[0];
+ for (int i = 0; i < transferAgents.length; i++){
+ Transfer transferAgent = transferAgents[i];
+ if (transferAgent != null) {
+ TransferData[] formats = transferAgent.getSupportedTypes();
+ TransferData[] newAllowedDataTypes = new TransferData[allowedDataTypes.length + formats.length];
+ System.arraycopy(allowedDataTypes, 0, newAllowedDataTypes, 0, allowedDataTypes.length);
+ System.arraycopy(formats, 0, newAllowedDataTypes, allowedDataTypes.length, formats.length);
+ allowedDataTypes = newAllowedDataTypes;
+ }
+ }
+
+ OleEnumFORMATETC enumFORMATETC = new OleEnumFORMATETC();
+ enumFORMATETC.AddRef();
+
+ FORMATETC[] formats = new FORMATETC[allowedDataTypes.length];
+ for (int i = 0; i < formats.length; i++){
+ formats[i] = allowedDataTypes[i].formatetc;
+ }
+ enumFORMATETC.setFormats(formats);
+
+ OS.MoveMemory(ppenumFormatetc, new int /*long*/[] {enumFORMATETC.getAddress()}, OS.PTR_SIZEOF);
+ return COM.S_OK;
+}
+/**
+ * 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;
+}
+
+private int GetData(int /*long*/ pFormatetc, int /*long*/ pmedium) {
+ /* Called by a data consumer to obtain data from a source data object.
+ The GetData method renders the data described in the specified FORMATETC
+ structure and transfers it through the specified STGMEDIUM structure.
+ The caller then assumes responsibility for releasing the STGMEDIUM structure.
+ */
+ if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
+
+ if (QueryGetData(pFormatetc) != COM.S_OK) return COM.DV_E_FORMATETC;
+
+ TransferData transferData = new TransferData();
+ transferData.formatetc = new FORMATETC();
+ COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+ transferData.type = transferData.formatetc.cfFormat;
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.E_FAIL;
+
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.time = OS.GetMessageTime();
+ event.dataType = transferData;
+ notifyListeners(DND.DragSetData,event);
+
+ if (!event.doit) return COM.E_FAIL;
+
+ // get matching transfer agent to perform conversion
+ 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 COM.DV_E_FORMATETC;
+ transfer.javaToNative(event.data, transferData);
+ if (transferData.result != COM.S_OK) return transferData.result;
+ COM.MoveMemory(pmedium, transferData.stgmedium, STGMEDIUM.sizeof);
+ return transferData.result;
+}
+
+/**
+ * Returns an array 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.
+ *
+ * @return the listeners who will be notified when a drag and drop
+ * operation is in progress
+ *
+ * @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
+ * @see #removeDragListener
+ * @see DragSourceEvent
+ *
+ * @since 3.4
+ */
+public DragSourceListener[] getDragListeners() {
+ Listener[] listeners = getListeners(DND.DragStart);
+ int length = listeners.length;
+ DragSourceListener[] dragListeners = new DragSourceListener[length];
+ int count = 0;
+ for (int i = 0; i < length; i++) {
+ Listener listener = listeners[i];
+ if (listener instanceof DNDListener) {
+ dragListeners[count] = (DragSourceListener) ((DNDListener) listener).getEventListener();
+ count++;
+ }
+ }
+ if (count == length) return dragListeners;
+ DragSourceListener[] result = new DragSourceListener[count];
+ System.arraycopy(dragListeners, 0, result, 0, count);
+ return result;
+}
+
+/**
+ * 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;
+}
+
+private int GiveFeedback(int dwEffect) {
+ return COM.DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+private int QueryContinueDrag(int fEscapePressed, int grfKeyState) {
+ if (topControl != null && topControl.isDisposed()) return COM.DRAGDROP_S_CANCEL;
+ if (fEscapePressed != 0){
+ if (hwndDrag != 0) OS.ImageList_DragLeave(hwndDrag);
+ return COM.DRAGDROP_S_CANCEL;
+ }
+ /*
+ * Bug in Windows. On some machines that do not have XBUTTONs,
+ * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
+ * causing mouse capture to become stuck. The fix is to test
+ * for the extra buttons only when they exist.
+ */
+ int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
+// if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
+ if ((grfKeyState & mask) == 0) {
+ if (hwndDrag != 0) OS.ImageList_DragLeave(hwndDrag);
+ return COM.DRAGDROP_S_DROP;
+ }
+
+ if (hwndDrag != 0) {
+ POINT pt = new POINT ();
+ OS.GetCursorPos (pt);
+ RECT rect = new RECT ();
+ OS.GetWindowRect (hwndDrag, rect);
+ OS.ImageList_DragMove (pt.x - rect.left, pt.y - rect.top);
+ }
+ return COM.S_OK;
+}
+
+private void onDispose() {
+ if (control == null) return;
+ this.Release();
+ 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;
+}
+
+private int opToOs(int operation) {
+ int osOperation = 0;
+ if ((operation & DND.DROP_COPY) != 0){
+ osOperation |= COM.DROPEFFECT_COPY;
+ }
+ if ((operation & DND.DROP_LINK) != 0) {
+ osOperation |= COM.DROPEFFECT_LINK;
+ }
+ if ((operation & DND.DROP_MOVE) != 0) {
+ osOperation |= COM.DROPEFFECT_MOVE;
+ }
+ return osOperation;
+}
+
+private int osToOp(int osOperation){
+ int operation = 0;
+ if ((osOperation & COM.DROPEFFECT_COPY) != 0){
+ operation |= DND.DROP_COPY;
+ }
+ if ((osOperation & COM.DROPEFFECT_LINK) != 0) {
+ operation |= DND.DROP_LINK;
+ }
+ if ((osOperation & COM.DROPEFFECT_MOVE) != 0) {
+ operation |= DND.DROP_MOVE;
+ }
+ return operation;
+}
+
+private int QueryGetData(int /*long*/ pFormatetc) {
+ if (transferAgents == null) return COM.E_FAIL;
+ TransferData transferData = new TransferData();
+ transferData.formatetc = new FORMATETC();
+ COM.MoveMemory(transferData.formatetc, pFormatetc, FORMATETC.sizeof);
+ transferData.type = transferData.formatetc.cfFormat;
+
+ // is this type supported by the transfer agent?
+ for (int i = 0; i < transferAgents.length; i++){
+ Transfer transfer = transferAgents[i];
+ if (transfer != null && transfer.isSupportedType(transferData))
+ return COM.S_OK;
+ }
+
+ return COM.DV_E_FORMATETC;
+}
+
+/* QueryInterface([in] riid, [out] ppvObject)
+ * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
+ * must be incremented before returning. Caller is responsible for releasing ppvObject.
+ */
+private int QueryInterface(int /*long*/ riid, int /*long*/ ppvObject) {
+ if (riid == 0 || ppvObject == 0)
+ return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+
+ if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDropSource)) {
+ OS.MoveMemory(ppvObject, new int /*long*/[] {iDropSource.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+
+ if (COM.IsEqualGUID(guid, COM.IIDIDataObject) ) {
+ OS.MoveMemory(ppvObject, new int /*long*/[] {iDataObject.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+
+ OS.MoveMemory(ppvObject, new int /*long*/[] {0}, OS.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+
+private int Release() {
+ refCount--;
+ if (refCount == 0) {
+ disposeCOMInterfaces();
+ COM.CoFreeUnusedLibraries();
+ }
+ return refCount;
+}
+
+/**
+ * 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 no longer 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
+ * @see #getDragListeners
+ */
+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);
+}
+
+private int SetData(int /*long*/ pFormatetc, int /*long*/ pmedium, int fRelease) {
+ if (pFormatetc == 0 || pmedium == 0) return COM.E_INVALIDARG;
+ FORMATETC formatetc = new FORMATETC();
+ COM.MoveMemory(formatetc, pFormatetc, FORMATETC.sizeof);
+ if (formatetc.cfFormat == CFSTR_PERFORMEDDROPEFFECT && formatetc.tymed == COM.TYMED_HGLOBAL) {
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ COM.MoveMemory(stgmedium, pmedium,STGMEDIUM.sizeof);
+ //TODO - this should be GlobalLock()
+ int /*long*/[] ptrEffect = new int /*long*/[1];
+ OS.MoveMemory(ptrEffect, stgmedium.unionField, OS.PTR_SIZEOF);
+ int[] effect = new int[1];
+ OS.MoveMemory(effect, ptrEffect[0], 4);
+ dataEffect = osToOp(effect[0]);
+ }
+ if (fRelease == 1) {
+ COM.ReleaseStgMedium(pmedium);
+ }
+ return COM.S_OK;
+}
+
+/**
+ * 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/win32/org/eclipse/swt/dnd/DropTarget.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DropTarget.java
new file mode 100755
index 0000000000..f8720f83fa
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/DropTarget.java
@@ -0,0 +1,781 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ *
+ * Class <code>DropTarget</code> defines the target object for a drag and drop transfer.
+ *
+ * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
+ *
+ * <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>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: DNDExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class DropTarget extends Widget {
+
+ Control control;
+ Listener controlListener;
+ Transfer[] transferAgents = new Transfer[0];
+ DropTargetEffect dropEffect;
+
+ // 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 - The dataobject address is only passed as an argument in drag enter and drop.
+ // To allow applications to query the data values during the drag over operations,
+ // maintain a reference to it.
+ IDataObject iDataObject;
+
+ // interfaces
+ COMObject iDropTarget;
+ int refCount;
+
+ static final String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$
+
+/**
+ * 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 (control.getData(DND.DROP_TARGET_KEY) != null) {
+ DND.error(DND.ERROR_CANNOT_INIT_DROP);
+ }
+ control.setData(DND.DROP_TARGET_KEY, this);
+ createCOMInterfaces();
+ this.AddRef();
+
+ if (COM.CoLockObjectExternal(iDropTarget.getAddress(), true, true) != COM.S_OK)
+ DND.error(DND.ERROR_CANNOT_INIT_DROP);
+ if (COM.RegisterDragDrop( control.handle, iDropTarget.getAddress()) != COM.S_OK)
+ DND.error(DND.ERROR_CANNOT_INIT_DROP);
+
+ 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);
+ }
+}
+
+static int checkStyle (int style) {
+ if (style == SWT.NONE) return DND.DROP_MOVE;
+ return style;
+}
+
+/**
+ * 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 #getDropListeners
+ * @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);
+}
+
+int AddRef() {
+ refCount++;
+ return refCount;
+}
+
+protected void checkSubclass () {
+ String name = getClass().getName ();
+ String validName = DropTarget.class.getName();
+ if (!validName.equals(name)) {
+ DND.error (SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+
+void createCOMInterfaces() {
+ // register each of the interfaces that this object implements
+ boolean is32 = C.PTR_SIZEOF == 4;
+ iDropTarget = new COMObject(new int[]{2, 0, 0, is32 ? 5 : 4, is32 ? 4 : 3, 0, is32 ? 5 : 4}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {
+ if (args.length == 5) {
+ return DragEnter(args[0], (int)/*64*/args[1], (int)/*64*/args[2], (int)/*64*/args[3], args[4]);
+ } else {
+ return DragEnter_64(args[0], (int)/*64*/args[1], args[2], args[3]);
+ }
+ }
+ public int /*long*/ method4(int /*long*/[] args) {
+ if (args.length == 4) {
+ return DragOver((int)/*64*/args[0], (int)/*64*/args[1], (int)/*64*/args[2], args[3]);
+ } else {
+ return DragOver_64((int)/*64*/args[0], args[1], args[2]);
+ }
+ }
+ public int /*long*/ method5(int /*long*/[] args) {return DragLeave();}
+ public int /*long*/ method6(int /*long*/[] args) {
+ if (args.length == 5) {
+ return Drop(args[0], (int)/*64*/args[1], (int)/*64*/args[2], (int)/*64*/args[3], args[4]);
+ } else {
+ return Drop_64(args[0], (int)/*64*/args[1], args[2], args[3]);
+ }
+ }
+ };
+}
+
+void disposeCOMInterfaces() {
+ if (iDropTarget != null)
+ iDropTarget.dispose();
+ iDropTarget = null;
+}
+
+int DragEnter_64(int /*long*/ pDataObject, int grfKeyState, long pt, int /*long*/ pdwEffect) {
+ POINT point = new POINT();
+ OS.MoveMemory(point, new long[]{pt}, 8);
+ return DragEnter(pDataObject, grfKeyState, point.x, point.y, pdwEffect);
+}
+
+int DragEnter(int /*long*/ pDataObject, int grfKeyState, int pt_x, int pt_y, int /*long*/ pdwEffect) {
+ selectedDataType = null;
+ selectedOperation = DND.DROP_NONE;
+ if (iDataObject != null) iDataObject.Release();
+ iDataObject = null;
+
+ DNDEvent event = new DNDEvent();
+ if (!setEventData(event, pDataObject, grfKeyState, pt_x, pt_y, pdwEffect)) {
+ OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+ return COM.S_FALSE;
+ }
+
+ // Remember the iDataObject because it is not passed into the DragOver callback
+ iDataObject = new IDataObject(pDataObject);
+ iDataObject.AddRef();
+
+ int allowedOperations = event.operations;
+ TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+ System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+ notifyListeners(DND.DragEnter, event);
+ refresh();
+ if (event.detail == DND.DROP_DEFAULT) {
+ event.detail = (allowedOperations & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+ }
+
+ selectedDataType = null;
+ for (int i = 0; i < allowedDataTypes.length; i++) {
+ if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
+ selectedDataType = allowedDataTypes[i];
+ break;
+ }
+ }
+
+ selectedOperation = DND.DROP_NONE;
+ if (selectedDataType != null && ((allowedOperations & event.detail) != 0)) {
+ selectedOperation = event.detail;
+ }
+
+ OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
+ return COM.S_OK;
+}
+
+int DragLeave() {
+ keyOperation = -1;
+
+ if (iDataObject == null) return COM.S_FALSE;
+
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.time = OS.GetMessageTime();
+ event.detail = DND.DROP_NONE;
+ notifyListeners(DND.DragLeave, event);
+ refresh();
+
+ iDataObject.Release();
+ iDataObject = null;
+ return COM.S_OK;
+}
+
+int DragOver_64(int grfKeyState, long pt, int /*long*/ pdwEffect) {
+ POINT point = new POINT();
+ OS.MoveMemory(point, new long[]{pt}, 8);
+ return DragOver(grfKeyState, point.x, point.y, pdwEffect);
+}
+
+int DragOver(int grfKeyState, int pt_x, int pt_y, int /*long*/ pdwEffect) {
+ if (iDataObject == null) return COM.S_FALSE;
+ int oldKeyOperation = keyOperation;
+
+ DNDEvent event = new DNDEvent();
+ if (!setEventData(event, iDataObject.getAddress(), grfKeyState, pt_x, pt_y, pdwEffect)) {
+ keyOperation = -1;
+ OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+ return COM.S_FALSE;
+ }
+
+ int allowedOperations = event.operations;
+ TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+ System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+
+ if (keyOperation == oldKeyOperation) {
+ event.type = DND.DragOver;
+ event.dataType = selectedDataType;
+ event.detail = selectedOperation;
+ } else {
+ event.type = DND.DragOperationChanged;
+ event.dataType = selectedDataType;
+ }
+ notifyListeners(event.type, event);
+ refresh();
+ if (event.detail == DND.DROP_DEFAULT) {
+ event.detail = (allowedOperations & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+ }
+
+ selectedDataType = null;
+ for (int i = 0; i < allowedDataTypes.length; i++) {
+ if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
+ selectedDataType = allowedDataTypes[i];
+ break;
+ }
+ }
+
+ selectedOperation = DND.DROP_NONE;
+ if (selectedDataType != null && ((allowedOperations & event.detail) == event.detail)) {
+ selectedOperation = event.detail;
+ }
+
+ OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
+ return COM.S_OK;
+}
+
+int Drop_64(int /*long*/ pDataObject, int grfKeyState, long pt, int /*long*/ pdwEffect) {
+ POINT point = new POINT();
+ OS.MoveMemory(point, new long[]{pt}, 8);
+ return Drop(pDataObject, grfKeyState, point.x, point.y, pdwEffect);
+}
+
+int Drop(int /*long*/ pDataObject, int grfKeyState, int pt_x, int pt_y, int /*long*/ pdwEffect) {
+ DNDEvent event = new DNDEvent();
+ event.widget = this;
+ event.time = OS.GetMessageTime();
+ if (dropEffect != null) {
+ event.item = dropEffect.getItem(pt_x, pt_y);
+ }
+ event.detail = DND.DROP_NONE;
+ notifyListeners(DND.DragLeave, event);
+ refresh();
+
+ event = new DNDEvent();
+ if (!setEventData(event, pDataObject, grfKeyState, pt_x, pt_y, pdwEffect)) {
+ keyOperation = -1;
+ OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+ return COM.S_FALSE;
+ }
+ keyOperation = -1;
+ int allowedOperations = event.operations;
+ TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+ System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+ event.dataType = selectedDataType;
+ event.detail = selectedOperation;
+ notifyListeners(DND.DropAccept,event);
+ refresh();
+
+ selectedDataType = null;
+ for (int i = 0; i < allowedDataTypes.length; i++) {
+ if (TransferData.sameType(allowedDataTypes[i], event.dataType)){
+ selectedDataType = allowedDataTypes[i];
+ break;
+ }
+ }
+ selectedOperation = DND.DROP_NONE;
+ if (selectedDataType != null && (allowedOperations & event.detail) == event.detail) {
+ selectedOperation = event.detail;
+ }
+
+ if (selectedOperation == DND.DROP_NONE){
+ OS.MoveMemory(pdwEffect, new int[] {COM.DROPEFFECT_NONE}, 4);
+ return COM.S_OK;
+ }
+
+ // 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)){
+ object = transfer.nativeToJava(selectedDataType);
+ break;
+ }
+ }
+ if (object == null){
+ selectedOperation = DND.DROP_NONE;
+ }
+
+ event.detail = selectedOperation;
+ event.dataType = selectedDataType;
+ event.data = object;
+ OS.ImageList_DragShowNolock(false);
+ try {
+ notifyListeners(DND.Drop,event);
+ } finally {
+ OS.ImageList_DragShowNolock(true);
+ }
+ refresh();
+ selectedOperation = DND.DROP_NONE;
+ if ((allowedOperations & event.detail) == event.detail) {
+ selectedOperation = event.detail;
+ }
+ //notify source of action taken
+ OS.MoveMemory(pdwEffect, new int[] {opToOs(selectedOperation)}, 4);
+ return COM.S_OK;
+}
+
+/**
+ * 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 an array 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.
+ *
+ * @return the listeners who will be notified when a drag and drop
+ * operation is in progress
+ *
+ * @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
+ * @see #removeDropListener
+ * @see DropTargetEvent
+ *
+ * @since 3.4
+ */
+public DropTargetListener[] getDropListeners() {
+ Listener[] listeners = getListeners(DND.DragEnter);
+ int length = listeners.length;
+ DropTargetListener[] dropListeners = new DropTargetListener[length];
+ int count = 0;
+ for (int i = 0; i < length; i++) {
+ Listener listener = listeners[i];
+ if (listener instanceof DNDListener) {
+ dropListeners[count] = (DropTargetListener) ((DNDListener) listener).getEventListener();
+ count++;
+ }
+ }
+ if (count == length) return dropListeners;
+ DropTargetListener[] result = new DropTargetListener[count];
+ System.arraycopy(dropListeners, 0, result, 0, count);
+ return result;
+}
+
+/**
+ * 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 grfKeyState) {
+ boolean ctrl = (grfKeyState & OS.MK_CONTROL) != 0;
+ boolean shift = (grfKeyState & OS.MK_SHIFT) != 0;
+ boolean alt = (grfKeyState & OS.MK_ALT) != 0;
+ if (alt) {
+ if (ctrl || shift) return DND.DROP_DEFAULT;
+ return DND.DROP_LINK;
+ }
+ if (ctrl && shift) return DND.DROP_LINK;
+ if (ctrl)return DND.DROP_COPY;
+ if (shift)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;
+
+ COM.RevokeDragDrop(control.handle);
+
+ if (controlListener != null)
+ control.removeListener(SWT.Dispose, controlListener);
+ controlListener = null;
+ control.setData(DND.DROP_TARGET_KEY, null);
+ transferAgents = null;
+ control = null;
+
+ COM.CoLockObjectExternal(iDropTarget.getAddress(), false, true);
+
+ this.Release();
+
+ COM.CoFreeUnusedLibraries();
+}
+
+int opToOs(int operation) {
+ int osOperation = 0;
+ if ((operation & DND.DROP_COPY) != 0){
+ osOperation |= COM.DROPEFFECT_COPY;
+ }
+ if ((operation & DND.DROP_LINK) != 0) {
+ osOperation |= COM.DROPEFFECT_LINK;
+ }
+ if ((operation & DND.DROP_MOVE) != 0) {
+ osOperation |= COM.DROPEFFECT_MOVE;
+ }
+ return osOperation;
+}
+
+int osToOp(int osOperation){
+ int operation = 0;
+ if ((osOperation & COM.DROPEFFECT_COPY) != 0){
+ operation |= DND.DROP_COPY;
+ }
+ if ((osOperation & COM.DROPEFFECT_LINK) != 0) {
+ operation |= DND.DROP_LINK;
+ }
+ if ((osOperation & COM.DROPEFFECT_MOVE) != 0) {
+ operation |= DND.DROP_MOVE;
+ }
+ return operation;
+}
+
+/* QueryInterface([in] iid, [out] ppvObject)
+ * Ownership of ppvObject transfers from callee to caller so reference count on ppvObject
+ * must be incremented before returning. Caller is responsible for releasing ppvObject.
+ */
+int QueryInterface(int /*long*/ riid, int /*long*/ ppvObject) {
+
+ if (riid == 0 || ppvObject == 0)
+ return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+ if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIDropTarget)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iDropTarget.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+
+ COM.MoveMemory(ppvObject, new int /*long*/[] {0}, OS.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+
+int Release() {
+ refCount--;
+
+ if (refCount == 0) {
+ disposeCOMInterfaces();
+ COM.CoFreeUnusedLibraries();
+ }
+
+ return refCount;
+}
+
+void refresh() {
+ if (control == null || control.isDisposed()) return;
+ int /*long*/ handle = control.handle;
+ RECT lpRect = new RECT();
+ if (OS.GetUpdateRect(handle, lpRect, false)) {
+ OS.ImageList_DragShowNolock(false);
+ OS.RedrawWindow(handle, lpRect, 0, OS.RDW_UPDATENOW | OS.RDW_INVALIDATE);
+ OS.ImageList_DragShowNolock(true);
+ }
+}
+
+/**
+ * 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 no longer 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
+ * @see #getDropListeners
+ */
+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(DNDEvent event, int /*long*/ pDataObject, int grfKeyState, int pt_x, int pt_y, int /*long*/ pdwEffect) {
+ if (pDataObject == 0 || pdwEffect == 0) return false;
+
+ // get allowed operations
+ int style = getStyle();
+ int[] operations = new int[1];
+ OS.MoveMemory(operations, pdwEffect, 4);
+ operations[0] = osToOp(operations[0]) & style;
+ if (operations[0] == DND.DROP_NONE) return false;
+
+ // get current operation
+ int operation = getOperationFromKeyState(grfKeyState);
+ keyOperation = operation;
+ if (operation == DND.DROP_DEFAULT) {
+ if ((style & DND.DROP_DEFAULT) == 0) {
+ operation = (operations[0] & DND.DROP_MOVE) != 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+ }
+ } else {
+ if ((operation & operations[0]) == 0) operation = DND.DROP_NONE;
+ }
+
+ // Get allowed transfer types
+ TransferData[] dataTypes = new TransferData[0];
+ IDataObject dataObject = new IDataObject(pDataObject);
+ dataObject.AddRef();
+ try {
+ int /*long*/[] address = new int /*long*/[1];
+ if (dataObject.EnumFormatEtc(COM.DATADIR_GET, address) != COM.S_OK) {
+ return false;
+ }
+ IEnumFORMATETC enumFormatetc = new IEnumFORMATETC(address[0]);
+ try {
+ // Loop over enumerator and save any types that match what we are looking for
+ int /*long*/ rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, FORMATETC.sizeof);
+ try {
+ int[] pceltFetched = new int[1];
+ enumFormatetc.Reset();
+ while (enumFormatetc.Next(1, rgelt, pceltFetched) == COM.S_OK && pceltFetched[0] == 1) {
+ TransferData transferData = new TransferData();
+ transferData.formatetc = new FORMATETC();
+ COM.MoveMemory(transferData.formatetc, rgelt, FORMATETC.sizeof);
+ transferData.type = transferData.formatetc.cfFormat;
+ transferData.pIDataObject = pDataObject;
+ for (int i = 0; i < transferAgents.length; i++){
+ Transfer transfer = transferAgents[i];
+ if (transfer != null && transfer.isSupportedType(transferData)){
+ TransferData[] newDataTypes = new TransferData[dataTypes.length + 1];
+ System.arraycopy(dataTypes, 0, newDataTypes, 0, dataTypes.length);
+ newDataTypes[dataTypes.length] = transferData;
+ dataTypes = newDataTypes;
+ break;
+ }
+ }
+ }
+ } finally {
+ OS.GlobalFree(rgelt);
+ }
+ } finally {
+ enumFormatetc.Release();
+ }
+ } finally {
+ dataObject.Release();
+ }
+ if (dataTypes.length == 0) return false;
+
+ event.widget = this;
+ event.x = pt_x;
+ event.y = pt_y;
+ event.time = OS.GetMessageTime();
+ event.feedback = DND.FEEDBACK_SELECT;
+ event.dataTypes = dataTypes;
+ event.dataType = dataTypes[0];
+ if (dropEffect != null) {
+ event.item = dropEffect.getItem(pt_x, pt_y);
+ }
+ event.operations = operations[0];
+ event.detail = operation;
+ 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;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/FileTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/FileTransfer.java
new file mode 100755
index 0000000000..8acb6456d1
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/FileTransfer.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * 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.
+ *
+ * <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>
+ *
+ * @see Transfer
+ */
+public class FileTransfer extends ByteArrayTransfer {
+
+ private static FileTransfer _instance = new FileTransfer();
+ private static final String CF_HDROP = "CF_HDROP "; //$NON-NLS-1$
+ private static final int CF_HDROPID = COM.CF_HDROP;
+ private static final String CF_HDROP_SEPARATOR = "\0"; //$NON-NLS-1$
+
+private 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.
+ *
+ * @param object a java <code>String[]</code> containing the file names to be converted
+ * @param transferData an empty <code>TransferData</code> object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+public void javaToNative(Object object, TransferData transferData) {
+ if (!checkFile(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ String[] fileNames = (String[]) object;
+ StringBuffer allFiles = new StringBuffer();
+ for (int i = 0; i < fileNames.length; i++) {
+ allFiles.append(fileNames[i]);
+ allFiles.append(CF_HDROP_SEPARATOR); // each name is null terminated
+ }
+ TCHAR buffer = new TCHAR(0, allFiles.toString(), true); // there is an extra null terminator at the very end
+ DROPFILES dropfiles = new DROPFILES();
+ dropfiles.pFiles = DROPFILES.sizeof;
+ dropfiles.pt_x = dropfiles.pt_y = 0;
+ dropfiles.fNC = 0;
+ dropfiles.fWide = OS.IsUnicode ? 1 : 0;
+ // Allocate the memory because the caller (DropTarget) has not handed it in
+ // The caller of this method must release the data when it is done with it.
+ int byteCount = buffer.length() * TCHAR.sizeof;
+ int /*long*/ newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, DROPFILES.sizeof + byteCount);
+ OS.MoveMemory(newPtr, dropfiles, DROPFILES.sizeof);
+ OS.MoveMemory(newPtr + DROPFILES.sizeof, buffer, byteCount);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = newPtr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+}
+
+/**
+ * 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.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java <code>String[]</code> containing a list of file names if the conversion
+ * was successful; otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+public Object nativeToJava(TransferData transferData) {
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+
+ // get file names from IDataObject
+ IDataObject dataObject = new IDataObject(transferData.pIDataObject);
+ dataObject.AddRef();
+ FORMATETC formatetc = new FORMATETC();
+ formatetc.cfFormat = COM.CF_HDROP;
+ formatetc.ptd = 0;
+ formatetc.dwAspect = COM.DVASPECT_CONTENT;
+ formatetc.lindex = -1;
+ formatetc.tymed = COM.TYMED_HGLOBAL;
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(dataObject, formatetc, stgmedium);
+ dataObject.Release();
+ if (transferData.result != COM.S_OK) return null;
+ // How many files are there?
+ int count = OS.DragQueryFile(stgmedium.unionField, 0xFFFFFFFF, null, 0);
+ String[] fileNames = new String[count];
+ for (int i = 0; i < count; i++) {
+ // How long is the name ?
+ int size = OS.DragQueryFile(stgmedium.unionField, i, null, 0) + 1;
+ TCHAR lpszFile = new TCHAR(0, size);
+ // Get file name and append it to string
+ OS.DragQueryFile(stgmedium.unionField, i, lpszFile, size);
+ fileNames[i] = lpszFile.toString(0, lpszFile.strlen());
+ }
+ OS.DragFinish(stgmedium.unionField); // frees data associated with HDROP data
+ return fileNames;
+}
+
+protected int[] getTypeIds(){
+ return new int[] {CF_HDROPID};
+}
+
+protected String[] getTypeNames(){
+ return new String[] {CF_HDROP};
+}
+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/win32/org/eclipse/swt/dnd/HTMLTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/HTMLTransfer.java
new file mode 100644
index 0000000000..9664d49d67
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/HTMLTransfer.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * 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.
+ *
+ * <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>
+ *
+ * @see Transfer
+ */
+public class HTMLTransfer extends ByteArrayTransfer {
+
+ static HTMLTransfer _instance = new HTMLTransfer();
+ static final String HTML_FORMAT = "HTML Format"; //$NON-NLS-1$
+ static final int HTML_FORMATID = registerType(HTML_FORMAT);
+ static final String NUMBER = "00000000"; //$NON-NLS-1$
+ static final String HEADER = "Version:0.9\r\nStartHTML:"+NUMBER+"\r\nEndHTML:"+NUMBER+"\r\nStartFragment:"+NUMBER+"\r\nEndFragment:"+NUMBER+"\r\n";
+ static final String PREFIX = "<html><body><!--StartFragment-->"; //$NON-NLS-1$
+ static final String SUFFIX = "<!--EndFragment--></body></html>"; //$NON-NLS-1$
+ static final String StartFragment = "StartFragment:"; //$NON-NLS-1$
+ static final String EndFragment = "EndFragment:"; //$NON-NLS-1$
+
+private 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.
+ *
+ * @param object a java <code>String</code> containing HTML text
+ * @param transferData an empty <code>TransferData</code> object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+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 + 1];
+ string.getChars(0, count, chars, 0);
+ /* NOTE: CF_HTML uses UTF-8 encoding. */
+ int cchMultiByte = OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, -1, null, 0, null, null);
+ if (cchMultiByte == 0) {
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.DV_E_STGMEDIUM;
+ return;
+ }
+ int startHTML = HEADER.length();
+ int startFragment = startHTML + PREFIX.length();
+ int endFragment = startFragment + cchMultiByte - 1;
+ int endHTML = endFragment + SUFFIX.length();
+
+ StringBuffer buffer = new StringBuffer(HEADER);
+ int maxLength = NUMBER.length();
+ //startHTML
+ int start = buffer.toString().indexOf(NUMBER);
+ String temp = Integer.toString(startHTML);
+ buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+ //endHTML
+ start = buffer.toString().indexOf(NUMBER, start);
+ temp = Integer.toString(endHTML);
+ buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+ //startFragment
+ start = buffer.toString().indexOf(NUMBER, start);
+ temp = Integer.toString(startFragment);
+ buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+ //endFragment
+ start = buffer.toString().indexOf(NUMBER, start);
+ temp = Integer.toString(endFragment);
+ buffer.replace(start + maxLength-temp.length(), start + maxLength, temp);
+
+ buffer.append(PREFIX);
+ buffer.append(string);
+ buffer.append(SUFFIX);
+
+ count = buffer.length();
+ chars = new char[count + 1];
+ buffer.getChars(0, count, chars, 0);
+ cchMultiByte = OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, -1, null, 0, null, null);
+ int /*long*/ lpMultiByteStr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, cchMultiByte);
+ OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = lpMultiByteStr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ return;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of HTML 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 HTML text if the conversion was successful;
+ * otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ FORMATETC formatetc = transferData.formatetc;
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ int /*long*/ hMem = stgmedium.unionField;
+
+ try {
+ int /*long*/ lpMultiByteStr = OS.GlobalLock(hMem);
+ if (lpMultiByteStr == 0) return null;
+ try {
+ /* NOTE: CF_HTML uses UTF-8 encoding.
+ * The MSDN documentation for MultiByteToWideChar states that dwFlags must be set to 0 for UTF-8.
+ * Otherwise, the function fails with ERROR_INVALID_FLAGS. */
+ int cchWideChar = OS.MultiByteToWideChar (OS.CP_UTF8, 0, lpMultiByteStr, -1, null, 0);
+ if (cchWideChar == 0) return null;
+ char[] lpWideCharStr = new char [cchWideChar - 1];
+ OS.MultiByteToWideChar (OS.CP_UTF8, 0, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+ String string = new String(lpWideCharStr);
+ int fragmentStart = 0, fragmentEnd = 0;
+ int start = string.indexOf(StartFragment) + StartFragment.length();
+ int end = start + 1;
+ while (end < string.length()) {
+ String s = string.substring(start, end);
+ try {
+ fragmentStart = Integer.parseInt(s);
+ end++;
+ } catch (NumberFormatException e) {
+ break;
+ }
+ }
+ start = string.indexOf(EndFragment) + EndFragment.length();
+ end = start + 1;
+ while (end < string.length()) {
+ String s = string.substring(start, end);
+ try {
+ fragmentEnd = Integer.parseInt(s);
+ end++;
+ } catch (NumberFormatException e) {
+ break;
+ }
+ }
+ if (fragmentEnd <= fragmentStart || fragmentEnd > OS.strlen(lpMultiByteStr)) return null;
+ cchWideChar = OS.MultiByteToWideChar (OS.CP_UTF8, 0, lpMultiByteStr+fragmentStart, fragmentEnd - fragmentStart, lpWideCharStr, lpWideCharStr.length);
+ if (cchWideChar == 0) return null;
+ String s = new String(lpWideCharStr, 0, cchWideChar);
+ /*
+ * Firefox includes <!--StartFragment --> in the fragment, so remove it.
+ */
+ String foxStart = "<!--StartFragment -->\r\n"; //$NON-NLS-1$
+ int prefix = s.indexOf(foxStart);
+ if (prefix != -1) {
+ prefix += foxStart.length();
+ s = s.substring(prefix);
+ }
+ return s;
+ } finally {
+ OS.GlobalUnlock(hMem);
+ }
+ } finally {
+ OS.GlobalFree(hMem);
+ }
+}
+protected int[] getTypeIds(){
+ return new int[] {HTML_FORMATID};
+}
+protected String[] getTypeNames(){
+ return new String[] {HTML_FORMAT};
+}
+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/win32/org/eclipse/swt/dnd/ImageTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ImageTransfer.java
new file mode 100644
index 0000000000..426adf1bcf
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ImageTransfer.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 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.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * 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.
+ *
+ * <p>An example of a java <code>ImageData</code> is shown below:</p>
+ *
+ * <code><pre>
+ * Image image = new Image(display, "C:\temp\img1.gif");
+ * ImageData imgData = image.getImageData();
+ * </code></pre>
+ *
+ * @see Transfer
+ *
+ * @since 3.4
+ */
+public class ImageTransfer extends ByteArrayTransfer {
+
+ private static ImageTransfer _instance = new ImageTransfer();
+ private static final String CF_DIB = "CF_DIB"; //$NON-NLS-1$
+ private static final int CF_DIBID = COM.CF_DIB;
+
+private 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 java <code>ImageData</code> to a platform specific representation.
+ *
+ * @param object a java <code>ImageData</code> containing the ImageData to be converted
+ * @param transferData an empty <code>TransferData</code> object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+public void javaToNative(Object object, TransferData transferData) {
+ if (!checkImage(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ ImageData imgData = (ImageData)object;
+ if (imgData == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+
+ int imageSize = imgData.data.length;
+ int imageHeight = imgData.height;
+ int bytesPerLine = imgData.bytesPerLine;
+
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biSizeImage = imageSize;
+ bmiHeader.biWidth = imgData.width;
+ bmiHeader.biHeight = imageHeight;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = (short)imgData.depth;
+ bmiHeader.biCompression = OS.DIB_RGB_COLORS;
+
+ int colorSize = 0;
+ if (bmiHeader.biBitCount <= 8) {
+ colorSize += (1 << bmiHeader.biBitCount) * 4;
+ }
+ byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + colorSize];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+
+ RGB[] rgbs = imgData.palette.getRGBs();
+ if (rgbs != null && colorSize > 0) {
+ int offset = BITMAPINFOHEADER.sizeof;
+ for (int j = 0; j < rgbs.length; j++) {
+ bmi[offset] = (byte)rgbs[j].blue;
+ bmi[offset + 1] = (byte)rgbs[j].green;
+ bmi[offset + 2] = (byte)rgbs[j].red;
+ bmi[offset + 3] = 0;
+ offset += 4;
+ }
+ }
+ int /*long*/ newPtr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, BITMAPINFOHEADER.sizeof + colorSize + imageSize);
+ OS.MoveMemory(newPtr, bmi, bmi.length);
+ int /*long*/ pBitDest = newPtr + BITMAPINFOHEADER.sizeof + colorSize;
+
+ if (imageHeight <= 0) {
+ OS.MoveMemory(pBitDest, imgData.data, imageSize);
+ } else {
+ int offset = 0;
+ pBitDest += bytesPerLine * (imageHeight - 1);
+ byte[] scanline = new byte[bytesPerLine];
+ for (int i = 0; i < imageHeight; i++) {
+ System.arraycopy(imgData.data, offset, scanline, 0, bytesPerLine);
+ OS.MoveMemory(pBitDest, scanline, bytesPerLine);
+ offset += bytesPerLine;
+ pBitDest -= bytesPerLine;
+ }
+ }
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = newPtr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+}
+
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of an image to java <code>ImageData</code>.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java <code>ImageData</code> of the image if the conversion was successful;
+ * otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+public Object nativeToJava(TransferData transferData) {
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+ IDataObject dataObject = new IDataObject(transferData.pIDataObject);
+ dataObject.AddRef();
+ FORMATETC formatetc = new FORMATETC();
+ formatetc.cfFormat = COM.CF_DIB;
+ formatetc.ptd = 0;
+ formatetc.dwAspect = COM.DVASPECT_CONTENT;
+ formatetc.lindex = -1;
+ formatetc.tymed = COM.TYMED_HGLOBAL;
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(dataObject, formatetc, stgmedium);
+
+ if (transferData.result != COM.S_OK) return null;
+ int /*long*/ hMem = stgmedium.unionField;
+ dataObject.Release();
+ try {
+ int /*long*/ ptr = OS.GlobalLock(hMem);
+ if (ptr == 0) return null;
+ try {
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ OS.MoveMemory(bmiHeader, ptr, BITMAPINFOHEADER.sizeof);
+ int /*long*/[] pBits = new int /*long*/[1];
+ int /*long*/ memDib = OS.CreateDIBSection(0, ptr, OS.DIB_RGB_COLORS, pBits, 0, 0);
+ if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ bits = ptr + bmiHeader.biSize;
+ if (bmiHeader.biBitCount <= 8) {
+ bits += (bmiHeader.biClrUsed == 0 ? (1 << bmiHeader.biBitCount) : bmiHeader.biClrUsed) * 4;
+ } else if (bmiHeader.biCompression == OS.BI_BITFIELDS) {
+ bits += 12;
+ }
+ if (bmiHeader.biHeight < 0) {
+ OS.MoveMemory(pBits[0], bits, bmiHeader.biSizeImage);
+ } else {
+ DIBSECTION dib = new DIBSECTION();
+ OS.GetObject(memDib, DIBSECTION.sizeof, dib);
+ int biHeight = dib.biHeight;
+ int scanline = dib.biSizeImage / biHeight;
+ int /*long*/ pDestBits = pBits[0];
+ int /*long*/ pSourceBits = bits + scanline * (biHeight - 1);
+ for (int i = 0; i < biHeight; i++) {
+ OS.MoveMemory(pDestBits, pSourceBits, scanline);
+ pDestBits += scanline;
+ pSourceBits -= scanline;
+ }
+ }
+ Image image = Image.win32_new(null, SWT.BITMAP, memDib);
+ ImageData data = image.getImageData();
+ OS.DeleteObject(memDib);
+ image.dispose();
+ return data;
+ } finally {
+ OS.GlobalUnlock(hMem);
+ }
+ } finally {
+ OS.GlobalFree(hMem);
+ }
+}
+
+protected int[] getTypeIds(){
+ return new int[] {CF_DIBID};
+}
+
+protected String[] getTypeNames(){
+ return new String[] {CF_DIB};
+}
+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/win32/org/eclipse/swt/dnd/OleEnumFORMATETC.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/OleEnumFORMATETC.java
new file mode 100755
index 0000000000..c1c8c1fbd6
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/OleEnumFORMATETC.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * 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.win32.*;
+import org.eclipse.swt.internal.ole.win32.*;
+
+final class OleEnumFORMATETC {
+
+ private COMObject iUnknown;
+ private COMObject iEnumFORMATETC;
+
+ private int refCount;
+ private int index;
+
+ private FORMATETC[] formats;
+
+OleEnumFORMATETC() {
+
+ createCOMInterfaces();
+
+}
+int AddRef() {
+ refCount++;
+ return refCount;
+}
+private void createCOMInterfaces() {
+ // register each of the interfaces that this object implements
+ iUnknown = new COMObject(new int[] {2, 0, 0}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ };
+ iEnumFORMATETC = new COMObject(new int[] {2, 0, 0, 3, 1, 0, 1}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return Next((int)/*64*/args[0], args[1], args[2]);}
+ public int /*long*/ method4(int /*long*/[] args) {return Skip((int)/*64*/args[0]);}
+ public int /*long*/ method5(int /*long*/[] args) {return Reset();}
+ // method6 Clone - not implemented
+ };
+}
+private void disposeCOMInterfaces() {
+
+ if (iUnknown != null)
+ iUnknown.dispose();
+ iUnknown = null;
+
+ if (iEnumFORMATETC != null)
+ iEnumFORMATETC.dispose();
+ iEnumFORMATETC = null;
+}
+int /*long*/ getAddress() {
+ return iEnumFORMATETC.getAddress();
+}
+private FORMATETC[] getNextItems(int numItems){
+
+ if (formats == null || numItems < 1) return null;
+
+ int endIndex = index + numItems - 1;
+ if (endIndex > (formats.length - 1)) endIndex = formats.length - 1;
+ if (index > endIndex) return null;
+
+ FORMATETC[] items = new FORMATETC[endIndex - index + 1];
+ for (int i = 0; i < items.length; i++){
+ items[i] = formats[index];
+ index++;
+ }
+
+ return items;
+}
+private int Next(int celt, int /*long*/ rgelt, int /*long*/ pceltFetched) {
+ /* Retrieves the next celt items in the enumeration sequence.
+ If there are fewer than the requested number of elements left in the sequence,
+ it retrieves the remaining elements.
+ The number of elements actually retrieved is returned through pceltFetched
+ (unless the caller passed in NULL for that parameter).
+ */
+
+ if (rgelt == 0) return COM.E_INVALIDARG;
+ if (pceltFetched == 0 && celt != 1) return COM.E_INVALIDARG;
+
+ FORMATETC[] nextItems = getNextItems(celt);
+ if (nextItems != null) {
+ for (int i = 0; i < nextItems.length; i++) {
+ COM.MoveMemory(rgelt + i*FORMATETC.sizeof, nextItems[i], FORMATETC.sizeof);
+ }
+
+ if (pceltFetched != 0)
+ COM.MoveMemory(pceltFetched, new int[] {nextItems.length}, 4);
+
+ if (nextItems.length == celt) return COM.S_OK;
+
+ } else {
+ if (pceltFetched != 0)
+ COM.MoveMemory(pceltFetched, new int[] {0}, 4);
+ COM.MoveMemory(rgelt, new FORMATETC(), FORMATETC.sizeof);
+
+ }
+ return COM.S_FALSE;
+}
+private int QueryInterface(int /*long*/ riid, int /*long*/ ppvObject) {
+
+ if (riid == 0 || ppvObject == 0) return COM.E_NOINTERFACE;
+
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+
+ if (COM.IsEqualGUID(guid, COM.IIDIUnknown)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iUnknown.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIEnumFORMATETC)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iEnumFORMATETC.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ COM.MoveMemory(ppvObject, new int /*long*/[] {0}, OS.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+int Release() {
+ refCount--;
+
+ if (refCount == 0) {
+ disposeCOMInterfaces();
+ COM.CoFreeUnusedLibraries();
+ }
+
+ return refCount;
+}
+private int Reset() {
+ //Resets the enumeration sequence to the beginning.
+ index = 0;
+ return COM.S_OK;
+}
+void setFormats(FORMATETC[] newFormats) {
+ formats = newFormats;
+ index = 0;
+}
+private int Skip(int celt) {
+ //Skips over the next specified number of elements in the enumeration sequence.
+ if (celt < 1 ) return COM.E_INVALIDARG;
+
+ index += celt;
+ if (index > (formats.length - 1)){
+ index = formats.length - 1;
+ return COM.S_FALSE;
+ }
+ return COM.S_OK;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/RTFTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/RTFTransfer.java
new file mode 100755
index 0000000000..f8da4986c4
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/RTFTransfer.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * 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.
+ *
+ * <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>
+ *
+ * @see Transfer
+ */
+public class RTFTransfer extends ByteArrayTransfer {
+
+ private static RTFTransfer _instance = new RTFTransfer();
+ private static final String CF_RTF = "Rich Text Format"; //$NON-NLS-1$
+ private static final int CF_RTFID = registerType(CF_RTF);
+
+private 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.
+ *
+ * @param object a java <code>String</code> containing RTF text
+ * @param transferData an empty <code>TransferData</code> object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+public void javaToNative (Object object, TransferData transferData){
+ if (!checkRTF(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ // CF_RTF is stored as a null terminated byte array
+ String string = (String)object;
+ int count = string.length();
+ char[] chars = new char[count + 1];
+ string.getChars(0, count, chars, 0);
+ int codePage = OS.GetACP();
+ int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+ if (cchMultiByte == 0) {
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.DV_E_STGMEDIUM;
+ return;
+ }
+ int /*long*/ lpMultiByteStr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, cchMultiByte);
+ OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = lpMultiByteStr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ return;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of RTF 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 RTF text if the conversion was successful;
+ * otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ FORMATETC formatetc = transferData.formatetc;
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ int /*long*/ hMem = stgmedium.unionField;
+ try {
+ int /*long*/ lpMultiByteStr = OS.GlobalLock(hMem);
+ if (lpMultiByteStr == 0) return null;
+ try {
+ int codePage = OS.GetACP();
+ int cchWideChar = OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, null, 0);
+ if (cchWideChar == 0) return null;
+ char[] lpWideCharStr = new char [cchWideChar - 1];
+ OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+ return new String(lpWideCharStr);
+ } finally {
+ OS.GlobalUnlock(hMem);
+ }
+ } finally {
+ OS.GlobalFree(hMem);
+ }
+}
+
+protected int[] getTypeIds(){
+ return new int[] {CF_RTFID};
+}
+
+protected String[] getTypeNames(){
+ return new String[] {CF_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/win32/org/eclipse/swt/dnd/TableDragSourceEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDragSourceEffect.java
new file mode 100644
index 0000000000..bc25bd33ae
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDragSourceEffect.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 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.win32.*;
+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
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.3
+ */
+public class TableDragSourceEffect extends DragSourceEffect {
+ Image dragSourceImage = null;
+
+ /**
+ * 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);
+ }
+
+ /**
+ * This implementation of <code>dragFinished</code> disposes the image
+ * that was created in <code>TableDragSourceEffect.dragStart</code>.
+ *
+ * Subclasses that override this method should call <code>super.dragFinished(event)</code>
+ * to dispose the image in the default implementation.
+ *
+ * @param event the information associated with the drag finished event
+ */
+ public void dragFinished(DragSourceEvent event) {
+ if (dragSourceImage != null) dragSourceImage.dispose();
+ dragSourceImage = null;
+ }
+
+ /**
+ * This implementation of <code>dragStart</code> will create a default
+ * image that will be used during the drag. The image should be disposed
+ * when the drag is completed in the <code>TableDragSourceEffect.dragFinished</code>
+ * method.
+ *
+ * Subclasses that override this method should call <code>super.dragStart(event)</code>
+ * to use the image from the default implementation.
+ *
+ * @param event the information associated with the drag start event
+ */
+ public void dragStart(DragSourceEvent event) {
+ event.image = getDragSourceImage(event);
+ }
+
+ Image getDragSourceImage(DragSourceEvent event) {
+ if (dragSourceImage != null) dragSourceImage.dispose();
+ dragSourceImage = null;
+ if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (5, 1)) {
+ SHDRAGIMAGE shdi = new SHDRAGIMAGE();
+ int DI_GETDRAGIMAGE = OS.RegisterWindowMessage (new TCHAR (0, "ShellGetDragImage", true)); //$NON-NLS-1$
+ if (OS.SendMessage (control.handle, DI_GETDRAGIMAGE, 0, shdi) != 0) {
+ if ((control.getStyle() & SWT.MIRRORED) != 0) {
+ event.offsetX = shdi.sizeDragImage.cx - shdi.ptOffset.x;
+ } else {
+ event.offsetX = shdi.ptOffset.x;
+ }
+ event.offsetY = shdi.ptOffset.y;
+ int /*long*/ hImage = shdi.hbmpDragImage;
+ if (hImage != 0) {
+ BITMAP bm = new BITMAP ();
+ OS.GetObject (hImage, BITMAP.sizeof, bm);
+ int srcWidth = bm.bmWidth;
+ int srcHeight = bm.bmHeight;
+
+ /* Create resources */
+ int /*long*/ hdc = OS.GetDC (0);
+ int /*long*/ srcHdc = OS.CreateCompatibleDC (hdc);
+ int /*long*/ oldSrcBitmap = OS.SelectObject (srcHdc, hImage);
+ int /*long*/ memHdc = OS.CreateCompatibleDC (hdc);
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = srcWidth;
+ bmiHeader.biHeight = -srcHeight;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = 32;
+ bmiHeader.biCompression = OS.BI_RGB;
+ byte [] bmi = new byte[BITMAPINFOHEADER.sizeof];
+ OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ int /*long*/ [] pBits = new int /*long*/ [1];
+ int /*long*/ memDib = OS.CreateDIBSection (0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
+ if (memDib == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+ int /*long*/ oldMemBitmap = OS.SelectObject (memHdc, memDib);
+
+ BITMAP dibBM = new BITMAP ();
+ OS.GetObject (memDib, BITMAP.sizeof, dibBM);
+ int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
+
+ /* Get the foreground pixels */
+ OS.BitBlt (memHdc, 0, 0, srcWidth, srcHeight, srcHdc, 0, 0, OS.SRCCOPY);
+ byte[] srcData = new byte [sizeInBytes];
+ OS.MoveMemory (srcData, dibBM.bmBits, sizeInBytes);
+
+ PaletteData palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ ImageData data = new ImageData(srcWidth, srcHeight, bm.bmBitsPixel, palette, bm.bmWidthBytes, srcData);
+ if (shdi.crColorKey == -1) {
+ byte[] alphaData = new byte[srcWidth * srcHeight];
+ int spinc = dibBM.bmWidthBytes - srcWidth * 4;
+ int ap = 0, sp = 3;
+ for (int y = 0; y < srcHeight; ++y) {
+ for (int x = 0; x < srcWidth; ++x) {
+ alphaData [ap++] = srcData [sp];
+ sp += 4;
+ }
+ sp += spinc;
+ }
+ data.alphaData = alphaData;
+ } else {
+ data.transparentPixel = shdi.crColorKey << 8;
+ }
+ dragSourceImage = new Image(control.getDisplay(), data);
+ OS.SelectObject (memHdc, oldMemBitmap);
+ OS.DeleteDC (memHdc);
+ OS.DeleteObject (memDib);
+ OS.SelectObject (srcHdc, oldSrcBitmap);
+ OS.DeleteDC (srcHdc);
+ OS.ReleaseDC (0, hdc);
+ OS.DeleteObject (hImage);
+ return dragSourceImage;
+ }
+ }
+ return null;
+ }
+ Table table = (Table) control;
+ //TEMPORARY CODE
+ if (table.isListening (SWT.EraseItem) || table.isListening (SWT.PaintItem)) return null;
+ TableItem[] selection = table.getSelection();
+ if (selection.length == 0) return null;
+ int /*long*/ tableImageList = OS.SendMessage (table.handle, OS.LVM_GETIMAGELIST, OS.LVSIL_SMALL, 0);
+ if (tableImageList != 0) {
+ int count = Math.min(selection.length, 10);
+ Rectangle bounds = selection[0].getBounds(0);
+ for (int i = 1; i < count; i++) {
+ bounds = bounds.union(selection[i].getBounds(0));
+ }
+ int /*long*/ hDC = OS.GetDC(0);
+ int /*long*/ hDC1 = OS.CreateCompatibleDC(hDC);
+ if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
+ if ((table.getStyle() & SWT.RIGHT_TO_LEFT) != 0) {
+ OS.SetLayout(hDC1, OS.LAYOUT_RTL | OS.LAYOUT_BITMAPORIENTATIONPRESERVED);
+ }
+ }
+ int /*long*/ bitmap = OS.CreateCompatibleBitmap(hDC, bounds.width, bounds.height);
+ int /*long*/ hOldBitmap = OS.SelectObject(hDC1, bitmap);
+ RECT rect = new RECT();
+ rect.right = bounds.width;
+ rect.bottom = bounds.height;
+ int /*long*/ hBrush = OS.GetStockObject(OS.WHITE_BRUSH);
+ OS.FillRect(hDC1, rect, hBrush);
+ for (int i = 0; i < count; i++) {
+ TableItem selected = selection[i];
+ Rectangle cell = selected.getBounds(0);
+ POINT pt = new POINT();
+ int /*long*/ imageList = OS.SendMessage (table.handle, OS.LVM_CREATEDRAGIMAGE, table.indexOf(selected), pt);
+ OS.ImageList_Draw(imageList, 0, hDC1, cell.x - bounds.x, cell.y - bounds.y, OS.ILD_SELECTED);
+ OS.ImageList_Destroy(imageList);
+ }
+ OS.SelectObject(hDC1, hOldBitmap);
+ OS.DeleteDC (hDC1);
+ OS.ReleaseDC (0, hDC);
+ Display display = table.getDisplay();
+ dragSourceImage = Image.win32_new(display, SWT.BITMAP, bitmap);
+ return dragSourceImage;
+ }
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDropTargetEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDropTargetEffect.java
new file mode 100644
index 0000000000..6d27948cc1
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TableDropTargetEffect.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 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.graphics.*;
+import org.eclipse.swt.internal.win32.*;
+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
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.3
+ */
+public class TableDropTargetEffect extends DropTargetEffect {
+ static final int SCROLL_HYSTERESIS = 200; // milli seconds
+
+ int scrollIndex = -1;
+ long scrollBeginTime;
+ TableItem dropHighlight;
+
+ /**
+ * 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) {
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ dropHighlight = 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) {
+ Table table = (Table) control;
+ int /*long*/ handle = table.handle;
+ if (dropHighlight != null) {
+ LVITEM lvItem = new LVITEM ();
+ lvItem.stateMask = OS.LVIS_DROPHILITED;
+ OS.SendMessage(handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+ dropHighlight = null;
+ }
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+
+ /**
+ * 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) getControl();
+ int effect = checkEffect(event.feedback);
+ int /*long*/ handle = table.handle;
+ Point coordinates = new Point(event.x, event.y);
+ coordinates = table.toControl(coordinates);
+ LVHITTESTINFO pinfo = new LVHITTESTINFO();
+ pinfo.x = coordinates.x;
+ pinfo.y = coordinates.y;
+ OS.SendMessage(handle, OS.LVM_HITTEST, 0, pinfo);
+ if ((effect & DND.FEEDBACK_SCROLL) == 0) {
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ } else {
+ if (pinfo.iItem != -1 && scrollIndex == pinfo.iItem && scrollBeginTime != 0) {
+ if (System.currentTimeMillis() >= scrollBeginTime) {
+ int top = Math.max (0, (int)/*64*/OS.SendMessage (handle, OS.LVM_GETTOPINDEX, 0, 0));
+ int count = (int)/*64*/OS.SendMessage (handle, OS.LVM_GETITEMCOUNT, 0, 0);
+ int index = (scrollIndex - 1 < top) ? Math.max(0, scrollIndex - 1) : Math.min(count - 1, scrollIndex + 1);
+ boolean scroll = true;
+ if (pinfo.iItem == top) {
+ scroll = pinfo.iItem != index;
+ } else {
+ RECT itemRect = new RECT ();
+ itemRect.left = OS.LVIR_BOUNDS;
+ if (OS.SendMessage (handle, OS.LVM_GETITEMRECT, pinfo.iItem, itemRect) != 0) {
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ POINT pt = new POINT ();
+ pt.x = itemRect.left;
+ pt.y = itemRect.top;
+ if (OS.PtInRect (rect, pt)) {
+ pt.y = itemRect.bottom;
+ if (OS.PtInRect (rect, pt)) scroll = false;
+ }
+ }
+ }
+ if (scroll) {
+ OS.SendMessage (handle, OS.LVM_ENSUREVISIBLE, index, 0);
+ table.redraw();
+ }
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+ } else {
+ scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+ scrollIndex = pinfo.iItem;
+ }
+ }
+
+ if (pinfo.iItem != -1 && (effect & DND.FEEDBACK_SELECT) != 0) {
+ TableItem item = table.getItem(pinfo.iItem);
+ if (dropHighlight != item) {
+ LVITEM lvItem = new LVITEM();
+ lvItem.stateMask = OS.LVIS_DROPHILITED;
+ OS.SendMessage(handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+ lvItem.state = OS.LVIS_DROPHILITED;
+ OS.SendMessage(handle, OS.LVM_SETITEMSTATE, pinfo.iItem, lvItem);
+ dropHighlight = item;
+ }
+ } else {
+ if (dropHighlight != null) {
+ LVITEM lvItem = new LVITEM ();
+ lvItem.stateMask = OS.LVIS_DROPHILITED;
+ OS.SendMessage(handle, OS.LVM_SETITEMSTATE, -1, lvItem);
+ dropHighlight = null;
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TextTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TextTransfer.java
new file mode 100755
index 0000000000..94b3cf0fed
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TextTransfer.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * 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 {
+
+ private static TextTransfer _instance = new TextTransfer();
+ private static final String CF_UNICODETEXT = "CF_UNICODETEXT"; //$NON-NLS-1$
+ private static final String CF_TEXT = "CF_TEXT"; //$NON-NLS-1$
+ private static final int CF_UNICODETEXTID = COM.CF_UNICODETEXT;
+ private static final int CF_TEXTID = COM.CF_TEXT;
+
+private 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 that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+public void javaToNative (Object object, TransferData transferData){
+ if (!checkText(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ transferData.result = COM.E_FAIL;
+ String string = (String)object;
+ switch (transferData.type) {
+ case COM.CF_UNICODETEXT: {
+ int charCount = string.length ();
+ char[] chars = new char[charCount+1];
+ string.getChars (0, charCount, chars, 0);
+ int byteCount = chars.length * 2;
+ int /*long*/ newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, byteCount);
+ OS.MoveMemory(newPtr, chars, byteCount);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = newPtr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ break;
+ }
+ case COM.CF_TEXT: {
+ int count = string.length();
+ char[] chars = new char[count + 1];
+ string.getChars(0, count, chars, 0);
+ int codePage = OS.GetACP();
+ int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+ if (cchMultiByte == 0) {
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.DV_E_STGMEDIUM;
+ return;
+ }
+ int /*long*/ lpMultiByteStr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, cchMultiByte);
+ OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = lpMultiByteStr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ break;
+ }
+ }
+ return;
+}
+
+/**
+ * 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#javaToNative
+ */
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ FORMATETC formatetc = transferData.formatetc;
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ int /*long*/ hMem = stgmedium.unionField;
+ try {
+ switch (transferData.type) {
+ case CF_UNICODETEXTID: {
+ /* Ensure byteCount is a multiple of 2 bytes */
+ int size = OS.GlobalSize(hMem) / 2 * 2;
+ if (size == 0) return null;
+ char[] chars = new char[size/2];
+ int /*long*/ ptr = OS.GlobalLock(hMem);
+ if (ptr == 0) return null;
+ try {
+ OS.MoveMemory(chars, ptr, size);
+ int length = chars.length;
+ for (int i=0; i<chars.length; i++) {
+ if (chars [i] == '\0') {
+ length = i;
+ break;
+ }
+ }
+ return new String (chars, 0, length);
+ } finally {
+ OS.GlobalUnlock(hMem);
+ }
+ }
+ case CF_TEXTID: {
+ int /*long*/ lpMultiByteStr = OS.GlobalLock(hMem);
+ if (lpMultiByteStr == 0) return null;
+ try {
+ int codePage = OS.GetACP();
+ int cchWideChar = OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, null, 0);
+ if (cchWideChar == 0) return null;
+ char[] lpWideCharStr = new char [cchWideChar - 1];
+ OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+ return new String(lpWideCharStr);
+ } finally {
+ OS.GlobalUnlock(hMem);
+ }
+ }
+ }
+ } finally {
+ OS.GlobalFree(hMem);
+ }
+ return null;
+}
+
+protected int[] getTypeIds(){
+ return new int[] {CF_UNICODETEXTID, CF_TEXTID};
+}
+
+protected String[] getTypeNames(){
+ return new String[] {CF_UNICODETEXT, CF_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/win32/org/eclipse/swt/dnd/Transfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/Transfer.java
new file mode 100755
index 0000000000..4a7f318b21
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/Transfer.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * <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
+ * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: DNDExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public abstract class Transfer {
+
+private static final int RETRY_LIMIT = 10;
+/*
+ * Feature in Windows. When another application has control
+ * of the clipboard, the clipboard is locked and it's not
+ * possible to retrieve data until the other application is
+ * finished. To allow other applications to get the
+ * data, use PeekMessage() to enable cross thread
+ * message sends.
+ */
+int getData(IDataObject dataObject, FORMATETC pFormatetc, STGMEDIUM pmedium) {
+ if (dataObject.GetData(pFormatetc, pmedium) == COM.S_OK) return COM.S_OK;
+ try {Thread.sleep(50);} catch (Throwable t) {}
+ int result = dataObject.GetData(pFormatetc, pmedium);
+ int retryCount = 0;
+ while (result != COM.S_OK && retryCount++ < RETRY_LIMIT) {
+ MSG msg = new MSG();
+ OS.PeekMessage(msg, 0, 0, 0, OS.PM_NOREMOVE | OS.PM_NOYIELD);
+ try {Thread.sleep(50);} catch (Throwable t) {}
+ result = dataObject.GetData(pFormatetc, pmedium);
+ }
+ return result;
+}
+
+/**
+ * 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) {
+ // Look name up in the registry
+ // If name is not in registry, add it and return assigned value.
+ // If name already exists in registry, return its assigned value
+ TCHAR chFormatName = new TCHAR(0, formatName, true);
+ return OS.RegisterClipboardFormat(chFormatName);
+}
+
+/**
+ * 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/win32/org/eclipse/swt/dnd/TransferData.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TransferData.java
new file mode 100755
index 0000000000..a1c57b813b
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TransferData.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.ole.win32.*;
+
+/**
+ * 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>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+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 formatetc structure is a generalized data transfer format, enhanced to
+ * encompass a target device, the aspect, or view of the data, and
+ * a storage medium.
+ * (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 FORMATETC formatetc;
+
+ /**
+ * The stgmedium structure is a generalized global memory handle used for
+ * data transfer operations.
+ * (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 STGMEDIUM stgmedium;
+
+ /**
+ * 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 = COM.E_FAIL;
+
+ /**
+ * The pIDataObject is the address of an IDataObject OLE Interface which
+ * provides access to the data associated with the transfer.
+ * (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 /*long*/ pIDataObject;
+
+ static boolean sameType(TransferData data1, TransferData data2) {
+ if (data1 == data2) return true;
+ if (data1 == null || data2 == null) return false;
+ return (data1.type == data2.type &&
+ data1.formatetc.cfFormat == data2.formatetc.cfFormat &&
+ data1.formatetc.dwAspect == data2.formatetc.dwAspect &&
+ data1.formatetc.tymed == data2.formatetc.tymed);
+ }
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDragSourceEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDragSourceEffect.java
new file mode 100644
index 0000000000..645549a14f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDragSourceEffect.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 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.win32.*;
+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
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.3
+ */
+public class TreeDragSourceEffect extends DragSourceEffect {
+ Image dragSourceImage = null;
+
+ /**
+ * 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);
+ }
+
+ /**
+ * This implementation of <code>dragFinished</code> disposes the image
+ * that was created in <code>TreeDragSourceEffect.dragStart</code>.
+ *
+ * Subclasses that override this method should call <code>super.dragFinished(event)</code>
+ * to dispose the image in the default implementation.
+ *
+ * @param event the information associated with the drag finished event
+ */
+ public void dragFinished(DragSourceEvent event) {
+ if (dragSourceImage != null) dragSourceImage.dispose();
+ dragSourceImage = null;
+ }
+
+ /**
+ * This implementation of <code>dragStart</code> will create a default
+ * image that will be used during the drag. The image should be disposed
+ * when the drag is completed in the <code>TreeDragSourceEffect.dragFinished</code>
+ * method.
+ *
+ * Subclasses that override this method should call <code>super.dragStart(event)</code>
+ * to use the image from the default implementation.
+ *
+ * @param event the information associated with the drag start event
+ */
+ public void dragStart(DragSourceEvent event) {
+ event.image = getDragSourceImage(event);
+ }
+
+ Image getDragSourceImage(DragSourceEvent event) {
+ if (dragSourceImage != null) dragSourceImage.dispose();
+ dragSourceImage = null;
+ if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (5, 1)) {
+ SHDRAGIMAGE shdi = new SHDRAGIMAGE();
+ int DI_GETDRAGIMAGE = OS.RegisterWindowMessage (new TCHAR (0, "ShellGetDragImage", true)); //$NON-NLS-1$
+ if (OS.SendMessage (control.handle, DI_GETDRAGIMAGE, 0, shdi) != 0) {
+ if ((control.getStyle() & SWT.MIRRORED) != 0) {
+ event.offsetX = shdi.sizeDragImage.cx - shdi.ptOffset.x;
+ } else {
+ event.offsetX = shdi.ptOffset.x;
+ }
+ event.offsetY = shdi.ptOffset.y;
+ int /*long*/ hImage = shdi.hbmpDragImage;
+ if (hImage != 0) {
+ BITMAP bm = new BITMAP ();
+ OS.GetObject (hImage, BITMAP.sizeof, bm);
+ int srcWidth = bm.bmWidth;
+ int srcHeight = bm.bmHeight;
+
+ /* Create resources */
+ int /*long*/ hdc = OS.GetDC (0);
+ int /*long*/ srcHdc = OS.CreateCompatibleDC (hdc);
+ int /*long*/ oldSrcBitmap = OS.SelectObject (srcHdc, hImage);
+ int /*long*/ memHdc = OS.CreateCompatibleDC (hdc);
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = srcWidth;
+ bmiHeader.biHeight = -srcHeight;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = 32;
+ bmiHeader.biCompression = OS.BI_RGB;
+ byte [] bmi = new byte[BITMAPINFOHEADER.sizeof];
+ OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ int /*long*/ [] pBits = new int /*long*/ [1];
+ int /*long*/ memDib = OS.CreateDIBSection (0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
+ if (memDib == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+ int /*long*/ oldMemBitmap = OS.SelectObject (memHdc, memDib);
+
+ BITMAP dibBM = new BITMAP ();
+ OS.GetObject (memDib, BITMAP.sizeof, dibBM);
+ int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
+
+ /* Get the foreground pixels */
+ OS.BitBlt (memHdc, 0, 0, srcWidth, srcHeight, srcHdc, 0, 0, OS.SRCCOPY);
+ byte[] srcData = new byte [sizeInBytes];
+ OS.MoveMemory (srcData, dibBM.bmBits, sizeInBytes);
+
+ PaletteData palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ ImageData data = new ImageData(srcWidth, srcHeight, bm.bmBitsPixel, palette, bm.bmWidthBytes, srcData);
+ if (shdi.crColorKey == -1) {
+ byte[] alphaData = new byte[srcWidth * srcHeight];
+ int spinc = dibBM.bmWidthBytes - srcWidth * 4;
+ int ap = 0, sp = 3;
+ for (int y = 0; y < srcHeight; ++y) {
+ for (int x = 0; x < srcWidth; ++x) {
+ alphaData [ap++] = srcData [sp];
+ sp += 4;
+ }
+ sp += spinc;
+ }
+ data.alphaData = alphaData;
+ } else {
+ data.transparentPixel = shdi.crColorKey << 8;
+ }
+ dragSourceImage = new Image (control.getDisplay (), data);
+ OS.SelectObject (memHdc, oldMemBitmap);
+ OS.DeleteDC (memHdc);
+ OS.DeleteObject (memDib);
+ OS.SelectObject (srcHdc, oldSrcBitmap);
+ OS.DeleteDC (srcHdc);
+ OS.ReleaseDC (0, hdc);
+ OS.DeleteObject (hImage);
+ return dragSourceImage;
+ }
+ }
+ return null;
+ }
+
+ Tree tree = (Tree) control;
+ //TEMPORARY CODE
+ if (tree.isListening (SWT.EraseItem) || tree.isListening (SWT.PaintItem)) return null;
+ TreeItem[] selection = tree.getSelection();
+ if (selection.length == 0) return null;
+ int /*long*/ treeImageList = OS.SendMessage (tree.handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
+ if (treeImageList != 0) {
+ int count = Math.min(selection.length, 10);
+ Rectangle bounds = selection[0].getBounds(0);
+ for (int i = 1; i < count; i++) {
+ bounds = bounds.union(selection[i].getBounds(0));
+ }
+ int /*long*/ hDC = OS.GetDC(tree.handle);
+ int /*long*/ hDC1 = OS.CreateCompatibleDC(hDC);
+ int /*long*/ bitmap = OS.CreateCompatibleBitmap(hDC, bounds.width, bounds.height);
+ int /*long*/ hOldBitmap = OS.SelectObject(hDC1, bitmap);
+ RECT rect = new RECT();
+ rect.right = bounds.width;
+ rect.bottom = bounds.height;
+ int /*long*/ hBrush = OS.GetStockObject(OS.WHITE_BRUSH);
+ OS.FillRect(hDC1, rect, hBrush);
+ for (int i = 0; i < count; i++) {
+ TreeItem selected = selection[i];
+ Rectangle cell = selected.getBounds(0);
+ int /*long*/ imageList = OS.SendMessage(tree.handle, OS.TVM_CREATEDRAGIMAGE, 0, selected.handle);
+ OS.ImageList_Draw(imageList, 0, hDC1, cell.x - bounds.x, cell.y - bounds.y, OS.ILD_SELECTED);
+ OS.ImageList_Destroy(imageList);
+ }
+ OS.SelectObject(hDC1, hOldBitmap);
+ OS.DeleteDC (hDC1);
+ OS.ReleaseDC (tree.handle, hDC);
+ Display display = tree.getDisplay();
+ dragSourceImage = Image.win32_new(display, SWT.BITMAP, bitmap);
+ return dragSourceImage;
+ }
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDropTargetEffect.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDropTargetEffect.java
new file mode 100644
index 0000000000..04776faaac
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/TreeDropTargetEffect.java
@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 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.win32.*;
+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
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.3
+ */
+public class TreeDropTargetEffect extends DropTargetEffect {
+ static final int SCROLL_HYSTERESIS = 200; // milli seconds
+ static final int EXPAND_HYSTERESIS = 1000; // milli seconds
+
+ int /*long*/ dropIndex;
+ int /*long*/ scrollIndex;
+ long scrollBeginTime;
+ int /*long*/ expandIndex;
+ long expandBeginTime;
+ TreeItem insertItem;
+ boolean insertBefore;
+
+ /**
+ * 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) {
+ dropIndex = -1;
+ insertItem = null;
+ expandBeginTime = 0;
+ expandIndex = -1;
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+
+ /**
+ * 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;
+ int /*long*/ handle = tree.handle;
+ if (dropIndex != -1) {
+ TVITEM tvItem = new TVITEM ();
+ tvItem.hItem = dropIndex;
+ tvItem.mask = OS.TVIF_STATE;
+ tvItem.stateMask = OS.TVIS_DROPHILITED;
+ tvItem.state = 0;
+ OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
+ dropIndex = -1;
+ }
+ if (insertItem != null) {
+ tree.setInsertMark(null, false);
+ insertItem = null;
+ }
+ expandBeginTime = 0;
+ expandIndex = -1;
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+
+ /**
+ * 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) getControl();
+ int effect = checkEffect(event.feedback);
+ int /*long*/ handle = tree.handle;
+ Point coordinates = new Point(event.x, event.y);
+ coordinates = tree.toControl(coordinates);
+ TVHITTESTINFO lpht = new TVHITTESTINFO ();
+ lpht.x = coordinates.x;
+ lpht.y = coordinates.y;
+ OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
+ int /*long*/ hItem = lpht.hItem;
+ if ((effect & DND.FEEDBACK_SCROLL) == 0) {
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ } else {
+ if (hItem != -1 && scrollIndex == hItem && scrollBeginTime != 0) {
+ if (System.currentTimeMillis() >= scrollBeginTime) {
+ int /*long*/ topItem = OS.SendMessage(handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
+ int /*long*/ nextItem = OS.SendMessage(handle, OS.TVM_GETNEXTITEM, hItem == topItem ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE, hItem);
+ boolean scroll = true;
+ if (hItem == topItem) {
+ scroll = nextItem != 0;
+ } else {
+ RECT itemRect = new RECT ();
+ if (OS.TreeView_GetItemRect (handle, nextItem, itemRect, true)) {
+ RECT rect = new RECT ();
+ OS.GetClientRect (handle, rect);
+ POINT pt = new POINT ();
+ pt.x = itemRect.left;
+ pt.y = itemRect.top;
+ if (OS.PtInRect (rect, pt)) {
+ pt.y = itemRect.bottom;
+ if (OS.PtInRect (rect, pt)) scroll = false;
+ }
+ }
+ }
+ if (scroll) {
+ OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, nextItem);
+ tree.redraw();
+ }
+ scrollBeginTime = 0;
+ scrollIndex = -1;
+ }
+ } else {
+ scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+ scrollIndex = hItem;
+ }
+ }
+ if ((effect & DND.FEEDBACK_EXPAND) == 0) {
+ expandBeginTime = 0;
+ expandIndex = -1;
+ } else {
+ if (hItem != -1 && expandIndex == hItem && expandBeginTime != 0) {
+ if (System.currentTimeMillis() >= expandBeginTime) {
+ if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem) != 0) {
+ TreeItem item = (TreeItem)tree.getDisplay().findWidget(tree.handle, hItem);
+ if (item != null && !item.getExpanded()) {
+ item.setExpanded(true);
+ tree.redraw();
+ Event expandEvent = new Event ();
+ expandEvent.item = item;
+ tree.notifyListeners(SWT.Expand, expandEvent);
+ }
+ }
+ expandBeginTime = 0;
+ expandIndex = -1;
+ }
+ } else {
+ expandBeginTime = System.currentTimeMillis() + EXPAND_HYSTERESIS;
+ expandIndex = hItem;
+ }
+ }
+ if (dropIndex != -1 && (dropIndex != hItem || (effect & DND.FEEDBACK_SELECT) == 0)) {
+ TVITEM tvItem = new TVITEM ();
+ tvItem.hItem = dropIndex;
+ tvItem.mask = OS.TVIF_STATE;
+ tvItem.stateMask = OS.TVIS_DROPHILITED;
+ tvItem.state = 0;
+ OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
+ dropIndex = -1;
+ }
+ if (hItem != -1 && hItem != dropIndex && (effect & DND.FEEDBACK_SELECT) != 0) {
+ TVITEM tvItem = new TVITEM ();
+ tvItem.hItem = hItem;
+ tvItem.mask = OS.TVIF_STATE;
+ tvItem.stateMask = OS.TVIS_DROPHILITED;
+ tvItem.state = OS.TVIS_DROPHILITED;
+ OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
+ dropIndex = hItem;
+ }
+ if ((effect & DND.FEEDBACK_INSERT_BEFORE) != 0 || (effect & DND.FEEDBACK_INSERT_AFTER) != 0) {
+ boolean before = (effect & DND.FEEDBACK_INSERT_BEFORE) != 0;
+ /*
+ * Bug in Windows. When TVM_SETINSERTMARK is used to set
+ * an insert mark for a tree and an item is expanded or
+ * collapsed near the insert mark, the tree does not redraw
+ * the insert mark properly. The fix is to hide and show
+ * the insert mark whenever an item is expanded or collapsed.
+ * Since the insert mark can not be queried from the tree,
+ * use the Tree API rather than calling the OS directly.
+ */
+ TreeItem item = (TreeItem)tree.getDisplay().findWidget(tree.handle, hItem);
+ if (item != null) {
+ if (item != insertItem || before != insertBefore) {
+ tree.setInsertMark(item, before);
+ }
+ insertItem = item;
+ insertBefore = before;
+ } else {
+ if (insertItem != null) {
+ tree.setInsertMark(null, false);
+ }
+ insertItem = null;
+ }
+ } else {
+ if (insertItem != null) {
+ tree.setInsertMark(null, false);
+ }
+ insertItem = null;
+ }
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/URLTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/URLTransfer.java
new file mode 100644
index 0000000000..5aedfb1ff1
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/URLTransfer.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * 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. The string
+ * must contain a 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>
+ *
+ * @see Transfer
+ * @since 3.4
+ */
+public class URLTransfer extends ByteArrayTransfer {
+
+ static URLTransfer _instance = new URLTransfer();
+ static final String CFSTR_INETURL = "UniformResourceLocator"; //$NON-NLS-1$
+ static final int CFSTR_INETURLID = registerType(CFSTR_INETURL);
+
+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.
+ *
+ * @param object a java <code>String</code> containing a URL
+ * @param transferData an empty <code>TransferData</code> object that will
+ * be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#nativeToJava
+ */
+public void javaToNative (Object object, TransferData transferData){
+ if (!checkURL(object) || !isSupportedType(transferData)) {
+ DND.error(DND.ERROR_INVALID_DATA);
+ }
+ transferData.result = COM.E_FAIL;
+ // URL is stored as a null terminated byte array
+ String url = ((String)object);
+ int count = url.length();
+ char[] chars = new char[count + 1];
+ url.getChars(0, count, chars, 0);
+ int codePage = OS.GetACP();
+ int cchMultiByte = OS.WideCharToMultiByte(codePage, 0, chars, -1, null, 0, null, null);
+ if (cchMultiByte == 0) {
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.result = COM.DV_E_STGMEDIUM;
+ return;
+ }
+ int /*long*/ lpMultiByteStr = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, cchMultiByte);
+ OS.WideCharToMultiByte(codePage, 0, chars, -1, lpMultiByteStr, cchMultiByte, null, null);
+ transferData.stgmedium = new STGMEDIUM();
+ transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.stgmedium.unionField = lpMultiByteStr;
+ transferData.stgmedium.pUnkForRelease = 0;
+ transferData.result = COM.S_OK;
+ return;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform
+ * specific representation of a URL 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 a URL if the conversion was successful;
+ * otherwise null
+ *
+ * @see Transfer#javaToNative
+ */
+public Object nativeToJava(TransferData transferData){
+ if (!isSupportedType(transferData) || transferData.pIDataObject == 0) return null;
+ IDataObject data = new IDataObject(transferData.pIDataObject);
+ data.AddRef();
+ STGMEDIUM stgmedium = new STGMEDIUM();
+ FORMATETC formatetc = transferData.formatetc;
+ stgmedium.tymed = COM.TYMED_HGLOBAL;
+ transferData.result = getData(data, formatetc, stgmedium);
+ data.Release();
+ if (transferData.result != COM.S_OK) return null;
+ int /*long*/ hMem = stgmedium.unionField;
+ try {
+ int /*long*/ lpMultiByteStr = OS.GlobalLock(hMem);
+ if (lpMultiByteStr == 0) return null;
+ try {
+ int codePage = OS.GetACP();
+ int cchWideChar = OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, null, 0);
+ if (cchWideChar == 0) return null;
+ char[] lpWideCharStr = new char [cchWideChar - 1];
+ OS.MultiByteToWideChar (codePage, OS.MB_PRECOMPOSED, lpMultiByteStr, -1, lpWideCharStr, lpWideCharStr.length);
+ return new String(lpWideCharStr);
+ } finally {
+ OS.GlobalUnlock(hMem);
+ }
+ } finally {
+ OS.GlobalFree(hMem);
+ }
+}
+
+protected int[] getTypeIds(){
+ return new int[] {CFSTR_INETURLID};
+}
+
+protected String[] getTypeNames(){
+ return new String[] {CFSTR_INETURL};
+}
+
+boolean checkURL(Object object) {
+ return object != null && (object instanceof String) && ((String)object).length() > 0;
+}
+
+protected boolean validate(Object object) {
+ return checkURL(object);
+}
+}