Mercurial > projects > dwt-linux
changeset 92:ddb19cb18d2e
package dnd
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Fri, 18 Jan 2008 00:34:32 +0100 |
parents | b58ec55ce70d |
children | c3d44df6708f |
files | dwt/dnd/ByteArrayTransfer.d dwt/dnd/Clipboard.d dwt/dnd/ClipboardProxy.d dwt/dnd/DND.d dwt/dnd/DNDEvent.d dwt/dnd/DNDListener.d dwt/dnd/DragSource.d dwt/dnd/DragSourceAdapter.d dwt/dnd/DragSourceEffect.d dwt/dnd/DragSourceEvent.d dwt/dnd/DragSourceListener.d dwt/dnd/DropTarget.d dwt/dnd/DropTargetAdapter.d dwt/dnd/DropTargetEffect.d dwt/dnd/DropTargetEvent.d dwt/dnd/DropTargetListener.d dwt/dnd/FileTransfer.d dwt/dnd/HTMLTransfer.d dwt/dnd/RTFTransfer.d dwt/dnd/TableDragSourceEffect.d dwt/dnd/TableDropTargetEffect.d dwt/dnd/TextTransfer.d dwt/dnd/Transfer.d dwt/dnd/TransferData.d dwt/dnd/TreeDragSourceEffect.d dwt/dnd/TreeDropTargetEffect.d dwt/dwthelper/System.d dwt/dwthelper/utils.d dwt/graphics/Image.d dwt/internal/gtk/OS.d |
diffstat | 30 files changed, 5384 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/ByteArrayTransfer.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.ByteArrayTransfer; + +import dwt.internal.gtk.OS; +import dwt.dnd.Transfer; +import dwt.dnd.TransferData; +import dwt.dnd.DND; +import dwt.dwthelper.utils; + +/** + * The class <code>ByteArrayTransfer</code> provides a platform specific + * mechanism for converting a java <code>byte[]</code> to a platform + * specific representation of the byte array and vice versa. See + * <code>Transfer</code> for additional information. + * + * <p><code>ByteArrayTransfer</code> is never used directly but is sub-classed + * by transfer agents that convert between data in a java format such as a + * <code>String</code> and a platform specific byte array. + * + * <p>If the data you are converting <b>does not</b> map to a + * <code>byte[]</code>, you should sub-class <code>Transfer</code> directly + * and do your own mapping to a platform data type.</p> + * + * <p>The following snippet shows a subclass of ByteArrayTransfer that transfers + * data defined by the class <code>MyType</code>.</p> + * + * <pre><code> + * public class MyType { + * public String fileName; + * public long fileLength; + * public long lastModified; + * } + * </code></pre> + * + * <pre><code> + * public class MyTypeTransfer extends ByteArrayTransfer { + * + * private static final String MYTYPENAME = "my_type_name"; + * private static final int MYTYPEID = registerType(MYTYPENAME); + * private static MyTypeTransfer _instance = new MyTypeTransfer(); + * + * private MyTypeTransfer() {} + * + * public static MyTypeTransfer getInstance () { + * return _instance; + * } + * public void javaToNative (Object object, TransferData transferData) { + * if (object is 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 < 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 is null) return null; + * + * MyType[] myData = new MyType[0]; + * try { + * ByteArrayInputStream in = new ByteArrayInputStream(buffer); + * DataInputStream readIn = new DataInputStream(in); + * while(readIn.available() > 20) { + * MyType datum = new MyType(); + * int size = readIn.readInt(); + * byte[] name = new byte[size]; + * readIn.read(name); + * datum.fileName = new String(name); + * datum.fileLength = readIn.readLong(); + * datum.lastModified = readIn.readLong(); + * MyType[] newMyData = new MyType[myData.length + 1]; + * System.arraycopy(myData, 0, newMyData, 0, myData.length); + * newMyData[myData.length] = datum; + * myData = newMyData; + * } + * readIn.close(); + * } catch (IOException ex) { + * return null; + * } + * return myData; + * } + * + * return null; + * } + * protected String[] getTypeNames(){ + * return new String[]{MYTYPENAME}; + * } + * protected int[] getTypeIds(){ + * return new int[] {MYTYPEID}; + * } + * } + * </code></pre> + */ +public abstract class ByteArrayTransfer : 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 = cast(void*)types[i]; + } + return data; +} + +public bool isSupportedType(TransferData transferData){ + if (transferData is null) return false; + int[] types = getTypeIds(); + for (int i = 0; i < types.length; i++) { + if (transferData.type is cast(void*)types[i]) return true; + } + return false; +} + +/** + * This implementation of <code>javaToNative</code> converts a java + * <code>byte[]</code> to a platform specific representation. For additional + * information see <code>Transfer#javaToNative</code>. + * + * @see Transfer#javaToNative + * + * @param object a java <code>byte[]</code> containing the data to be converted + * @param transferData an empty <code>TransferData</code> object; this + * object will be filled in on return with the platform specific format of the data + */ +protected void javaToNative (Object object, TransferData transferData) { + transferData.result = 0; + if (!checkByteArray(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + byte[] buffer = (cast(ArrayWrapperByte)object).array; + if (buffer.length is 0) return; + byte* pValue = cast(byte*)OS.g_malloc(buffer.length); + if (pValue is null) return; + pValue[ 0 .. buffer.length ] = buffer; + transferData.length = buffer.length; + transferData.format = 8; + transferData.pValue = cast(char*)pValue; + transferData.result = 1; +} + +/** + * This implementation of <code>nativeToJava</code> converts a platform specific + * representation of a byte array to a java <code>byte[]</code>. + * For additional information see <code>Transfer#nativeToJava</code>. + * + * @see Transfer#nativeToJava + * + * @param transferData the platform specific representation of the data to be + * been converted + * @return a java <code>byte[]</code> containing the converted data if the + * conversion was successful; otherwise null + */ +protected Object nativeToJava(TransferData transferData) { + if ( !isSupportedType(transferData) || transferData.pValue is null) return null; + int size = transferData.format * transferData.length / 8; + if (size is 0) return null; + byte* ptr = cast(byte*)transferData.pValue; + return new ArrayWrapperByte( ptr[ 0 .. size ].dup ); +} + +bool checkByteArray(Object object) { + if( object is null ) return false; + ArrayWrapperByte arr = cast(ArrayWrapperByte)object; + if( arr is null ) return false; + return arr.array.length > 0; +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/Clipboard.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,623 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.Clipboard; + + + +import dwt.DWT; +import dwt.DWTError; +import dwt.DWTException; +import dwt.internal.Converter; +import dwt.internal.gtk.OS; +import dwt.widgets.Display; +import dwt.dnd.Transfer; +import dwt.dnd.TransferData; +import dwt.dnd.DND; +import dwt.dnd.ClipboardProxy; + +import dwt.dwthelper.utils; + +import tango.core.Thread; +static import tango.stdc.stringz; +static import tango.stdc.string; + +/** + * The <code>Clipboard</code> provides a mechanism for transferring data from one + * application to another or within an application. + * + * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p> + */ +public class Clipboard { + + private Display display; + + static void* GTKCLIPBOARD; + static void* GTKPRIMARYCLIPBOARD; + private static void* TARGET; + + static this(){ + GTKCLIPBOARD = OS.gtk_clipboard_get( cast(void*)OS.GDK_NONE); + auto primary = OS.gdk_atom_intern("PRIMARY".ptr, false); + GTKPRIMARYCLIPBOARD = OS.gtk_clipboard_get(primary); + TARGET = OS.gdk_atom_intern("TARGETS".ptr, false); + } + +/** + * 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 DWTException <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 this(Display display) { + checkSubclass (); + if (display is null) { + display = Display.getCurrent(); + if (display is null) { + display = Display.getDefault(); + } + } + if (display.getThread() !is Thread.getThis()) { + DND.error(DWT.ERROR_THREAD_INVALID_ACCESS); + } + this.display = display; +} + +/** + * Checks that this class can be subclassed. + * <p> + * The DWT 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 DWT 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 DWT classes + * is intended purely to enable those not on the DWT 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 DWTException <ul> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> + * </ul> + */ +protected void checkSubclass () { + char[] name = this.classinfo.name; + char[] validName = Clipboard.stringof; + if ( validName !=/*eq*/ name ) { + DND.error (DWT.ERROR_INVALID_SUBCLASS); + } +} +/** + * Throws an <code>DWTException</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 DWT 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 DWT, there may be more or fewer error + * checks and exceptions may be thrown for different reasons. + * </p> + * + * @exception DWTException <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 is null) DND.error (DWT.ERROR_WIDGET_DISPOSED); + if (display.getThread() !is Thread.getThis ()) DND.error (DWT.ERROR_THREAD_INVALID_ACCESS); + if (display.isDisposed()) DND.error(DWT.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 DWTException <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 DWTException <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(); + ClipboardProxy proxy = ClipboardProxy._getInstance(display); + proxy.clear(this, clipboards); +} + +/** + * 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 DWTException <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() !is Thread.getThis()) DND.error(DWT.ERROR_THREAD_INVALID_ACCESS); + display = null; +} + +/** + * Retrieve the data of the specified type currently available on the system + * clipboard. Refer to the specific subclass of <code>Transfer</code> to + * determine the type of object returned. + * + * <p>The following snippet shows text and RTF text being retrieved from the + * clipboard:</p> + * + * <code><pre> + * Clipboard clipboard = new Clipboard(display); + * TextTransfer textTransfer = TextTransfer.getInstance(); + * String textData = (String)clipboard.getContents(textTransfer); + * if (textData !is null) System.out.println("Text is "+textData); + * RTFTransfer rtfTransfer = RTFTransfer.getInstance(); + * String rtfData = (String)clipboard.getContents(rtfTransfer); + * if (rtfData !is 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 DWTException <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 !is null) System.out.println("Text is "+textData); + * RTFTransfer rtfTransfer = RTFTransfer.getInstance(); + * String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD); + * if (rtfData !is 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 DWTException <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 is null) DND.error(DWT.ERROR_NULL_ARGUMENT); + GtkSelectionData* selection_data; + auto typeIds = transfer.getTypeIds(); + for (int i = 0; i < typeIds.length; i++) { + if ((clipboards & DND.CLIPBOARD) !is 0) { + selection_data = gtk_clipboard_wait_for_contents(GTKCLIPBOARD, cast(void*)typeIds[i]); + } + if (selection_data !is null) break; + if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0) { + selection_data = gtk_clipboard_wait_for_contents(GTKPRIMARYCLIPBOARD, cast(void*)typeIds[i]); + } + } + if (selection_data is null) return null; + GtkSelectionData* gtkSelectionData = selection_data; + TransferData tdata = new TransferData(); + tdata.type = gtkSelectionData.type; + tdata.pValue = gtkSelectionData.data; + tdata.length = gtkSelectionData.length; + tdata.format = gtkSelectionData.format; + Object result = transfer.nativeToJava(tdata); + OS.gtk_selection_data_free(selection_data); + return result; +} + +/** + * 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 bool isDisposed () { + return (display is 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 DWTException <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 DWTError <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 DWTException, 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 DWTException <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 DWTError <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 DWTException, 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 is null || dataTypes is null || data.length !is dataTypes.length || data.length is 0) { + DND.error(DWT.ERROR_INVALID_ARGUMENT); + } + for (int i = 0; i < data.length; i++) { + if (data[i] is null || dataTypes[i] is null || !dataTypes[i].validate(data[i])) { + DND.error(DWT.ERROR_INVALID_ARGUMENT); + } + } + ClipboardProxy proxy = ClipboardProxy._getInstance(display); + if (!proxy.setData(this, data, dataTypes, clipboards)) { + DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); + } +} + +/** + * Returns an array of the data types currently available on the system + * clipboard. Use with Transfer.isSupportedType. + * + * @return array of data types currently available on the system clipboard + * + * @exception DWTException <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 DWTException <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(); + TransferData[] result = null; + if ((clipboards & DND.CLIPBOARD) !is 0) { + auto types = getAvailableClipboardTypes(); + result = new TransferData[types.length]; + for (int i = 0; i < types.length; i++) { + result[i] = new TransferData(); + result[i].type = types[i]; + } + } + if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0) { + auto types = getAvailablePrimaryTypes(); + int offset = 0; + if (result !is null) { + TransferData[] newResult = new TransferData[result.length + types.length]; + System.arraycopy(result,0, newResult, 0, result.length); + offset = result.length; + result = newResult; + } else { + result = new TransferData[types.length]; + } + for (int i = 0; i < types.length; i++) { + result[offset+i] = new TransferData(); + result[offset+i].type = types[i]; + } + } + return result is null ? new TransferData[0] : result; +} + +/** + * Returns a platform specific list of the data types currently available on the + * system clipboard. + * + * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer + * sub-class. It should NOT be used within an application because it provides + * platform specific information.</p> + * + * @return a platform specific list of the data types currently available on the + * system clipboard + * + * @exception DWTException <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 char[][] getAvailableTypeNames() { + checkWidget(); + auto types1 = getAvailableClipboardTypes(); + auto types2 = getAvailablePrimaryTypes(); + char[][] result = new char[][types1.length + types2.length]; + int count = 0; + for (int i = 0; i < types1.length; i++) { + auto pName = OS.gdk_atom_name(types1[i]); + if (pName is null) { + continue; + } + char[] buffer = tango.stdc.stringz.fromUtf8z( pName ).dup; + OS.g_free (pName); + result[count++] = "GTKCLIPBOARD "~buffer; + } + for (int i = 0; i < types2.length; i++) { + auto pName = OS.gdk_atom_name(types2[i]); + if (pName is null) { + continue; + } + char[] buffer = tango.stdc.stringz.fromUtf8z( pName ).dup; + OS.g_free (pName); + result[count++] = "GTKPRIMARYCLIPBOARD "~buffer; + } + if (count < result.length){ + char[][] temp = new char[][count]; + System.arraycopy(result, 0, temp, 0, count); + result = temp; + } + return result; +} + +private void*[] getAvailablePrimaryTypes() { + void*[] types; + auto selection_data = gtk_clipboard_wait_for_contents(GTKPRIMARYCLIPBOARD, TARGET); + if (selection_data !is null) { + try { + GtkSelectionData* gtkSelectionData = selection_data; + if (gtkSelectionData.length !is 0) { + types = cast(void*[])new int[gtkSelectionData.length * 8 / gtkSelectionData.format]; + tango.stdc.string.memmove( cast(void*)types.ptr, gtkSelectionData.data, gtkSelectionData.length ); + } + } finally { + OS.gtk_selection_data_free(selection_data); + } + } + return types; +} +private void*[] getAvailableClipboardTypes () { + void*[] types; + auto selection_data = gtk_clipboard_wait_for_contents(GTKCLIPBOARD, TARGET); + if (selection_data !is null) { + try { + GtkSelectionData* gtkSelectionData = selection_data; + if (gtkSelectionData.length !is 0) { + types = cast(void*[])new int[gtkSelectionData.length * 8 / gtkSelectionData.format]; + tango.stdc.string.memmove( cast(void*)types, gtkSelectionData.data, gtkSelectionData.length); + } + } finally { + OS.gtk_selection_data_free(selection_data); + } + } + return types; +} + +GtkSelectionData* gtk_clipboard_wait_for_contents(void* clipboard, void* target) { + char[] key = "org.eclipse.swt.internal.gtk.dispatchEvent"; + Display display = this.display; + ArrayWrapperInt arr = new ArrayWrapperInt( [ OS.GDK_PROPERTY_NOTIFY, OS.GDK_SELECTION_CLEAR, OS.GDK_SELECTION_REQUEST, OS.GDK_SELECTION_NOTIFY ] ); + display.setData(key, arr ); + GtkSelectionData* selection_data = OS.gtk_clipboard_wait_for_contents(clipboard, target); + display.setData(key, null); + return selection_data; +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/ClipboardProxy.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.ClipboardProxy; + + + +import dwt.DWT; +import dwt.internal.gtk.OS; +import dwt.widgets.Display; +import dwt.widgets.Event; +import dwt.widgets.Listener; +import dwt.dnd.Transfer; +import dwt.dnd.Clipboard; +import dwt.dnd.DND; +import dwt.dnd.TransferData; + +import dwt.dwthelper.System; +static import tango.stdc.string; + + +class ClipboardProxy { + /* Data is not flushed to the clipboard immediately. + * This class will remember the data and provide it when requested. + */ + Object[] clipboardData; + Transfer[] clipboardDataTypes; + Object[] primaryClipboardData; + Transfer[] primaryClipboardDataTypes; + + Display display; + Clipboard activeClipboard = null; + Clipboard activePrimaryClipboard = null; + + static char[] ID = "CLIPBOARD PROXY OBJECT"; //$NON-NLS-1$ + +static ClipboardProxy _getInstance(Display display) { + ClipboardProxy proxy = cast(ClipboardProxy) display.getData(ID); + if (proxy !is null) return proxy; + proxy = new ClipboardProxy(display); + display.setData(ID, proxy); + display.addListener(DWT.Dispose, new class( display ) Listener { + Display disp; + this( Display disp ){ this.disp = disp; } + public void handleEvent(Event event) { + ClipboardProxy clipbordProxy = cast(ClipboardProxy)disp.getData(ID); + if (clipbordProxy is null) return; + display.setData(ID, null); + clipbordProxy.dispose(); + } + }); + return proxy; +} + +this(Display display) { + this.display = display; +} + +void clear (Clipboard owner, int clipboards) { + if ((clipboards & DND.CLIPBOARD) !is 0 && activeClipboard is owner) { + OS.gtk_clipboard_clear(Clipboard.GTKCLIPBOARD); + } + if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0 && activePrimaryClipboard is owner) { + OS.gtk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD); + } +} + +private static extern(C) void clearFuncFunc(GtkClipboard *clipboard, void* user_data_or_owner){ + auto obj = cast(ClipboardProxy)user_data_or_owner; + obj.clearFunc( clipboard ); +} +void clearFunc(GtkClipboard *clipboard ){ + if (clipboard is Clipboard.GTKCLIPBOARD) { + activeClipboard = null; + clipboardData = null; + clipboardDataTypes = null; + } + if (clipboard is Clipboard.GTKPRIMARYCLIPBOARD) { + activePrimaryClipboard = null; + primaryClipboardData = null; + primaryClipboardDataTypes = null; + } +} + +void dispose () { + if (display is null) return; + if (activeClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKCLIPBOARD); + if (activePrimaryClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD); + display = null; + clipboardData = null; + clipboardDataTypes = null; + primaryClipboardData = null; + primaryClipboardDataTypes = null; +} + +private static extern(C) void getFuncFunc( + GtkClipboard *clipboard, + GtkSelectionData *selection_data, + uint info, + void* user_data_or_owner) +{ + auto obj = cast(ClipboardProxy)user_data_or_owner; + obj.getFunc( clipboard, selection_data, info ); +} +/** + * This function provides the data to the clipboard on request. + * When this clipboard is disposed, the data will no longer be available. + */ +void getFunc( + GtkClipboard *clipboard, + GtkSelectionData *selectionData, + uint info) +{ + if (selectionData is null) return 0; + TransferData tdata = new TransferData(); + tdata.type = selectionData.target; + Transfer[] types = (clipboard is Clipboard.GTKCLIPBOARD) ? clipboardDataTypes : primaryClipboardDataTypes; + int index = -1; + for (int i = 0; i < types.length; i++) { + if (types[i].isSupportedType(tdata)) { + index = i; + break; + } + } + if (index is -1) return 0; + Object[] data = (clipboard is Clipboard.GTKCLIPBOARD) ? clipboardData : primaryClipboardData; + types[index].javaToNative(data[index], tdata); + if (tdata.format < 8 || tdata.format % 8 !is 0) { + return 0; + } + OS.gtk_selection_data_set(selectionData, tdata.type, tdata.format, tdata.pValue, tdata.length); + OS.g_free(tdata.pValue); + return 1; +} + +bool setData(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) { + GtkTargetEntry*[] entries; + GtkTargetEntry* pTargetsList; + try { + for (int i = 0; i < dataTypes.length; i++) { + Transfer transfer = dataTypes[i]; + int[] typeIds = transfer.getTypeIds(); + char[][] typeNames = transfer.getTypeNames(); + for (int j = 0; j < typeIds.length; j++) { + GtkTargetEntry* entry = new GtkTargetEntry(); + entry.info = typeIds[j]; + char* pName = cast(char*)OS.g_malloc(typeNames[j].length+1); + pName[ 0 .. typeNames[j].length ] = typeNames[j]; + pName[ typeNames[j].length ] = '\0'; + entry.target = pName; + GtkTargetEntry*[] tmp = new GtkTargetEntry*[entries.length + 1]; + SimpleType!(GtkTargetEntry*).arraycopy(entries, 0, tmp, 0, entries.length); + tmp[entries.length] = entry; + entries = tmp; + } + } + + pTargetsList = cast(GtkTargetEntry*)OS.g_malloc(GtkTargetEntry.sizeof * entries.length); + int offset = 0; + for (int i = 0; i < entries.length; i++) { + tango.stdc.string.memmove(pTargetsList + offset, entries[i], GtkTargetEntry.sizeof); + offset += GtkTargetEntry.sizeof; + } + if ((clipboards & DND.CLIPBOARD) !is 0) { + if (activeClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKCLIPBOARD); + clipboardData = data; + clipboardDataTypes = dataTypes; + if (!OS.gtk_clipboard_set_with_data(Clipboard.GTKCLIPBOARD, pTargetsList, entries.length, &getFuncFunc, &clearFuncFunc, cast(void*)this )) { + return false; + } + activeClipboard = owner; + } + if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0) { + if (activePrimaryClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD); + primaryClipboardData = data; + primaryClipboardDataTypes = dataTypes; + if (!OS.gtk_clipboard_set_with_data(Clipboard.GTKPRIMARYCLIPBOARD, pTargetsList, entries.length, &getFuncFunc, &clearFuncFunc, cast(void*)this )) { + return false; + } + activePrimaryClipboard = owner; + } + return true; + } finally { + for (int i = 0; i < entries.length; i++) { + GtkTargetEntry* entry = entries[i]; + if( entry.target !is null) OS.g_free(entry.target); + } + if (pTargetsList !is null) OS.g_free(pTargetsList); + } +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DND.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,269 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.DND; + + +import dwt.DWT; +import dwt.DWTError; +import dwt.DWTException; + +import tango.util.Convert; + +/** + * + * Class DND contains all the constants used in defining a + * DragSource or a DropTarget. + * + */ +public class DND { + + /** + * The transfer mechanism for data that is being cut + * and then pasted or copied and then pasted (value is 1). + * + * @see Clipboard + * + * @since 3.1 + */ + public const static int CLIPBOARD = 1 << 0; + + /** + * The transfer mechanism for clients that use the selection + * mechanism (value is 2). + * + * @see Clipboard + * + * @since 3.1 + */ + public const static int SELECTION_CLIPBOARD = 1 << 1; + + /** + * Drag and Drop Operation: no drag/drop operation performed + * (value is 0). + */ + public const static int DROP_NONE = 0; + + /** + * Drag and Drop Operation: a copy of the data in the drag source is + * added to the drop target (value is 1 << 0). + */ + public const static int DROP_COPY = 1 << 0; + + /** + * Drag and Drop Operation: a copy of the data is added to the drop target and + * the original data is removed from the drag source (value is 1 << 1). + */ + public const static int DROP_MOVE = 1 << 1; + + /** + * Drag and Drop Operation: the drop target makes a link to the data in + * the drag source (value is 1 << 2). + */ + public const static int DROP_LINK = 1 << 2; + + /** + * Drag and Drop Operation: the drop target moves the data and the drag source removes + * any references to the data and updates its display. This is not available on all platforms + * and is only used when a non-DWT application is the drop target. In this case, the DWT + * drag source is informed in the dragFinished event that the drop target has moved the data. + * (value is 1 << 3). + * + * @see DragSourceListener#dragFinished + */ + public const static int DROP_TARGET_MOVE = 1 << 3; + + /** + * Drag and Drop Operation: During a dragEnter event or a dragOperationChanged, if no modifier keys + * are pressed, the operation is set to DROP_DEFAULT. The application can choose what the default + * operation should be by setting a new value in the operation field. If no value is choosen, the + * default operation for the platform will be selected (value is 1 << 4). + * + * @see DropTargetListener#dragEnter + * @see DropTargetListener#dragOperationChanged + * @since 2.0 + */ + public const static int DROP_DEFAULT = 1 << 4; + + /** + * DragSource Event: the drop has successfully completed or has been terminated (such as hitting + * the ESC key); perform cleanup such as removing data on a move operation (value is 2000). + */ + public static const int DragEnd = 2000; + + /** + * DragSource Event: the data to be dropped is required from the drag source (value is 2001). + */ + public static const int DragSetData = 2001; + + /** + * DropTarget Event: the cursor has entered the drop target boundaries (value is 2002). + */ + public static const int DragEnter = 2002; + + /** + * DropTarget Event: the cursor has left the drop target boundaries OR the drop + * operation has been cancelled (such as by hitting ECS) OR the drop is about to + * happen (user has released the mous ebutotn over this target) (value is 2003). + */ + public static const int DragLeave = 2003; + + /** + * DropTarget Event: the cursor is over the drop target (value is 2004). + */ + public static const int DragOver = 2004; + + /** + * DropTarget Event: the operation being performed has changed usually due to the user + * changing the selected modifier keys while dragging (value is 2005). + */ + public static const int DragOperationChanged = 2005; + + /** + * DropTarget Event: the data has been dropped (value is 2006). + */ + public static const int Drop = 2006; + + /** + * DropTarget Event: the drop target is given a last chance to modify the drop (value is 2007). + */ + public static const int DropAccept = 2007; + + /** + * DragSource Event: a drag is about to begin (value is 2008). + */ + public static const int DragStart = 2008; + + /** + * DropTarget drag under effect: No effect is shown (value is 0). + */ + public static const int FEEDBACK_NONE = 0; + + /** + * DropTarget drag under effect: The item under the cursor is selected; applies to tables + * and trees (value is 1). + */ + public static const int FEEDBACK_SELECT = 1; + + /** + * DropTarget drag under effect: An insertion mark is shown before the item under the cursor; applies to + * trees (value is 2). + */ + public static const int FEEDBACK_INSERT_BEFORE = 2; + + /** + * DropTarget drag under effect:An insertion mark is shown after the item under the cursor; applies to + * trees (value is 4). + */ + public static const int FEEDBACK_INSERT_AFTER = 4; + + /** + * DropTarget drag under effect: The widget is scrolled up or down to allow the user to drop on items that + * are not currently visible; applies to tables and trees (value is 8). + */ + public static const int FEEDBACK_SCROLL = 8; + + /** + * DropTarget drag under effect: The item currently under the cursor is expanded to allow the user to + * select a drop target from a sub item; applies to trees (value is 16). + */ + public static const int FEEDBACK_EXPAND = 16; + + /** + * Error code: drag source can not be initialized (value is 2000). + */ + public static const int ERROR_CANNOT_INIT_DRAG = 2000; + + /** + * Error code: drop target cannot be initialized (value is 2001). + */ + public static const int ERROR_CANNOT_INIT_DROP = 2001; + + /** + * Error code: Data can not be set on system clipboard (value is 2002). + */ + public static const int ERROR_CANNOT_SET_CLIPBOARD = 2002; + + /** + * Error code: Data does not have correct format for type (value is 2003). + * @since 3.1 + */ + public static const int ERROR_INVALID_DATA = 2003; + + + static const char[] INIT_DRAG_MESSAGE = "Cannot initialize Drag"; //$NON-NLS-1$ + static const char[] INIT_DROP_MESSAGE = "Cannot initialize Drop"; //$NON-NLS-1$ + static const char[] CANNOT_SET_CLIPBOARD_MESSAGE = "Cannot set data in clipboard"; //$NON-NLS-1$ + static const char[] INVALID_DATA_MESSAGE = "Data does not have correct format for type"; //$NON-NLS-1$ + +/** + * Throws an appropriate exception based on the passed in error code. + * + * @param code the DND error code + */ +public static void error (int code) { + error (code, 0); +} + +/** + * Throws an appropriate exception based on the passed in error code. + * The <code>hresult</code> argument should be either 0, or the + * platform specific error code. + * <p> + * In DND, errors are reported by throwing one of three exceptions: + * <dl> + * <dd>java.lang.IllegalArgumentException</dd> + * <dt>thrown whenever one of the API methods is invoked with an illegal argument</dt> + * <dd>org.eclipse.swt.DWTException (extends java.lang.RuntimeException)</dd> + * <dt>thrown whenever a recoverable error happens internally in DWT</dt> + * <dd>org.eclipse.swt.DWTError (extends java.lang.Error)</dd> + * <dt>thrown whenever a <b>non-recoverable</b> error happens internally in DWT</dt> + * </dl> + * This method provides the logic which maps between error codes + * and one of the above exceptions. + * </p> + * + * @param code the DND error code. + * @param hresult the platform specific error code. + * + * @see DWTError + * @see DWTException + * @see IllegalArgumentException + */ +public static void error (int code, int hresult) { + switch (code) { + /* OS Failure/Limit (fatal, may occur only on some platforms) */ + case DND.ERROR_CANNOT_INIT_DRAG:{ + char[] msg = DND.INIT_DRAG_MESSAGE; + if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$ + throw new DWTError (code, msg); + } + case DND.ERROR_CANNOT_INIT_DROP:{ + char[] msg = DND.INIT_DROP_MESSAGE; + if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$ + throw new DWTError (code, msg); + } + case DND.ERROR_CANNOT_SET_CLIPBOARD:{ + char[] msg = DND.CANNOT_SET_CLIPBOARD_MESSAGE; + if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$ + throw new DWTError (code, msg); + } + case DND.ERROR_INVALID_DATA:{ + char[] msg = DND.INVALID_DATA_MESSAGE; + if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$ + throw new DWTException (code, msg); + } + } + + /* Unknown/Undefined Error */ + DWT.error(code); +} + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DNDEvent.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,25 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.DNDEvent; + + + +import dwt.graphics.Image; +import dwt.widgets.Event; +import dwt.dnd.TransferData; + +class DNDEvent : Event { + public TransferData dataType; + public TransferData[] dataTypes; + public int operations; + public int feedback; + public Image image; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DNDListener.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,134 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.DNDListener; + + +import dwt.internal.DWTEventListener; +import dwt.widgets.Event; +import dwt.widgets.TypedListener; +import dwt.widgets.Widget; +import dwt.dnd.DND; +import dwt.dnd.DNDEvent; +import dwt.dnd.DragSourceEvent; +import dwt.dnd.DragSourceEffect; +import dwt.dnd.DragSource; +import dwt.dnd.DragSourceListener; +import dwt.dnd.DropTargetEvent; +import dwt.dnd.DropTargetListener; +import dwt.dnd.DropTargetEffect; +import dwt.dnd.DropTarget; + + +class DNDListener : TypedListener { + Widget dndWidget; +/** + * DNDListener constructor comment. + * @param listener org.eclipse.swt.internal.DWTEventListener + */ +this(DWTEventListener listener) { + super(listener); +} +public void handleEvent (Event e) { + switch (e.type) { + case DND.DragStart: { + DragSourceEvent event = new DragSourceEvent(cast(DNDEvent)e); + DragSourceEffect sourceEffect = (cast(DragSource) dndWidget).getDragSourceEffect(); + if (sourceEffect !is null) { + sourceEffect.dragStart (event); + } + (cast(DragSourceListener) eventListener).dragStart (event); + event.updateEvent(cast(DNDEvent)e); + break; + } + case DND.DragEnd: { + DragSourceEvent event = new DragSourceEvent(cast(DNDEvent)e); + DragSourceEffect sourceEffect = (cast(DragSource) dndWidget).getDragSourceEffect(); + if (sourceEffect !is null) { + sourceEffect.dragFinished (event); + } + (cast(DragSourceListener) eventListener).dragFinished (event); + event.updateEvent(cast(DNDEvent)e); + break; + } + case DND.DragSetData: { + DragSourceEvent event = new DragSourceEvent(cast(DNDEvent)e); + DragSourceEffect sourceEffect = (cast(DragSource) dndWidget).getDragSourceEffect(); + if (sourceEffect !is null) { + sourceEffect.dragSetData (event); + } + (cast(DragSourceListener) eventListener).dragSetData (event); + event.updateEvent(cast(DNDEvent)e); + break; + } + case DND.DragEnter: { + DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e); + (cast(DropTargetListener) eventListener).dragEnter (event); + DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect(); + if (dropEffect !is null) { + dropEffect.dragEnter (event); + } + event.updateEvent(cast(DNDEvent)e); + break; + } + case DND.DragLeave: { + DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e); + (cast(DropTargetListener) eventListener).dragLeave (event); + DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect(); + if (dropEffect !is null) { + dropEffect.dragLeave (event); + } + event.updateEvent(cast(DNDEvent)e); + break; + } + case DND.DragOver: { + DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e); + (cast(DropTargetListener) eventListener).dragOver (event); + DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect(); + if (dropEffect !is null) { + dropEffect.dragOver (event); + } + event.updateEvent(cast(DNDEvent)e); + break; + } + case DND.Drop: { + DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e); + (cast(DropTargetListener) eventListener).drop (event); + DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect(); + if (dropEffect !is null) { + dropEffect.drop (event); + } + event.updateEvent(cast(DNDEvent)e); + break; + } + case DND.DropAccept: { + DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e); + (cast(DropTargetListener) eventListener).dropAccept (event); + DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect(); + if (dropEffect !is null) { + dropEffect.dropAccept (event); + } + event.updateEvent(cast(DNDEvent)e); + break; + } + case DND.DragOperationChanged: { + DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e); + (cast(DropTargetListener) eventListener).dragOperationChanged (event); + DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect(); + if (dropEffect !is null) { + dropEffect.dragOperationChanged (event); + } + event.updateEvent(cast(DNDEvent)e); + break; + } + + } +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DragSource.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,633 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.DragSource; + + + +import dwt.DWT; +import dwt.DWTError; +import dwt.DWTException; +import dwt.graphics.Image; +import dwt.graphics.ImageData; +import dwt.internal.gtk.OS; +import dwt.widgets.Control; +import dwt.widgets.Display; +import dwt.widgets.Event; +import dwt.widgets.Listener; +import dwt.widgets.Table; +import dwt.widgets.Tree; +import dwt.widgets.Widget; +import dwt.dnd.Transfer; +import dwt.dnd.DragSourceEffect; +import dwt.dnd.DragSourceListener; +import dwt.dnd.DND; +import dwt.dnd.TreeDragSourceEffect; +import dwt.dnd.TableDragSourceEffect; +import dwt.dnd.DNDListener; +import dwt.dnd.DNDEvent; +import dwt.dnd.TransferData; + +import tango.core.Thread; + +/** + * + * <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, DWT.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() is 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 is DND.DROP_MOVE) + * label.setText(""); + * } + * }); + * </pre></code> + * + * + * <dl> + * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd> + * <dt><b>Events</b></dt> <dd>DND.DragStart, DND.DragSetData, DND.DragEnd</dd> + * </dl> + */ +public class DragSource : Widget { + + // info for registering as a drag source + Control control; + Listener controlListener; + Transfer[] transferAgents; + DragSourceEffect dragEffect; + + void* targetList; + + //workaround - remember action performed for DragEnd + bool moveData = false; + + static const char[] DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$ + static const char[] DRAGSOURCEID = "DragSource"; //$NON-NLS-1$ + +// static Callback DragGetData; +// static Callback DragEnd; +// static Callback DragDataDelete; +// static this() { +// DragGetData = new Callback(DragSource.class, "DragGetData", 5); //$NON-NLS-1$ +// if (DragGetData.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); +// DragEnd = new Callback(DragSource.class, "DragEnd", 2); //$NON-NLS-1$ +// if (DragEnd.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); +// DragDataDelete = new Callback(DragSource.class, "DragDataDelete", 2); //$NON-NLS-1$ +// if (DragDataDelete.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); +// } + +/** + * Creates a new <code>DragSource</code> to handle dragging from the specified <code>Control</code>. + * Creating an instance of a DragSource may cause system resources to be allocated depending on the platform. + * It is therefore mandatory that the DragSource instance be disposed when no longer required. + * + * @param control the <code>Control</code> that the user clicks on to initiate the drag + * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of + * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK + * + * @exception DWTException <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 DWTError <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 DWTException, 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 this(Control control, int style) { + super (control, checkStyle(style)); + this.control = control; +// if (DragGetData is null || DragEnd is null || DragDataDelete is null) { +// DND.error(DND.ERROR_CANNOT_INIT_DRAG); +// } + if (control.getData(DRAGSOURCEID) !is null) { + DND.error(DND.ERROR_CANNOT_INIT_DRAG); + } + control.setData(DRAGSOURCEID, this); + + OS.g_signal_connect(control.handle, OS.drag_data_get.ptr, cast(GCallback)&DragGetData, null); + OS.g_signal_connect(control.handle, OS.drag_end.ptr, cast(GCallback)&DragEnd, null); + OS.g_signal_connect(control.handle, OS.drag_data_delete.ptr, cast(GCallback)&DragDataDelete, null); + + controlListener = new class() Listener { + public void handleEvent (Event event) { + if (event.type is DWT.Dispose) { + if (!this.outer.isDisposed()) { + this.outer.dispose(); + } + } + if (event.type is DWT.DragDetect) { + if (!this.outer.isDisposed()) { + this.outer.drag(event); + } + } + } + }; + control.addListener (DWT.Dispose, controlListener); + control.addListener (DWT.DragDetect, controlListener); + + Object effect = control.getData(DEFAULT_DRAG_SOURCE_EFFECT); + if ( auto de = cast(DragSourceEffect)effect ) { + dragEffect = de; + } else if ( auto tree = cast(Tree)control) { + dragEffect = new TreeDragSourceEffect(tree); + } else if ( auto table = cast(Table)control ) { + dragEffect = new TableDragSourceEffect(table); + } + + this.addListener(DWT.Dispose, new class() Listener { + public void handleEvent(Event e) { + onDispose(); + } + }); +} + +static int checkStyle (int style) { + if (style is DWT.NONE) return DND.DROP_MOVE; + return style; +} + +private static extern(C) void DragDataDelete( + GtkWidget *widget, + GdkDragContext *drag_context, + void* user_data ) +{ + DragSource source = FindDragSource(widget); + if (source is null) return; + source.dragDataDelete(widget, drag_context); + return; +} + +private static extern(C) void DragEnd ( + GtkWidget *widget, + GdkDragContext *drag_context, + void* user_data) +{ + DragSource source = FindDragSource(widget); + if (source is null) return; + source.dragEnd(widget, drag_context); + return; +} + +private static extern(C) void DragGetData( + GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + uint info, + uint time, + void* user_data ) +{ + DragSource source = FindDragSource(widget); + if (source is null) return; + source.dragGetData(widget, context, selection_data, cast(int)/*64*/info, cast(int)/*64*/time); + return; +} + +static DragSource FindDragSource(GtkWidget* handle) { + Display display = Display.findDisplay(Thread.getThis()); + if (display is null || display.isDisposed()) return null; + Widget widget = display.findWidget(handle); + if (widget is null) return null; + return cast(DragSource)widget.getData(DRAGSOURCEID); +} + +/** + * 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 DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see DragSourceListener + * @see #removeDragListener + * @see DragSourceEvent + */ +public void addDragListener(DragSourceListener listener) { + if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT); + DNDListener typedListener = new DNDListener (listener); + typedListener.dndWidget = this; + addListener (DND.DragStart, typedListener); + addListener (DND.DragSetData, typedListener); + addListener (DND.DragEnd, typedListener); +} + +protected void checkSubclass () { + char[] name = this.classinfo.name; + char[] validName = DragSource.stringof; + if ( validName !=/*eq*/ name ) { + DND.error (DWT.ERROR_INVALID_SUBCLASS); + } +} + +void drag(Event dragEvent) { + moveData = false; + DNDEvent event = new DNDEvent(); + event.widget = this; + event.x = dragEvent.x; + event.y = dragEvent.y; + event.time = dragEvent.time; + event.doit = true; + notifyListeners(DND.DragStart, event); + if (!event.doit || transferAgents is null || transferAgents.length is 0) return; + if (targetList is null) return; + + int actions = opToOsOp(getStyle()); + Image image = event.image; + auto context = OS.gtk_drag_begin(control.handle, targetList, actions, 1, null); + if (context !is null && image !is null) { + auto pixbuf = createPixbuf(image); + OS.gtk_drag_set_icon_pixbuf(context, pixbuf, 0, 0); + OS.g_object_unref(pixbuf); + } +} + +void dragEnd( + GtkWidget *widget, + GdkDragContext *context ) +{ + /* + * Bug in GTK. If a drag is initiated using gtk_drag_begin and the + * mouse is released immediately, the mouse and keyboard remain + * grabbed. The fix is to release the grab on the mouse and keyboard + * whenever the drag is terminated. + * + * NOTE: We believe that it is never an error to ungrab when + * a drag is finished. + */ + OS.gdk_pointer_ungrab(OS.GDK_CURRENT_TIME); + OS.gdk_keyboard_ungrab(OS.GDK_CURRENT_TIME); + + int operation = DND.DROP_NONE; + if (context !is null) { + GdkDragContext* gdkDragContext = context; + if (gdkDragContext.dest_window !is null) { //NOTE: if dest_window is 0, drag was aborted + if (moveData) { + operation = DND.DROP_MOVE; + } else { + operation = osOpToOp(gdkDragContext.action); + if (operation is DND.DROP_MOVE) operation = DND.DROP_NONE; + } + } + } + + DNDEvent event = new DNDEvent(); + event.widget = this; + //event.time = ??? + event.doit = operation !is 0; + event.detail = operation; + notifyListeners(DND.DragEnd, event); + moveData = false; +} + +void dragGetData( + GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *gtkSelectionData, + uint info, + uint time ) +{ + if (gtkSelectionData is null) return; + if (gtkSelectionData.target is null) return; + + TransferData transferData = new TransferData(); + transferData.type = gtkSelectionData.target; + transferData.pValue = gtkSelectionData.data; + transferData.length = gtkSelectionData.length; + transferData.format = gtkSelectionData.format; + + DNDEvent event = new DNDEvent(); + event.widget = this; + event.time = time; + event.dataType = transferData; + notifyListeners(DND.DragSetData, event); + + Transfer transfer = null; + for (int i = 0; i < transferAgents.length; i++) { + Transfer transferAgent = transferAgents[i]; + if (transferAgent !is null && transferAgent.isSupportedType(transferData)) { + transfer = transferAgent; + break; + } + } + if (transfer is null) return; + transfer.javaToNative(event.data, transferData); + if (transferData.result !is 1) return; + OS.gtk_selection_data_set(gtkSelectionData, transferData.type, transferData.format, transferData.pValue, transferData.length); + OS.g_free(transferData.pValue); + return; +} + +void dragDataDelete( + GtkWidget *widget, + GdkDragContext *drag_context) +{ + moveData = true; +} + +/** + * Returns the Control which is registered for this DragSource. This is the control that the + * user clicks in to initiate dragging. + * + * @return the Control which is registered for this DragSource + */ +public Control getControl () { + return control; +} + +/** + * Returns the drag effect that is registered for this DragSource. This drag + * effect will be used during a drag and drop operation. + * + * @return the drag effect that is registered for this DragSource + * + * @since 3.3 + */ +public DragSourceEffect getDragSourceEffect() { + return dragEffect; +} + +/** + * Returns the list of data types that can be transferred by this DragSource. + * + * @return the list of data types that can be transferred by this DragSource + */ +public Transfer[] getTransfer(){ + return transferAgents; +} + +void onDispose() { + if (control is null) return; + if (targetList !is null) { + OS.gtk_target_list_unref(targetList); + } + targetList = null; + if (controlListener !is null) { + control.removeListener(DWT.Dispose, controlListener); + control.removeListener(DWT.DragDetect, controlListener); + } + controlListener = null; + control.setData(DRAGSOURCEID, null); + control = null; + transferAgents = null; +} + +int opToOsOp(int operation){ + int osOperation = 0; + + if ((operation & DND.DROP_COPY) is DND.DROP_COPY) + osOperation |= OS.GDK_ACTION_COPY; + if ((operation & DND.DROP_MOVE) is DND.DROP_MOVE) + osOperation |= OS.GDK_ACTION_MOVE; + if ((operation & DND.DROP_LINK) is DND.DROP_LINK) + osOperation |= OS.GDK_ACTION_LINK; + + return osOperation; +} + +int osOpToOp(int osOperation){ + int operation = DND.DROP_NONE; + + if ((osOperation & OS.GDK_ACTION_COPY) is OS.GDK_ACTION_COPY) + operation |= DND.DROP_COPY; + if ((osOperation & OS.GDK_ACTION_MOVE) is OS.GDK_ACTION_MOVE) + operation |= DND.DROP_MOVE; + if ((osOperation & OS.GDK_ACTION_LINK) is OS.GDK_ACTION_LINK) + operation |= DND.DROP_LINK; + + return operation; +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when a drag and drop operation is in progress. + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see DragSourceListener + * @see #addDragListener + */ +public void removeDragListener(DragSourceListener listener) { + if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT); + removeListener (DND.DragStart, listener); + removeListener (DND.DragSetData, listener); + removeListener (DND.DragEnd, listener); +} + +/** + * Specifies the drag effect for this DragSource. This drag effect will be + * used during a drag and drop operation. + * + * @param effect the drag effect that is registered for this DragSource + * + * @since 3.3 + */ +public void setDragSourceEffect(DragSourceEffect effect) { + dragEffect = effect; +} + +/** + * Specifies the list of data types that can be transferred by this DragSource. + * The application must be able to provide data to match each of these types when + * a successful drop has occurred. + * + * @param transferAgents a list of Transfer objects which define the types of data that can be + * dragged from this source + */ +public void setTransfer(Transfer[] transferAgents){ + if (targetList !is null) { + OS.gtk_target_list_unref(targetList); + targetList = null; + } + this.transferAgents = transferAgents; + if (transferAgents is null || transferAgents.length is 0) return; + + GtkTargetEntry*[] targets; + for (int i = 0; i < transferAgents.length; i++) { + Transfer transfer = transferAgents[i]; + if (transfer !is null) { + int[] typeIds = transfer.getTypeIds(); + char[][] typeNames = transfer.getTypeNames(); + for (int j = 0; j < typeIds.length; j++) { + GtkTargetEntry* entry = new GtkTargetEntry(); + char[] type = typeNames[j]; + entry.target = cast(char*)OS.g_malloc(type.length+1); + entry.target[ 0 .. type.length ] = type[]; + entry.target[ type.length ] = '\0'; + entry.info = typeIds[j]; + GtkTargetEntry*[] newTargets = new GtkTargetEntry*[targets.length + 1]; + SimpleType!(GtkTargetEntry*).arraycopy(targets, 0, newTargets, 0, targets.length); + newTargets[targets.length] = entry; + targets = newTargets; + } + } + } + + void* pTargets = OS.g_malloc(targets.length * GtkTargetEntry.sizeof); + for (int i = 0; i < targets.length; i++) { + tango.stdc.string.memmove(pTargets + i*GtkTargetEntry.sizeof, targets[i], GtkTargetEntry.sizeof); + } + targetList = OS.gtk_target_list_new(pTargets, targets.length); + + for (int i = 0; i < targets.length; i++) { + OS.g_free(targets[i].target); + } +} + +static GdkDrawable* createPixbuf(Image image) { + int w, h; + OS.gdk_drawable_get_size (image.pixmap, &w, &h); + auto colormap = OS.gdk_colormap_get_system (); + void* pixbuf; + bool hasMask = image.mask !is null && OS.gdk_drawable_get_depth (image.mask) is 1; + if (hasMask) { + pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, true, 8, w, h); + if (pixbuf is null) DWT.error (DWT.ERROR_NO_HANDLES); + OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w , h); + auto maskPixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, w , h ); + if (maskPixbuf is null) DWT.error (DWT.ERROR_NO_HANDLES); + OS.gdk_pixbuf_get_from_drawable(maskPixbuf, image.mask, null, 0, 0, 0, 0, w , h ); + int stride = OS.gdk_pixbuf_get_rowstride(pixbuf); + auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf); + byte[] line = new byte[stride]; + int maskStride = OS.gdk_pixbuf_get_rowstride(maskPixbuf); + auto maskPixels = OS.gdk_pixbuf_get_pixels(maskPixbuf); + byte[] maskLine = new byte[maskStride]; + for (int y=0; y<h; y++) { + auto offset = pixels + (y * stride); + tango.stdc.string.memmove(line.ptr, offset, stride); + auto maskOffset = maskPixels + (y * maskStride); + tango.stdc.string.memmove(maskLine.ptr, maskOffset, maskStride); + for (int x=0; x<w; x++) { + if (maskLine[x * 3] is 0) { + line[x * 4 + 3] = 0; + } + } + tango.stdc.string.memmove(offset, line.ptr, stride); + } + OS.g_object_unref(maskPixbuf); + } else { + ImageData data = image.getImageData (); + bool hasAlpha = data.getTransparencyType () is DWT.TRANSPARENCY_ALPHA; + pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, hasAlpha, 8, w , h ); + if (pixbuf is null) DWT.error (DWT.ERROR_NO_HANDLES); + OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w , h ); + if (hasAlpha) { + byte [] alpha = data.alphaData; + int stride = OS.gdk_pixbuf_get_rowstride (pixbuf); + auto pixels = OS.gdk_pixbuf_get_pixels (pixbuf); + byte [] line = new byte [stride]; + for (int y = 0; y < h ; y++) { + auto offset = pixels + (y * stride); + tango.stdc.string.memmove (line.ptr, offset, stride); + for (int x = 0; x < w ; x++) { + line [x*4+3] = alpha [y*w +x]; + } + tango.stdc.string.memmove (offset, line.ptr, stride); + } + } + } + return cast(GdkDrawable*)pixbuf; +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DragSourceAdapter.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 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 + *******************************************************************************/ +module dwt.dnd.DragSourceAdapter; + +import dwt.dnd.DragSourceListener; +import dwt.dnd.DragSourceEvent; + +/** + * This adapter class provides default implementations for the + * methods described by the <code>DragSourceListener</code> interface. + * + * <p>Classes that wish to deal with <code>DragSourceEvent</code>s can + * extend this class and override only the methods which they are + * interested in.</p> + * + * @see DragSourceListener + * @see DragSourceEvent + */ +public class DragSourceAdapter : DragSourceListener { + /** + * This implementation of <code>dragStart</code> permits the drag operation to start. + * For additional information see <code>DragSourceListener.dragStart</code>. + */ + public void dragStart(DragSourceEvent event){} + /** + * This implementation of <code>dragFinished</code> does nothing. + * For additional information see <code>DragSourceListener.dragFinished</code>. + */ + public void dragFinished(DragSourceEvent event){} + /** + * This implementation of <code>dragSetData</code> does nothing. + * For additional information see <code>DragSourceListener.dragSetData</code>. + */ + public void dragSetData(DragSourceEvent event){} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DragSourceEffect.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.DragSourceEffect; + + +import dwt.DWT; +import dwt.widgets.Control; +import dwt.dnd.DragSourceAdapter; + +/** + * This class provides default implementations to display a drag source + * effect during a drag and drop operation. The current implementation + * does not provide any visual feedback. + * + * <p>The drag source effect has the same API as the + * <code>DragSourceAdapter</code> so that it can provide custom visual + * feedback when a <code>DragSourceEvent</code> occurs. + * </p> + * + * <p>Classes that wish to provide their own drag source effect such as + * displaying a default source image during a drag can extend the <code>DragSourceEffect</code> + * class, override the <code>DragSourceAdapter.dragStart</code> method and set + * the field <code>DragSourceEvent.image</code> with their own image. + * The image should be disposed when <code>DragSourceAdapter.dragFinished</code> is called. + * </p> + * + * @see DragSourceAdapter + * @see DragSourceEvent + * + * @since 3.3 + */ +public class DragSourceEffect : DragSourceAdapter { + Control control = null; + + /** + * Creates a new <code>DragSourceEffect</code> to handle drag effect from the specified <code>Control</code>. + * + * @param control the <code>Control</code> that the user clicks on to initiate the drag + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the control is null</li> + * </ul> + */ + public this(Control control) { + if (control is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + this.control = control; + } + + /** + * Returns the Control which is registered for this DragSourceEffect. This is the control that the + * user clicks in to initiate dragging. + * + * @return the Control which is registered for this DragSourceEffect + */ + public Control getControl() { + return control; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DragSourceEvent.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,109 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.DragSourceEvent; + + +import dwt.events.TypedEvent; +import dwt.widgets.Event; +import dwt.graphics.Image; +import dwt.dnd.TransferData; +import dwt.dnd.DNDEvent; + +/** + * The DragSourceEvent contains the event information passed in the methods of the DragSourceListener. + * + * @see DragSourceListener + */ +public class DragSourceEvent : TypedEvent { + /** + * The operation that was performed. + * @see DND#DROP_NONE + * @see DND#DROP_MOVE + * @see DND#DROP_COPY + * @see DND#DROP_LINK + * @see DND#DROP_TARGET_MOVE + */ + public int detail; + + /** + * In dragStart, the doit field determines if the drag and drop operation + * should proceed; in dragFinished, the doit field indicates whether + * the operation was performed successfully. + * <p></p> + * In dragStart: + * <p>Flag to determine if the drag and drop operation should proceed. + * The application can set this value to false to prevent the drag from starting. + * Set to true by default.</p> + * + * <p>In dragFinished:</p> + * <p>Flag to indicate if the operation was performed successfully. + * True if the operation was performed successfully.</p> + */ + public bool doit; + + /** + * In dragStart, the x coordinate (relative to the control) of the + * position the mouse went down to start the drag. + * @since 3.2 + */ + public int x; + /** + * In dragStart, the y coordinate (relative to the control) of the + * position the mouse went down to start the drag . + * @since 3.2 + */ + public int y; + + /** + * The type of data requested. + * Data provided in the data field must be of the same type. + */ + public TransferData dataType; + + /** + * The drag source image to be displayed during the drag. + * <p>A value of null indicates that no drag image will be displayed.</p> + * <p>The default value is null.</p> + * + * @since 3.3 + */ + public Image image; + + static const long serialVersionUID = 3257002142513770808L; + +/** + * Constructs a new instance of this class based on the + * information in the given untyped event. + * + * @param e the untyped event containing the information + */ +public this(DNDEvent e) { + super( cast(Event) e ); + this.data = e.data; + this.detail = e.detail; + this.doit = e.doit; + this.dataType = e.dataType; + this.x = e.x; + this.y = e.y; + this.image = e.image; +} +void updateEvent(DNDEvent e) { + e.widget = this.widget; + e.time = this.time; + e.data = this.data; + e.detail = this.detail; + e.doit = this.doit; + e.dataType = this.dataType; + e.x = this.x; + e.y = this.y; + e.image = this.image; +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DragSourceListener.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 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 + *******************************************************************************/ +module dwt.dnd.DragSourceListener; + +import dwt.internal.DWTEventListener; +import dwt.dnd.DragSourceEvent; + +/** + * The <code>DragSourceListener</code> class provides event notification to the application for DragSource events. + * + * <p>When the user drops data on a <code>DropTarget</code>, the application which defines the <code>DragSource</code> + * must provide the dropped data by implementing <code>dragSetData</code>. In the dragSetData, the application + * must support all the data types that were specified in the DragSource#setTransfer method.</p> + * + * <p>After the drop has completed successfully or has been aborted, the application which defines the + * <code>DragSource</code> is required to take the appropriate cleanup action. In the case of a successful + * <b>move</b> operation, the application must remove the data that was transferred.</p> + * + */ +public interface DragSourceListener : DWTEventListener { + +/** + * 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. + * + * <p>The following fields in the DragSourceEvent apply: + * <ul> + * <li>(in)widget + * <li>(in)time + * <li>(in,out)doit + * </ul></p> + * + * @param event the information associated with the drag start event + * + * @see DragSourceEvent + */ +public void dragStart(DragSourceEvent event); + +/** + * The data is required from the drag source. + * + * <p>The following fields in the DragSourceEvent apply: + * <ul> + * <li>(in)widget + * <li>(in)time + * <li>(in)dataType - the type of data requested. + * <li>(out)data - the application inserts the actual data here (must match the dataType) + * </ul></p> + * + * @param event the information associated with the drag set data event + * + * @see DragSourceEvent + */ +public void dragSetData(DragSourceEvent event); + +/** + * 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. + * + * <p>The following fields in the DragSourceEvent apply: + * <ul> + * <li>(in)widget + * <li>(in)time + * <li>(in)doit + * <li>(in)detail + * </ul></p> + * + * @param event the information associated with the drag finished event + * + * @see DragSourceEvent + */ +public void dragFinished(DragSourceEvent event); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DropTarget.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,820 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.DropTarget; + + + +import dwt.DWT; +import dwt.DWTError; +import dwt.DWTException; +import dwt.graphics.Point; +import dwt.internal.gtk.OS; +import dwt.widgets.Control; +import dwt.widgets.Display; +import dwt.widgets.Event; +import dwt.widgets.Listener; +import dwt.widgets.Table; +import dwt.widgets.Tree; +import dwt.widgets.Widget; +import dwt.dnd.DND; +import dwt.dnd.Transfer; +import dwt.dnd.DropTargetEffect; +import dwt.dnd.DNDEvent; +import dwt.dnd.DNDListener; +import dwt.dnd.TransferData; +import dwt.dnd.DropTargetListener; +import dwt.dnd.TableDropTargetEffect; +import dwt.dnd.TreeDropTargetEffect; + +import dwt.dwthelper.Runnable; +import tango.core.Thread; +static import tango.stdc.string; + +/** + * + * Class <code>DropTarget</code> defines the target object for a drag and drop transfer. + * + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * + * <p>This class identifies the <code>Control</code> over which the user must position the cursor + * in order to drop the data being transferred. It also specifies what data types can be dropped on + * this control and what operations can be performed. You may have several DropTragets in an + * application but there can only be a one to one mapping between a <code>Control</code> and a <code>DropTarget</code>. + * The DropTarget can receive data from within the same application or from other applications + * (such as text dragged from a text editor like Word).</p> + * + * <code><pre> + * int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK; + * Transfer[] types = new Transfer[] {TextTransfer.getInstance()}; + * DropTarget target = new DropTarget(label, operations); + * target.setTransfer(types); + * </code></pre> + * + * <p>The application is notified of data being dragged over this control and of when a drop occurs by + * implementing the interface <code>DropTargetListener</code> which uses the class + * <code>DropTargetEvent</code>. The application can modify the type of drag being performed + * on this Control at any stage of the drag by modifying the <code>event.detail</code> field or the + * <code>event.currentDataType</code> field. When the data is dropped, it is the responsibility of + * the application to copy this data for its own purposes. + * + * <code><pre> + * target.addDropListener (new DropTargetListener() { + * public void dragEnter(DropTargetEvent event) {}; + * public void dragOver(DropTargetEvent event) {}; + * public void dragLeave(DropTargetEvent event) {}; + * public void dragOperationChanged(DropTargetEvent event) {}; + * public void dropAccept(DropTargetEvent event) {} + * public void drop(DropTargetEvent event) { + * // A drop has occurred, copy over the data + * if (event.data is null) { // no data to copy, indicate failure in event.detail + * event.detail = DND.DROP_NONE; + * return; + * } + * label.setText ((String) event.data); // data copied to label text + * } + * }); + * </pre></code> + * + * <dl> + * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd> + * <dt><b>Events</b></dt> <dd>DND.DragEnter, DND.DragLeave, DND.DragOver, DND.DragOperationChanged, + * DND.DropAccept, DND.Drop </dd> + * </dl> + */ +public class DropTarget : Widget { + + Control control; + Listener controlListener; + Transfer[] transferAgents; + 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 - Simulate events when the mouse is not moving + long dragOverStart; + Runnable dragOverHeartbeat; + DNDEvent dragOverEvent; + + int drag_motion_handler; + int drag_leave_handler; + int drag_data_received_handler; + int drag_drop_handler; + + static const char[] DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$ + static const char[] DROPTARGETID = "DropTarget"; //$NON-NLS-1$ + static const int DRAGOVER_HYSTERESIS = 50; + +// static Callback Drag_Motion; +// static Callback Drag_Leave; +// static Callback Drag_Data_Received; +// static Callback Drag_Drop; +// +// static this(){ +// Drag_Motion = new Callback(DropTarget.class, "Drag_Motion", 5); //$NON-NLS-1$ +// if (Drag_Motion.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); +// Drag_Leave = new Callback(DropTarget.class, "Drag_Leave", 3); //$NON-NLS-1$ +// if (Drag_Leave.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); +// Drag_Data_Received = new Callback(DropTarget.class, "Drag_Data_Received", 7); //$NON-NLS-1$ +// if (Drag_Data_Received.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); +// Drag_Drop = new Callback(DropTarget.class, "Drag_Drop", 5); //$NON-NLS-1$ +// if (Drag_Drop.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); +// } + +/** + * 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 DWTException <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 DWTError <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 DWTException, 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 this(Control control, int style) { + super(control, checkStyle(style)); + this.control = control; +// if (Drag_Motion is null || Drag_Leave is null || Drag_Data_Received is null || Drag_Drop is null) { +// DND.error(DND.ERROR_CANNOT_INIT_DROP); +// } + if (control.getData(DROPTARGETID) !is null) { + DND.error(DND.ERROR_CANNOT_INIT_DROP); + } + control.setData(DROPTARGETID, this); + + drag_motion_handler = OS.g_signal_connect(control.handle, OS.drag_motion.ptr, cast(GCallback)&Drag_Motion, null); + drag_leave_handler = OS.g_signal_connect(control.handle, OS.drag_leave.ptr, cast(GCallback)&Drag_Leave, null); + drag_data_received_handler = OS.g_signal_connect(control.handle, OS.drag_data_received.ptr, cast(GCallback)&Drag_Data_Received, null); + drag_drop_handler = OS.g_signal_connect(control.handle, OS.drag_drop.ptr, cast(GCallback)&Drag_Drop, null); + + // Dispose listeners + controlListener = new class() Listener{ + public void handleEvent(Event event){ + if (!this.outer.isDisposed()){ + this.outer.dispose(); + } + } + }; + control.addListener(DWT.Dispose, controlListener); + + this.addListener(DWT.Dispose, new class() Listener { + public void handleEvent(Event event){ + onDispose(); + } + }); + + Object effect = control.getData(DEFAULT_DROP_TARGET_EFFECT); + if ( auto de = cast(DropTargetEffect)effect ) { + dropEffect = de; + } else if ( auto table = cast(Table)control ) { + dropEffect = new TableDropTargetEffect(table); + } else if ( auto tree = cast(Tree) control ) { + dropEffect = new TreeDropTargetEffect(tree); + } + + dragOverHeartbeat = new class() Runnable { + public void run() { + Control control = this.outer.control; + if (control is null || control.isDisposed() || dragOverStart is 0) return; + long time = System.currentTimeMillis(); + int delay = DRAGOVER_HYSTERESIS; + if (time < dragOverStart) { + delay = cast(int)(dragOverStart - time); + } else { + dragOverEvent.time += DRAGOVER_HYSTERESIS; + int allowedOperations = dragOverEvent.operations; + TransferData[] allowedTypes = dragOverEvent.dataTypes; + //pass a copy of data types in to listeners in case application modifies it + TransferData[] dataTypes = new TransferData[allowedTypes.length]; + System.arraycopy(allowedTypes, 0, dataTypes, 0, dataTypes.length); + + DNDEvent event = new DNDEvent(); + event.widget = dragOverEvent.widget; + event.x = dragOverEvent.x; + event.y = dragOverEvent.y; + event.time = dragOverEvent.time; + event.feedback = DND.FEEDBACK_SELECT; + event.dataTypes = dataTypes; + event.dataType = selectedDataType; + event.operations = dragOverEvent.operations; + event.detail = selectedOperation; + if (dropEffect !is null) { + event.item = dropEffect.getItem(dragOverEvent.x, dragOverEvent.y); + } + selectedDataType = null; + selectedOperation = DND.DROP_NONE; + notifyListeners(DND.DragOver, event); + if (event.dataType !is null) { + for (int i = 0; i < allowedTypes.length; i++) { + if (allowedTypes[i].type is event.dataType.type) { + selectedDataType = event.dataType; + break; + } + } + } + if (selectedDataType !is null && (event.detail & allowedOperations) !is 0) { + selectedOperation = event.detail; + } + } + control = this.outer.control; + if (control is null || control.isDisposed()) return; + control.getDisplay().timerExec(delay, dragOverHeartbeat); + } + }; +} + +static int checkStyle (int style) { + if (style is DWT.NONE) return DND.DROP_MOVE; + return style; +} + +private static extern(C) void Drag_Data_Received ( + GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + GtkSelectionData *data, + uint info, + uint time, + void* user_data) +{ + DropTarget target = FindDropTarget(widget); + if (target is null) return; + target.drag_data_received (widget, context, cast(int)/*64*/x, cast(int)/*64*/y, data, cast(int)/*64*/info, cast(int)/*64*/time); +} + +private static extern(C) int Drag_Drop( + GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + uint time, + void* user_data) +{ + DropTarget target = FindDropTarget(widget); + if (target is null) return 0; + return target.drag_drop (widget, context, cast(int)/*64*/x, cast(int)/*64*/y, cast(int)/*64*/time) ? 1 : 0; +} + +private static extern(C) void Drag_Leave ( + GtkWidget *widget, + GdkDragContext *context, + uint time, + void* user_data) +{ + DropTarget target = FindDropTarget(widget); + if (target is null) return; + target.drag_leave (widget, context, cast(int)/*64*/time); +} + +private static extern(C) int Drag_Motion ( + GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + uint time, + void* user_data) +{ + DropTarget target = FindDropTarget(widget); + if (target is null) return 0; + return target.drag_motion (widget, context, cast(int)/*64*/x, cast(int)/*64*/y, cast(int)/*64*/time) ? 1 : 0; +} + +static DropTarget FindDropTarget(GtkWidget* handle) { + Display display = Display.findDisplay(Thread.getThis()); + if (display is null || display.isDisposed()) return null; + Widget widget = display.findWidget(handle); + if (widget is null) return null; + return cast(DropTarget)widget.getData(DROPTARGETID); +} + +/** + * 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 DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see DropTargetListener + * @see #removeDropListener + * @see DropTargetEvent + */ +public void addDropListener(DropTargetListener listener) { + if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT); + DNDListener typedListener = new DNDListener (listener); + typedListener.dndWidget = this; + addListener (DND.DragEnter, typedListener); + addListener (DND.DragLeave, typedListener); + addListener (DND.DragOver, typedListener); + addListener (DND.DragOperationChanged, typedListener); + addListener (DND.Drop, typedListener); + addListener (DND.DropAccept, typedListener); +} + +protected void checkSubclass () { + char[] name = this.classinfo.name; + char[] validName = DropTarget.stringof; + if ( validName !=/*eq*/ name ) { + DND.error (DWT.ERROR_INVALID_SUBCLASS); + } +} + +void drag_data_received ( + GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + GtkSelectionData *data, + uint info, + uint time ) +{ + DNDEvent event = new DNDEvent(); + if (data is null || !setEventData(context, x, y, time, event)) { + keyOperation = -1; + return; + } + keyOperation = -1; + + int allowedOperations = event.operations; + + // Get data in a Java format + Object object = null; + TransferData transferData = new TransferData(); + if (data.data !is null) { + transferData.type = data.type; + transferData.length = data.length; + transferData.pValue = data.data; + transferData.format = data.format; + for (int i = 0; i < transferAgents.length; i++) { + Transfer transfer = transferAgents[i]; + if (transfer !is null && transfer.isSupportedType(transferData)) { + object = transfer.nativeToJava(transferData); + break; + } + } + } + if (object is null) { + selectedOperation = DND.DROP_NONE; + } + + event.detail = selectedOperation; + event.dataType = transferData; + event.data = object; + selectedOperation = DND.DROP_NONE; + notifyListeners(DND.Drop, event); + if ((allowedOperations & event.detail) is event.detail) { + selectedOperation = event.detail; + } + //stop native handler + OS.g_signal_stop_emission_by_name(widget, OS.drag_data_received.ptr); + + //notify source of action taken + OS.gtk_drag_finish(context, selectedOperation !is DND.DROP_NONE, selectedOperation is DND.DROP_MOVE, time); + return; +} + +bool drag_drop( + GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + uint time) +{ + DNDEvent event = new DNDEvent(); + if (!setEventData(context, x, y, time, event)) { + keyOperation = -1; + return 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; + selectedDataType = null; + selectedOperation = DND.DROP_NONE; + notifyListeners(DND.DropAccept,event); + if (event.dataType !is null) { + for (int i = 0; i < allowedDataTypes.length; i++) { + if (allowedDataTypes[i].type is event.dataType.type) { + selectedDataType = allowedDataTypes[i]; + break; + } + } + } + if (selectedDataType !is null && ((event.detail & allowedOperations) is event.detail)) { + selectedOperation = event.detail; + } + if (selectedOperation is DND.DROP_NONE) { + // this was not a successful drop + return false; + } + // ask drag source for dropped data + OS.gtk_drag_get_data(widget, context, selectedDataType.type, time); + return true; +} + +void drag_leave( + GtkWidget *widget, + GdkDragContext *context, + uint time ) +{ + updateDragOverHover(0, null); + + if (keyOperation is -1) return; + keyOperation = -1; + + DNDEvent event = new DNDEvent(); + event.widget = this; + event.time = time; + event.detail = DND.DROP_NONE; + notifyListeners(DND.DragLeave, event); +} + +bool drag_motion ( + GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + uint time) +{ + int oldKeyOperation = keyOperation; + + if (oldKeyOperation is -1) { //drag enter + selectedDataType = null; + selectedOperation = DND.DROP_NONE; + } + + DNDEvent event = new DNDEvent(); + if (!setEventData(context, x, y, time, event)) { + keyOperation = -1; + OS.gdk_drag_status(context, 0, time); + return false; + } + + int allowedOperations = event.operations; + TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length]; + System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length); + + if (oldKeyOperation is -1) { + event.type = DND.DragEnter; + } else { + if (keyOperation is oldKeyOperation) { + event.type = DND.DragOver; + event.dataType = selectedDataType; + event.detail = selectedOperation; + } else { + event.type = DND.DragOperationChanged; + event.dataType = selectedDataType; + } + } + updateDragOverHover(DRAGOVER_HYSTERESIS, event); + selectedDataType = null; + selectedOperation = DND.DROP_NONE; + notifyListeners(event.type, event); + if (event.detail is DND.DROP_DEFAULT) { + event.detail = (allowedOperations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE; + } + if (event.dataType !is null) { + for (int i = 0; i < allowedDataTypes.length; i++) { + if (allowedDataTypes[i].type is event.dataType.type) { + selectedDataType = allowedDataTypes[i]; + break; + } + } + } + if (selectedDataType !is null && (allowedOperations & event.detail) !is 0) { + selectedOperation = event.detail; + } + + switch (selectedOperation) { + case DND.DROP_NONE: + OS.gdk_drag_status(context, 0, time); + break; + case DND.DROP_COPY: + OS.gdk_drag_status(context, OS.GDK_ACTION_COPY, time); + break; + case DND.DROP_MOVE: + OS.gdk_drag_status(context, OS.GDK_ACTION_MOVE, time); + break; + case DND.DROP_LINK: + OS.gdk_drag_status(context, OS.GDK_ACTION_LINK, time); + break; + } + + if (oldKeyOperation is -1) { + dragOverHeartbeat.run(); + } + return true; +} + +/** + * Returns the Control which is registered for this DropTarget. This is the control over which the + * user positions the cursor to drop the data. + * + * @return the Control which is registered for this DropTarget + */ +public Control getControl () { + return control; +} + +/** + * Returns the drop effect for this DropTarget. This drop effect will be + * used during a drag and drop to display the drag under effect on the + * target widget. + * + * @return the drop effect that is registered for this DropTarget + * + * @since 3.3 + */ +public DropTargetEffect getDropTargetEffect() { + return dropEffect; +} + +int getOperationFromKeyState() { + int state; + OS.gdk_window_get_pointer(null, null, null, &state); + bool ctrl = (state & OS.GDK_CONTROL_MASK) !is 0; + bool shift = (state & OS.GDK_SHIFT_MASK) !is 0; + 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 is null) return; + OS.g_signal_handler_disconnect(control.handle, drag_motion_handler); + OS.g_signal_handler_disconnect(control.handle, drag_leave_handler); + OS.g_signal_handler_disconnect(control.handle, drag_data_received_handler); + OS.g_signal_handler_disconnect(control.handle, drag_drop_handler); + if (transferAgents.length !is 0) + OS.gtk_drag_dest_unset(control.handle); + transferAgents = null; + if (controlListener !is null) + control.removeListener(DWT.Dispose, controlListener); + control.setData(DROPTARGETID, null); + control = null; + controlListener = null; +} + +int opToOsOp(int operation){ + int osOperation = 0; + if ((operation & DND.DROP_COPY) is DND.DROP_COPY) + osOperation |= OS.GDK_ACTION_COPY; + if ((operation & DND.DROP_MOVE) is DND.DROP_MOVE) + osOperation |= OS.GDK_ACTION_MOVE; + if ((operation & DND.DROP_LINK) is DND.DROP_LINK) + osOperation |= OS.GDK_ACTION_LINK; + return osOperation; +} + +int osOpToOp(int osOperation){ + int operation = DND.DROP_NONE; + if ((osOperation & OS.GDK_ACTION_COPY) is OS.GDK_ACTION_COPY) + operation |= DND.DROP_COPY; + if ((osOperation & OS.GDK_ACTION_MOVE) is OS.GDK_ACTION_MOVE) + operation |= DND.DROP_MOVE; + if ((osOperation & OS.GDK_ACTION_LINK) is OS.GDK_ACTION_LINK) + operation |= DND.DROP_LINK; + return operation; +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when a drag and drop operation is in progress. + * + * @param listener the listener which should be notified + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see DropTargetListener + * @see #addDropListener + */ +public void removeDropListener(DropTargetListener listener) { + if (listener is null) DND.error (DWT.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 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 is null) DND.error(DWT.ERROR_NULL_ARGUMENT); + + if (this.transferAgents.length !is 0) { + OS.gtk_drag_dest_unset(control.handle); + } + this.transferAgents = transferAgents; + + GtkTargetEntry*[] targets; + for (int i = 0; i < transferAgents.length; i++) { + Transfer transfer = transferAgents[i]; + if (transfer !is null) { + int[] typeIds = transfer.getTypeIds(); + char[][] typeNames = transfer.getTypeNames(); + for (int j = 0; j < typeIds.length; j++) { + GtkTargetEntry* entry = new GtkTargetEntry(); + entry.target = cast(char*)OS.g_malloc(typeNames[j].length +1); + entry.target[ 0 .. typeNames[j].length ] = typeNames[j]; + entry.target[ typeNames[j].length ] = '\0'; + entry.info = typeIds[j]; + GtkTargetEntry*[] newTargets = new GtkTargetEntry*[targets.length + 1]; + SimpleType!(GtkTargetEntry*).arraycopy(targets, 0, newTargets, 0, targets.length); + newTargets[targets.length] = entry; + targets = newTargets; + } + } + } + + auto pTargets = OS.g_malloc(targets.length * GtkTargetEntry.sizeof); + for (int i = 0; i < targets.length; i++) { + tango.stdc.string.memmove(pTargets + i*GtkTargetEntry.sizeof, targets[i], GtkTargetEntry.sizeof); + } + + int actions = opToOsOp(getStyle()); + OS.gtk_drag_dest_set(control.handle, 0, pTargets, targets.length, actions); + + for (int i = 0; i < targets.length; i++) { + OS.g_free(targets[i].target); + } +} + +/** + * 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; +} + +bool setEventData(GdkDragContext* dragContext, int x, int y, int time, DNDEvent event) { + if (dragContext is null) return false; + if (dragContext.targets is null) return false; + + // get allowed operations + int style = getStyle(); + int operations = osOpToOp(dragContext.actions) & style; + if (operations is DND.DROP_NONE) return false; + + // get current operation + int operation = getOperationFromKeyState(); + keyOperation = operation; + if (operation is DND.DROP_DEFAULT) { + if ((style & DND.DROP_DEFAULT) is 0) { + operation = (operations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE; + } + } else { + if ((operation & operations) is 0) operation = DND.DROP_NONE; + } + + // Get allowed transfer types + int length = OS.g_list_length(dragContext.targets); + TransferData[] dataTypes = new TransferData[0]; + for (int i = 0; i < length; i++) { + auto pData = OS.g_list_nth(dragContext.targets, i); + GtkTargetPair* gtkTargetPair = cast(GtkTargetPair*)pData; + TransferData data = new TransferData(); + data.type = gtkTargetPair.target; + for (int j = 0; j < transferAgents.length; j++) { + Transfer transfer = transferAgents[j]; + if (transfer !is null && transfer.isSupportedType(data)) { + TransferData[] newDataTypes = new TransferData[dataTypes.length + 1]; + System.arraycopy(dataTypes, 0, newDataTypes, 0, dataTypes.length); + newDataTypes[dataTypes.length] = data; + dataTypes = newDataTypes; + break; + } + } + } + if (dataTypes.length is 0) return false; + + auto window = OS.GTK_WIDGET_WINDOW(control.handle); + int origin_x, origin_y; + OS.gdk_window_get_origin(window, &origin_x, &origin_y); + Point coordinates = new Point(origin_x + x, origin_y + y); + + event.widget = this; + event.x = coordinates.x; + event.y = coordinates.y; + event.time = time; + event.feedback = DND.FEEDBACK_SELECT; + event.dataTypes = dataTypes; + event.dataType = dataTypes[0]; + event.operations = operations; + event.detail = operation; + if (dropEffect !is null) { + event.item = dropEffect.getItem(coordinates.x, coordinates.y); + } + return true; +} + +void updateDragOverHover(long delay, DNDEvent event) { + if (delay is 0) { + dragOverStart = 0; + dragOverEvent = null; + return; + } + dragOverStart = System.currentTimeMillis() + delay; + if (dragOverEvent is null) dragOverEvent = new DNDEvent(); + dragOverEvent.x = event.x; + dragOverEvent.y = event.y; + TransferData[] dataTypes = new TransferData[ event.dataTypes.length]; + System.arraycopy( event.dataTypes, 0, dataTypes, 0, dataTypes.length); + dragOverEvent.dataTypes = dataTypes; + dragOverEvent.operations = event.operations; + dragOverEvent.time = event.time; +} + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DropTargetAdapter.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 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 + *******************************************************************************/ +module dwt.dnd.DropTargetAdapter; + +import dwt.dnd.DropTargetListener; +import dwt.dnd.DropTargetEvent; + +/** + * This adapter class provides default implementations for the + * methods described by the <code>DropTargetListener</code> interface. + * <p> + * Classes that wish to deal with <code>DropTargetEvent</code>s can + * extend this class and override only the methods which they are + * interested in. + * </p> + * + * @see DropTargetListener + * @see DropTargetEvent + */ +public class DropTargetAdapter : DropTargetListener { + +/** + * This implementation of <code>dragEnter</code> permits the default + * operation defined in <code>event.detail</code>to be performed on the current data type + * defined in <code>event.currentDataType</code>. + * For additional information see <code>DropTargetListener.dragEnter</code>. + */ +public void dragEnter(DropTargetEvent event){} +/** + * This implementation of <code>dragLeave</code> does nothing. + * For additional information see <code>DropTargetListener.dragOperationChanged</code>. + */ +public void dragLeave(DropTargetEvent event){} +/** + * This implementation of <code>dragOperationChanged</code> permits the default + * operation defined in <code>event.detail</code>to be performed on the current data type + * defined in <code>event.currentDataType</code>. + * For additional information see <code>DropTargetListener.dragOperationChanged</code>. + */ +public void dragOperationChanged(DropTargetEvent event){} +/** + * This implementation of <code>dragOver</code> permits the default + * operation defined in <code>event.detail</code>to be performed on the current data type + * defined in <code>event.currentDataType</code>. + * For additional information see <code>DropTargetListener.dragOver</code>. + */ +public void dragOver(DropTargetEvent event){} +/** + * This implementation of <code>drop</code> does nothing. + * For additional information see <code>DropTargetListener.drop</code>. + */ +public void drop(DropTargetEvent event){} +/** + * This implementation of <code>dropAccept</code> permits the default + * operation defined in <code>event.detail</code>to be performed on the current data type + * defined in <code>event.currentDataType</code>. + * For additional information see <code>DropTargetListener.dropAccept</code>. + */ +public void dropAccept(DropTargetEvent event){} + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DropTargetEffect.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.DropTargetEffect; + + +import dwt.DWT; +import dwt.graphics.Point; +import dwt.graphics.Rectangle; +import dwt.widgets.Control; +import dwt.widgets.Item; +import dwt.widgets.Table; +import dwt.widgets.Tree; +import dwt.widgets.TreeItem; +import dwt.widgets.Widget; +import dwt.dnd.DropTargetAdapter; + + +/** + * This class provides a default drag under effect during a drag and drop. + * The current implementation does not provide any visual feedback. + * + * <p>The drop target effect has the same API as the + * <code>DropTargetAdapter</code> so that it can provide custom visual + * feedback when a <code>DropTargetEvent</code> occurs. + * </p> + * + * <p>Classes that wish to provide their own drag under effect + * can extend the <code>DropTargetEffect</code> and override any applicable methods + * in <code>DropTargetAdapter</code> to display their own drag under effect.</p> + * + * <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_EXPAND, FEEDBACK_INSERT_AFTER, FEEDBACK_INSERT_BEFORE, + * FEEDBACK_NONE, FEEDBACK_SELECT, FEEDBACK_SCROLL</dd> + * </dl> + * </p> + * + * @see DropTargetAdapter + * @see DropTargetEvent + * + * @since 3.3 + */ +public class DropTargetEffect : DropTargetAdapter { + Control control; + + /** + * Creates a new <code>DropTargetEffect</code> to handle the drag under effect on the specified + * <code>Control</code>. + * + * @param control the <code>Control</code> over which the user positions the cursor to drop the data + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the control is null</li> + * </ul> + */ + public this(Control control) { + if (control is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + this.control = control; + } + + /** + * Returns the Control which is registered for this DropTargetEffect. This is the control over which the + * user positions the cursor to drop the data. + * + * @return the Control which is registered for this DropTargetEffect + */ + public Control getControl() { + return control; + } + + /** + * Returns the item at the given x-y coordinate in the receiver + * or null if no such item exists. The x-y coordinate is in the + * display relative coordinates. + * + * @param x the x coordinate used to locate the item + * @param y the y coordinate used to locate the item + * @return the item at the given x-y coordinate, or null if the coordinate is not in a selectable item + */ + public Widget getItem(int x, int y) { + if ( auto table = cast(Table)control ) { + return getItem(table, x, y); + } + if ( auto tree = cast(Tree)control ) { + return getItem(tree, x, y); + } + return null; + } + + Widget getItem(Table table, int x, int y) { + Point coordinates = new Point(x, y); + coordinates = table.toControl(coordinates); + Item item = table.getItem(coordinates); + if (item is null) { + Rectangle area = table.getClientArea(); + if (area.contains(coordinates)) { + // Scan across the width of the table. + for (int x1 = area.x; x1 < area.x + area.width; x1++) { + Point pt = new Point(x1, coordinates.y); + item = table.getItem(pt); + if (item !is null) { + break; + } + } + } + } + return item; + } + + Widget getItem(Tree tree, int x, int y) { + Point coordinates = new Point(x, y); + coordinates = tree.toControl(coordinates); + Item item = tree.getItem(coordinates); + if (item is null) { + Rectangle area = tree.getClientArea(); + if (area.contains(coordinates)) { + // Scan across the width of the tree. + for (int x1 = area.x; x1 < area.x + area.width; x1++) { + Point pt = new Point(x1, coordinates.y); + item = tree.getItem(pt); + if (item !is null) { + break; + } + } + } + } + return item; + } + + TreeItem nextItem(Tree tree, TreeItem item) { + if (item is null) return null; + if (item.getExpanded()) return item.getItem(0); + TreeItem childItem = item; + TreeItem parentItem = childItem.getParentItem(); + int index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem); + int count = parentItem is null ? tree.getItemCount() : parentItem.getItemCount(); + while (true) { + if (index + 1 < count) return parentItem is null ? tree.getItem(index + 1) : parentItem.getItem(index + 1); + if (parentItem is null) return null; + childItem = parentItem; + parentItem = childItem.getParentItem(); + index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem); + count = parentItem is null ? tree.getItemCount() : parentItem.getItemCount(); + } + } + + TreeItem previousItem(Tree tree, TreeItem item) { + if (item is null) return null; + TreeItem childItem = item; + TreeItem parentItem = childItem.getParentItem(); + int index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem); + if (index is 0) return parentItem; + TreeItem nextItem = parentItem is null ? tree.getItem(index-1) : parentItem.getItem(index-1); + int count = nextItem.getItemCount(); + while (count > 0 && nextItem.getExpanded()) { + nextItem = nextItem.getItem(count - 1); + count = nextItem.getItemCount(); + } + return nextItem; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DropTargetEvent.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,119 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.DropTargetEvent; + + +import dwt.events.TypedEvent; +import dwt.widgets.Widget; +import dwt.dnd.TransferData; +import dwt.dnd.DNDEvent; +import dwt.widgets.Event; + +/** + * The DropTargetEvent contains the event information passed in the methods of the DropTargetListener. + */ +public class DropTargetEvent : TypedEvent { + /** + * The x-cordinate of the cursor relative to the <code>Display</code> + */ + public int x; + + /** + * The y-cordinate of the cursor relative to the <code>Display</code> + */ + public int y; + + /** + * The operation being performed. + * @see DND#DROP_NONE + * @see DND#DROP_MOVE + * @see DND#DROP_COPY + * @see DND#DROP_LINK + */ + public int detail; + + /** + * A bitwise OR'ing of the operations that the DragSource can support + * (e.g. DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK). + * The detail value must be a member of this list or DND.DROP_NONE. + * @see DND#DROP_NONE + * @see DND#DROP_MOVE + * @see DND#DROP_COPY + * @see DND#DROP_LINK + */ + public int operations; + + /** + * A bitwise OR'ing of the drag under effect feedback to be displayed to the user + * (e.g. DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL | DND.FEEDBACK_EXPAND). + * <p>A value of DND.FEEDBACK_NONE indicates that no drag under effect will be displayed.</p> + * <p>Feedback effects will only be applied if they are applicable.</p> + * <p>The default value is DND.FEEDBACK_SELECT.</p> + * @see DND#FEEDBACK_NONE + * @see DND#FEEDBACK_SELECT + * @see DND#FEEDBACK_INSERT_BEFORE + * @see DND#FEEDBACK_INSERT_AFTER + * @see DND#FEEDBACK_SCROLL + * @see DND#FEEDBACK_EXPAND + */ + public int feedback; + + /** + * If the associated control is a table or tree, this field contains the item located + * at the cursor coordinates. + */ + public Widget item; + + /** + * The type of data that will be dropped. + */ + public TransferData currentDataType; + + /** + * A list of the types of data that the DragSource is capable of providing. + * The currentDataType must be a member of this list. + */ + public TransferData[] dataTypes; + + static const long serialVersionUID = 3256727264573338678L; + +/** + * Constructs a new instance of this class based on the + * information in the given untyped event. + * + * @param e the untyped event containing the information + */ +public this(DNDEvent e) { + super(cast(Event)e); + this.data = e.data; + this.x = e.x; + this.y = e.y; + this.detail = e.detail; + this.currentDataType = e.dataType; + this.dataTypes = e.dataTypes; + this.operations = e.operations; + this.feedback = e.feedback; + this.item = e.item; +} +void updateEvent(DNDEvent e) { + e.widget = this.widget; + e.time = this.time; + e.data = this.data; + e.x = this.x; + e.y = this.y; + e.detail = this.detail; + e.dataType = this.currentDataType; + e.dataTypes = this.dataTypes; + e.operations = this.operations; + e.feedback = this.feedback; + e.item = this.item; +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/DropTargetListener.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,251 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 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 + *******************************************************************************/ +module dwt.dnd.DropTargetListener; + +import dwt.internal.DWTEventListener; +import dwt.dnd.DropTargetEvent; + +/** + * The <code>DropTargetListener</code> class provides event notification to the application + * for DropTarget events. + * + * <p>As the user moves the cursor into, over and out of a Control that has been designated + * as a DropTarget, events indicate what operation can be performed and what data can be + * transferred if a drop where to occur at that point. + * The application can respond to these events and change the type of data that will + * be dropped by modifying event.currentDataType, or change the operation that will be performed + * by modifying the event.detail field or stop any drop from happening on the current target + * by setting the event.detail field to DND_DROP_NONE.</p> + * + * <p>When the user causes a drop to happen by releasing the mouse over a valid drop target, + * the application has one last chance to change the data type of the drop through the + * DropAccept event. If the drop is still allowed, the DropAccept event is immediately + * followed by the Drop event. In the Drop event, the application can still change the + * operation that is performed but the data type is fixed.</p> + * + * @see DropTargetEvent + * + */ +public interface DropTargetListener : DWTEventListener { + +/** + * The cursor has entered the drop target boundaries. + * + * <p>The following fields in the DropTargetEvent apply: + * <ul> + * <li>(in)widget + * <li>(in)time + * <li>(in)x + * <li>(in)y + * <li>(in)dataTypes + * <li>(in,out)currentDataType + * <li>(in)operations + * <li>(in,out)detail + * <li>(in,out)feedback + * </ul></p> + * + * <p>The <code>operation</code> value is determined by the modifier keys pressed by the user. + * If no keys are pressed the <code>event.detail</code> field is set to DND.DROP_DEFAULT. + * If the application does not set the <code>event.detail</code> to something other + * than <code>DND.DROP_DEFAULT</code> the operation will be set to the platform defined standard + * default.</p> + * + * <p>The <code>currentDataType</code> is determined by the first transfer agent specified in + * setTransfer() that matches a data type provided by the drag source.</p> + * + * <p>It is possible to get a DragEnter event when the drag source does not provide any matching data. + * In this case, the default operation is DND.DROP_NONE and the currentDataType is null.</p> + * + * <p>The application can change the operation that will be performed by modifying the + * <code>detail</code> field but the choice must be one of the values in the <code>operations</code> + * field or DND.DROP_NONE.</p> + * + * <p>The application can also change the type of data being requested by + * modifying the <code>currentDataTypes</code> field but the value must be one of the values + * in the <code>dataTypes</code> list.</p> + * + * @param event the information associated with the drag enter event + * + * @see DropTargetEvent + */ +public void dragEnter(DropTargetEvent event); + +/** + * The cursor has left the drop target boundaries OR the drop has been cancelled OR the data + * is about to be dropped. + * + * <p>The following fields in the DropTargetEvent apply: + * <ul> + * <li>(in)widget + * <li>(in)time + * <li>(in)x + * <li>(in)y + * <li>(in)dataTypes + * <li>(in)currentDataType + * <li>(in)operations + * <li>(in)detail + * </ul></p> + * + * @param event the information associated with the drag leave event + * + * @see DropTargetEvent + */ +public void dragLeave(DropTargetEvent event); + +/** + * The operation being performed has changed (usually due to the user changing the selected modifier key(s) + * while dragging). + * + * <p>The following fields in the DropTargetEvent apply: + * <ul> + * <li>(in)widget + * <li>(in)time + * <li>(in)x + * <li>(in)y + * <li>(in)dataTypes + * <li>(in,out)currentDataType + * <li>(in)operations + * <li>(in,out)detail + * <li>(in,out)feedback + * </ul></p> + * + * <p>The <code>operation</code> value is determined by the modifier keys pressed by the user. + * If no keys are pressed the <code>event.detail</code> field is set to DND.DROP_DEFAULT. + * If the application does not set the <code>event.detail</code> to something other than + * <code>DND.DROP_DEFAULT</code> the operation will be set to the platform defined standard default.</p> + * + * <p>The <code>currentDataType</code> value is determined by the value assigned to + * <code>currentDataType</code> in previous dragEnter and dragOver calls.</p> + * + * <p>The application can change the operation that will be performed by modifying the + * <code>detail</code> field but the choice must be one of the values in the <code>operations</code> + * field.</p> + * + * <p>The application can also change the type of data being requested by modifying + * the <code>currentDataTypes</code> field but the value must be one of the values in the + * <code>dataTypes</code> list.</p> + * + * @param event the information associated with the drag operation changed event + * + * @see DropTargetEvent + */ +public void dragOperationChanged(DropTargetEvent event); + +/** + * The cursor is moving over the drop target. + * + * <p>The following fields in the DropTargetEvent apply: + * <ul> + * <li>(in)widget + * <li>(in)time + * <li>(in)x + * <li>(in)y + * <li>(in)dataTypes + * <li>(in,out)currentDataType + * <li>(in)operations + * <li>(in,out)detail + * <li>(in,out)feedback + * </ul></p> + * + * <p>The <code>operation</code> value is determined by the value assigned to + * <code>currentDataType</code> in previous dragEnter and dragOver calls.</p> + * + * <p>The <code>currentDataType</code> value is determined by the value assigned to + * <code>currentDataType</code> in previous dragEnter and dragOver calls.</p> + * + * <p>The application can change the operation that will be performed by modifying the + * <code>detail</code> field but the choice must be one of the values in the <code>operations</code> + * field.</p> + * + * <p>The application can also change the type of data being requested by modifying the + * <code>currentDataTypes</code> field but the value must be one of the values in the + * <code>dataTypes</code> list.</p> + * + * <p>NOTE: At this point the <code>data</code> field is null. On some platforms, it is possible + * to obtain the data being transferred before the transfer occurs but in most platforms this is + * not possible. On those platforms where the data is available, the application can access the + * data as follows:</p> + * + * <pre><code> + * public void dragOver(DropTargetEvent event) { + * TextTransfer textTransfer = TextTransfer.getInstance(); + * String data = (String)textTransfer.nativeToJava(event.currentDataType); + * if (data !is null) { + * System.out.println("Data to be dropped is (Text)"+data); + * } + * }; + * </code></pre> + * + * @param event the information associated with the drag over event + * + * @see DropTargetEvent + */ +public void dragOver(DropTargetEvent event); + +/** + * The data is being dropped. The data field contains java format of the data being dropped. + * To determine the type of the data object, refer to the documentation for the Transfer subclass + * specified in event.currentDataType. + * + * <p>The following fields in DropTargetEvent apply: + * <ul> + * <li>(in)widget + * <li>(in)time + * <li>(in)x + * <li>(in)y + * <li>(in,out)detail + * <li>(in)currentDataType + * <li>(in)data + * </ul></p> + * + * <p>The application can refuse to perform the drop operation by setting the detail + * field to DND.DROP_NONE.</p> + * + * @param event the information associated with the drop event + * + * @see DropTargetEvent + */ +public void drop(DropTargetEvent event); + +/** + * The drop is about to be performed. + * The drop target is given a last chance to change the nature of the drop. + * + * <p>The following fields in the DropTargetEvent apply: + * <ul> + * <li>(in)widget + * <li>(in)time + * <li>(in)x + * <li>(in)y + * <li>(in)dataTypes + * <li>(in,out)currentDataType + * <li>(in)operations + * <li>(in,out)detail + * </ul></p> + * + * <p>The application can veto the drop by setting the <code>event.detail</code> field to + * <code>DND.DROP_NONE</code>.</p> + * + * <p>The application can change the operation that will be performed by modifying the + * <code>detail</code> field but the choice must be one of the values in the + * <code>operations</code> field.</p> + * + * <p>The application can also change the type of data being requested by modifying the + * <code>currentDataTypes</code> field but the value must be one of the values in the < + * code>dataTypes</code> list.</p> + * + * @param event the information associated with the drop accept event + * + * @see DropTargetEvent + */ +public void dropAccept(DropTargetEvent event); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/FileTransfer.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.FileTransfer; + +import dwt.internal.gtk.OS; +import dwt.dnd.ByteArrayTransfer; +import dwt.dnd.TransferData; +import dwt.dnd.DND; +import dwt.dwthelper.utils; + +/** + * The class <code>FileTransfer</code> provides a platform specific mechanism + * for converting a list of files represented as a java <code>String[]</code> to a + * platform specific representation of the data and vice versa. + * Each <code>String</code> in the array contains the absolute path for a single + * file or directory. + * See <code>Transfer</code> for additional information. + * + * <p>An example of a java <code>String[]</code> containing a list of files is shown + * below:</p> + * + * <code><pre> + * File file1 = new File("C:\temp\file1"); + * File file2 = new File("C:\temp\file2"); + * String[] fileData = new String[2]; + * fileData[0] = file1.getAbsolutePath(); + * fileData[1] = file2.getAbsolutePath(); + * </code></pre> + */ +public class FileTransfer : ByteArrayTransfer { + + private static FileTransfer _instance; + private static const char[] URI_LIST = "text/uri-list"; //$NON-NLS-1$ + private static const int URI_LIST_ID; + private static const char[] separator = "\r\n"; + +static this(){ + URI_LIST_ID = registerType(URI_LIST); + _instance = new FileTransfer(); +} + +private this() {} + +/** + * Returns the singleton instance of the FileTransfer class. + * + * @return the singleton instance of the FileTransfer class + */ +public static FileTransfer getInstance () { + return _instance; +} + +/** + * This implementation of <code>javaToNative</code> converts a list of file names + * represented by a java <code>String[]</code> to a platform specific representation. + * Each <code>String</code> in the array contains the absolute path for a single + * file or directory. For additional information see + * <code>Transfer#javaToNative</code>. + * + * @param object a java <code>String[]</code> containing the file names to be + * converted + * @param transferData an empty <code>TransferData</code> object; this + * object will be filled in on return with the platform specific format of the data + */ +public void javaToNative(Object object, TransferData transferData) { + transferData.result = 0; + if (!checkFile(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + char[][] files = (cast(ArrayWrapperString2)object).array; + char[] buffer; + for (int i = 0; i < files.length; i++) { + char[] string = files[i]; + if (string.ptr is null) continue; + if (string.length is 0) continue; + GError* error; + auto localePtr = OS.g_locale_from_utf8(string.ptr, -1, null, null, &error); + if (error !is null || localePtr is null) continue; + auto uriPtr = OS.g_filename_to_uri(localePtr, null, &error); + OS.g_free(localePtr); + if (error !is null || uriPtr is null) continue; + char[] temp = tango.stdc.stringz.fromUtf8z( uriPtr ).dup; + OS.g_free(uriPtr); + int newLength = (i > 0) ? buffer.length+separator.length+temp.length : temp.length; + char[] newBuffer = new char[newLength]; + int offset = 0; + if (i > 0) { + System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + offset += buffer.length; + System.arraycopy(separator, 0, newBuffer, offset, separator.length); + offset += separator.length; + } + System.arraycopy(temp, 0, newBuffer, offset, temp.length); + buffer = newBuffer; + } + if (buffer.length is 0) return; + char* ptr = cast(char*)OS.g_malloc(buffer.length+1); + ptr[ 0 .. buffer.length ] = buffer; + ptr[ buffer.length ] = '\0'; + transferData.pValue = ptr; + transferData.length = buffer.length; + transferData.format = 8; + transferData.result = 1; +} +/** + * This implementation of <code>nativeToJava</code> converts a platform specific + * representation of a list of file names to a java <code>String[]</code>. + * Each String in the array contains the absolute path for a single file or directory. + * For additional information see <code>Transfer#nativeToJava</code>. + * + * @param transferData the platform specific representation of the data to be + * been converted + * @return a java <code>String[]</code> containing a list of file names if the + * conversion was successful; otherwise null + */ +public Object nativeToJava(TransferData transferData) { + if ( !isSupportedType(transferData) || transferData.pValue is null || transferData.length <= 0 ) return null; + char[] temp = transferData.pValue[ 0 .. transferData.length ]; + char*[] files; + int offset = 0; + for (int i = 0; i < temp.length - 1; i++) { + if (temp[i] is '\r' && temp[i+1] is '\n') { + int size = i - offset; + char* file = cast(char*)OS.g_malloc(size + 1); + char[] fileBuffer = new char[size + 1]; + System.arraycopy(temp, offset, fileBuffer, 0, size); + file[ 0 .. size + 1 ] = fileBuffer; + char*[] newFiles = new char*[files.length + 1]; + SimpleType!(char*).arraycopy(files, 0, newFiles, 0, files.length); + newFiles[files.length] = file; + files = newFiles; + offset = i + 2; + } + } + if (offset < temp.length - 2) { + int size = temp.length - offset; + char* file = cast(char*)OS.g_malloc(size + 1); + char[] fileBuffer = new char[size + 1]; + System.arraycopy(temp, offset, fileBuffer, 0, size); + file[ 0 .. size+1 ] = fileBuffer; + char*[] newFiles = new char*[files.length + 1]; + SimpleType!(char*).arraycopy(files, 0, newFiles, 0, files.length); + newFiles[files.length] = file; + files = newFiles; + } + char[][] fileNames; + for (int i = 0; i < files.length; i++) { + GError* error; + auto localePtr = OS.g_filename_from_uri(files[i], null, &error); + OS.g_free(files[i]); + if (error !is null || localePtr is null) continue; + auto utf8Ptr = OS.g_locale_to_utf8(localePtr, -1, null, null, &error); + OS.g_free(localePtr); + if (error !is null || utf8Ptr is null) continue; + char[] buffer = tango.stdc.stringz.fromUtf8z( utf8Ptr ).dup; + OS.g_free(utf8Ptr); + char[] name = buffer; + char[][] newFileNames = new char[][]( fileNames.length + 1 ); + System.arraycopy(fileNames, 0, newFileNames, 0, fileNames.length); + newFileNames[fileNames.length] = name; + fileNames = newFileNames; + } + if (fileNames.length is 0) return null; + return new ArrayWrapperString2( fileNames ); +} + +protected int[] getTypeIds(){ + return [URI_LIST_ID]; +} + +protected char[][] getTypeNames(){ + return [URI_LIST]; +} + +bool checkFile(Object object) { + if( object is null ) return false; + ArrayWrapperString2 arr = cast(ArrayWrapperString2)object; + if( arr is null ) return false; + if( arr.array.length is 0 ) return false; + + char[][] strings = arr.array; + for (int i = 0; i < strings.length; i++) { + if (strings[i] is null || strings[i].length is 0) return false; + } + return true; +} + +protected bool validate(Object object) { + return checkFile(object); +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/HTMLTransfer.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.HTMLTransfer; + +import dwt.internal.gtk.OS; +import dwt.dnd.ByteArrayTransfer; +import dwt.dnd.TransferData; +import dwt.dnd.DND; +import dwt.dwthelper.utils; + +static import tango.text.Util; + +/** + * The class <code>HTMLTransfer</code> provides a platform specific mechanism + * for converting text in HTML format represented as a java <code>String</code> + * to a platform specific representation of the data and vice versa. See + * <code>Transfer</code> for additional information. + * + * <p>An example of a java <code>String</code> containing HTML text is shown + * below:</p> + * + * <code><pre> + * String htmlData = "<p>This is a paragraph of text.</p>"; + * </code></pre> + */ +public class HTMLTransfer : ByteArrayTransfer { + + private static HTMLTransfer _instance; + private static const char[] TEXT_HTML = "text/html"; //$NON-NLS-1$ + private static const int TEXT_HTML_ID; + private static const char[] TEXT_HTML2 = "TEXT/HTML"; //$NON-NLS-1$ + private static const int TEXT_HTML2_ID; + +static this(){ + _instance = new HTMLTransfer(); + TEXT_HTML_ID = registerType(TEXT_HTML); + TEXT_HTML2_ID = registerType(TEXT_HTML2); +} + +private this() {} + +/** + * Returns the singleton instance of the HTMLTransfer class. + * + * @return the singleton instance of the HTMLTransfer class + */ +public static HTMLTransfer getInstance () { + return _instance; +} + +/** + * This implementation of <code>javaToNative</code> converts HTML-formatted text + * represented by a java <code>String</code> to a platform specific representation. + * For additional information see <code>Transfer#javaToNative</code>. + * + * @param object a java <code>String</code> containing HTML text + * @param transferData an empty <code>TransferData</code> object; this + * object will be filled in on return with the platform specific format of the data + */ +public void javaToNative (Object object, TransferData transferData){ + transferData.result = 0; + if (!checkHTML(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + char[] string = (cast(ArrayWrapperString)object).array; + char* pValue = cast(char*)OS.g_malloc(string.length); + if (pValue is null) return; + pValue[0 .. string.length ] = string; + transferData.length = string.length; + transferData.format = 8; + transferData.pValue = pValue; + transferData.result = 1; +} + +/** + * This implementation of <code>nativeToJava</code> converts a platform specific + * representation of HTML text to a java <code>String</code>. + * For additional information see <code>Transfer#nativeToJava</code>. + * + * @param transferData the platform specific representation of the data to be + * been converted + * @return a java <code>String</code> containing HTML text if the + * conversion was successful; otherwise null + */ +public Object nativeToJava(TransferData transferData){ + if ( !isSupportedType(transferData) || transferData.pValue is null ) return null; + /* Ensure byteCount is a multiple of 2 bytes */ + int size = (transferData.format * transferData.length / 8) / 2 * 2; + if (size <= 0) return null; + char[] chars = transferData.pValue[ 0 .. size ].dup; + return new ArrayWrapperString( chars[ 0 .. tango.text.Util.locate( chars, '\0' ) ] ); +} +protected int[] getTypeIds() { + return [TEXT_HTML_ID, TEXT_HTML2_ID]; +} + +protected char[][] getTypeNames() { + return [TEXT_HTML, TEXT_HTML2]; +} + +bool checkHTML(Object object) { + if( object is null ) return false; + auto arr = cast(ArrayWrapperString)object; + if( arr is null ) return false; + if( arr.array.length is 0 ) return false; + return true; +} + +protected bool validate(Object object) { + return checkHTML(object); +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/RTFTransfer.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.RTFTransfer; + +import dwt.internal.Converter; +import dwt.internal.gtk.OS; +import dwt.dnd.ByteArrayTransfer; +import dwt.dnd.TransferData; +import dwt.dnd.DND; + +import dwt.dwthelper.utils; +static import tango.text.Util; + +/** + * The class <code>RTFTransfer</code> provides a platform specific mechanism + * for converting text in RTF format represented as a java <code>String</code> + * to a platform specific representation of the data and vice versa. See + * <code>Transfer</code> for additional information. + * + * <p>An example of a java <code>String</code> containing RTF text is shown + * below:</p> + * + * <code><pre> + * String rtfData = "{\\rtf1{\\colortbl;\\red255\\green0\\blue0;}\\uc1\\b\\i Hello World}"; + * </code></pre> + */ +public class RTFTransfer : ByteArrayTransfer { + + private static RTFTransfer _instance; + private static const char[] TEXT_RTF = "text/rtf"; //$NON-NLS-1$ + private static const int TEXT_RTF_ID; + private static const char[] TEXT_RTF2 = "TEXT/RTF"; //$NON-NLS-1$ + private static const int TEXT_RTF2_ID; + private static const char[] APPLICATION_RTF = "application/rtf"; //$NON-NLS-1$ + private static const int APPLICATION_RTF_ID; + +static this(){ + TEXT_RTF_ID = registerType(TEXT_RTF); + TEXT_RTF2_ID = registerType(TEXT_RTF2); + APPLICATION_RTF_ID = registerType(APPLICATION_RTF); + _instance = new RTFTransfer(); +} + +private this() {} + +/** + * Returns the singleton instance of the RTFTransfer class. + * + * @return the singleton instance of the RTFTransfer class + */ +public static RTFTransfer getInstance () { + return _instance; +} + +/** + * This implementation of <code>javaToNative</code> converts RTF-formatted text + * represented by a java <code>String</code> to a platform specific representation. + * For additional information see <code>Transfer#javaToNative</code>. + * + * @param object a java <code>String</code> containing RTF text + * @param transferData an empty <code>TransferData</code> object; this + * object will be filled in on return with the platform specific format of the data + */ +public void javaToNative (Object object, TransferData transferData){ + transferData.result = 0; + if (!checkRTF(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + char[] string = (cast(ArrayWrapperString)object).array; + char* pValue = cast(char*)OS.g_malloc(string.length + 1); + if (pValue is null) return; + pValue[ 0 .. string.length ] = string; + pValue[ string.length ] = '\0'; + transferData.length = string.length; + transferData.format = 8; + transferData.pValue = pValue; + transferData.result = 1; +} + +/** + * This implementation of <code>nativeToJava</code> converts a platform specific + * representation of RTF text to a java <code>String</code>. + * For additional information see <code>Transfer#nativeToJava</code>. + * + * @param transferData the platform specific representation of the data to be + * been converted + * @return a java <code>String</code> containing RTF text if the + * conversion was successful; otherwise null + */ +public Object nativeToJava(TransferData transferData){ + if ( !isSupportedType(transferData) || transferData.pValue is null ) return null; + int size = transferData.format * transferData.length / 8; + if (size is 0) return null; + byte[] buffer = new byte[size]; + char [] chars = transferData.pValue[ 0 .. size]; + return new ArrayWrapperString( chars[ 0 .. tango.text.Util.locate( chars, '\0' ) ] ); +} + +protected int[] getTypeIds() { + return [TEXT_RTF_ID, TEXT_RTF2_ID, APPLICATION_RTF_ID]; +} + +protected char[][] getTypeNames() { + return [TEXT_RTF, TEXT_RTF2, APPLICATION_RTF]; +} + +bool checkRTF(Object object) { + if( object is null ) return false; + ArrayWrapperString astr = cast(ArrayWrapperString)object; + if( astr is null ) return false; + return astr.array.length > 0; +} + +protected bool validate(Object object) { + return checkRTF(object); +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/TableDragSourceEffect.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,146 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.TableDragSourceEffect; + + +import dwt.DWT; +import dwt.graphics.Image; +import dwt.internal.gtk.OS; +import dwt.widgets.Display; +import dwt.widgets.Table; +import dwt.dnd.DragSourceEffect; +import dwt.dnd.DragSourceEvent; + +import Math = tango.math.Math; + +/** + * This class provides default implementations to display a source image + * when a drag is initiated from a <code>Table</code>. + * + * <p>Classes that wish to provide their own source image for a <code>Table</code> can + * extend the <code>TableDragSourceEffect</code> class, override the + * <code>TableDragSourceEffect.dragStart</code> method and set the field + * <code>DragSourceEvent.image</code> with their own image.</p> + * + * Subclasses that override any methods of this class must call the corresponding + * <code>super</code> method to get the default drag source effect implementation. + * + * @see DragSourceEffect + * @see DragSourceEvent + * + * @since 3.3 + */ +public class TableDragSourceEffect : 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 this(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 !is 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 !is null) dragSourceImage.dispose(); + dragSourceImage = null; + + Table table = cast(Table) control; + if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) return null; + /* + * Bug in GTK. gtk_tree_selection_get_selected_rows() segmentation faults + * in versions smaller than 2.2.4 if the model is NULL. The fix is + * to give a valid pointer instead. + */ + auto handle = table.handle; + auto selection = OS.gtk_tree_view_get_selection (handle); + int dummy; + void* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null; + auto list = OS.gtk_tree_selection_get_selected_rows (selection, &model); + if (list is null) return null; + int count = Math.min(10, OS.g_list_length (list)); + + Display display = table.getDisplay(); + if (count is 1) { + auto path = OS.g_list_nth_data (list, 0); + auto pixmap = OS.gtk_tree_view_create_row_drag_icon(handle, path); + dragSourceImage = Image.gtk_new(display, DWT.ICON, pixmap, null); + } else { + int width = 0, height = 0; + int w, h; + int[] yy, hh; yy.length = count; hh.length = count; + GdkDrawable*[] pixmaps; pixmaps.length = count; + GdkRectangle rect; + for (int i=0; i<count; i++) { + auto path = OS.g_list_nth_data (list, i); + OS.gtk_tree_view_get_cell_area (handle, path, null, &rect); + pixmaps[i] = OS.gtk_tree_view_create_row_drag_icon(handle, path); + OS.gdk_drawable_get_size(pixmaps[i], &w, &h); + width = Math.max(width, w); + height = rect.y + h - yy[0]; + yy[i] = rect.y; + hh[i] = h; + } + auto source = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, -1); + auto gcSource = OS.gdk_gc_new(source); + auto mask = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, 1); + auto gcMask = OS.gdk_gc_new(mask); + GdkColor color; + color.pixel = 0; + OS.gdk_gc_set_foreground(gcMask, &color); + OS.gdk_draw_rectangle(mask, gcMask, 1, 0, 0, width, height); + color.pixel = 1; + OS.gdk_gc_set_foreground(gcMask, &color); + for (int i=0; i<count; i++) { + OS.gdk_draw_drawable(source, gcSource, pixmaps[i], 0, 0, 0, yy[i] - yy[0], -1, -1); + OS.gdk_draw_rectangle(mask, gcMask, 1, 0, yy[i] - yy[0], width, hh[i]); + OS.g_object_unref(pixmaps[i]); + } + OS.g_object_unref(gcSource); + OS.g_object_unref(gcMask); + dragSourceImage = Image.gtk_new(display, DWT.ICON, source, mask); + } + OS.g_list_free (list); + + return dragSourceImage; +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/TableDropTargetEffect.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,189 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.TableDropTargetEffect; + + +import dwt.graphics.Point; +import dwt.internal.gtk.OS; +import dwt.widgets.Table; +import dwt.dnd.DropTargetEffect; +import dwt.dnd.DropTargetEvent; +import dwt.dnd.DND; + +import dwt.dwthelper.System; + +/** + * This class provides a default drag under effect (eg. select, insert and scroll) + * when a drag occurs over a <code>Table</code>. + * + * <p>Classes that wish to provide their own drag under effect for a <code>Table</code> + * can extend the <code>TableDropTargetEffect</code> and override any applicable methods + * in <code>TableDropTargetEffect</code> to display their own drag under effect.</p> + * + * Subclasses that override any methods of this class must call the corresponding + * <code>super</code> method to get the default drag under effect implementation. + * + * <p>The feedback value is either one of the FEEDBACK constants defined in + * class <code>DND</code> which is applicable to instances of this class, + * or it must be built by <em>bitwise OR</em>'ing together + * (that is, using the <code>int</code> "|" operator) two or more + * of those <code>DND</code> effect constants. + * </p> + * <p> + * <dl> + * <dt><b>Feedback:</b></dt> + * <dd>FEEDBACK_SELECT, FEEDBACK_SCROLL</dd> + * </dl> + * </p> + * + * @see DropTargetAdapter + * @see DropTargetEvent + * + * @since 3.3 + */ +public class TableDropTargetEffect : DropTargetEffect { + static const int SCROLL_HYSTERESIS = 150; // milli seconds + + int scrollIndex; + long scrollBeginTime; + + /** + * 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 this(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) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE; + if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 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; + } + + /** + * 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 = cast(Table) control; + auto handle = table.handle; + OS.gtk_tree_view_unset_rows_drag_dest(handle); + + 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 = cast(Table) control; + auto handle = table.handle; + int effect = checkEffect(event.feedback); + Point coordinates = new Point(event.x, event.y); + coordinates = table.toControl(coordinates); + void* path; + OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y, &path, null, null, null); + int index = -1; + if (path !is null) { + auto indices = OS.gtk_tree_path_get_indices (path); + if (indices !is null) { + index = indices[0]; + } + } + if ((effect & DND.FEEDBACK_SCROLL) is 0) { + scrollBeginTime = 0; + scrollIndex = -1; + } else { + if (index !is -1 && scrollIndex is index && scrollBeginTime !is 0) { + if (System.currentTimeMillis() >= scrollBeginTime) { + if (coordinates.y < table.getItemHeight()) { + OS.gtk_tree_path_prev(path); + } else { + OS.gtk_tree_path_next(path); + } + if (path !is null) { + OS.gtk_tree_view_scroll_to_cell(handle, path, null, false, 0, 0); + OS.gtk_tree_path_free(path); + path = null; + OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y, &path, null, null, null); + } + scrollBeginTime = 0; + scrollIndex = -1; + } + } else { + scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS; + scrollIndex = index; + } + } + if (path !is null) { + int position = 0; + if ((effect & DND.FEEDBACK_SELECT) !is 0) position = OS.GTK_TREE_VIEW_DROP_INTO_OR_BEFORE; + //if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 0) position = OS.GTK_TREE_VIEW_DROP_BEFORE; + //if ((effect & DND.FEEDBACK_INSERT_AFTER) !is 0) position = OS.GTK_TREE_VIEW_DROP_AFTER; + if (position !is 0) { + OS.gtk_tree_view_set_drag_dest_row(handle, path, OS.GTK_TREE_VIEW_DROP_INTO_OR_BEFORE); + } else { + OS.gtk_tree_view_unset_rows_drag_dest(handle); + } + } else { + OS.gtk_tree_view_unset_rows_drag_dest(handle); + } + if (path !is null) OS.gtk_tree_path_free (path ); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/TextTransfer.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.TextTransfer; + +import dwt.internal.Converter; +import dwt.internal.gtk.OS; +import dwt.dwthelper.utils; +import dwt.dnd.ByteArrayTransfer; +import dwt.dnd.TransferData; +import dwt.dnd.DND; + + +static import tango.stdc.stringz; + +/** + * 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 : ByteArrayTransfer { + + private static TextTransfer _instance; + private static const char[] COMPOUND_TEXT = "COMPOUND_TEXT"; //$NON-NLS-1$ + private static const char[] UTF8_STRING = "UTF8_STRING"; //$NON-NLS-1$ + private static const char[] STRING = "STRING"; //$NON-NLS-1$ + private static const int COMPOUND_TEXT_ID; + private static const int UTF8_STRING_ID; + private static const int STRING_ID; + +static this(){ + COMPOUND_TEXT_ID = registerType(COMPOUND_TEXT); + UTF8_STRING_ID = registerType(UTF8_STRING); + STRING_ID = registerType(STRING); + _instance = new TextTransfer(); +} + +private this() {} + +/** + * Returns the singleton instance of the TextTransfer class. + * + * @return the singleton instance of the TextTransfer class + */ +public static TextTransfer getInstance () { + return _instance; +} + +/** + * This implementation of <code>javaToNative</code> converts plain text + * represented by a java <code>String</code> to a platform specific representation. + * + * @param object a java <code>String</code> containing text + * @param transferData an empty <code>TransferData</code> object; this object + * will be filled in on return with the platform specific format of the data + * + * @see Transfer#javaToNative + */ +public void javaToNative (Object object, TransferData transferData) { + transferData.result = 0; + if (!checkText(object) || !isSupportedType(transferData)) { + DND.error(DND.ERROR_INVALID_DATA); + } + char[] string = (cast(ArrayWrapperString)object).array; + char* utf8 = tango.stdc.stringz.toStringz(string); + if (transferData.type is cast(void*) COMPOUND_TEXT_ID) { + void* encoding; + int format; + char* ctext; + int length; + bool result = cast(bool) OS.gdk_utf8_to_compound_text(utf8, &encoding, &format, &ctext, &length); + if (!result) return; + transferData.type = encoding; + transferData.format = format; + transferData.length = length; + transferData.pValue = ctext; + transferData.result = 1; + } + if (transferData.type is cast(void*)UTF8_STRING_ID) { + char* pValue = cast(char*)OS.g_malloc(string.length+1); + if (pValue is null) return; + pValue[ 0 .. string.length ] = string; + pValue[ string.length ] = '\0'; + transferData.type = cast(void*)UTF8_STRING_ID; + transferData.format = 8; + transferData.length = string.length; + transferData.pValue = pValue; + transferData.result = 1; + } + if (transferData.type is cast(void*)STRING_ID) { + auto string_target = OS.gdk_utf8_to_string_target(utf8); + if (string_target is null) return; + transferData.type = cast(void*)STRING_ID; + transferData.format = 8; + transferData.length = tango.stdc.string.strlen(string_target); + transferData.pValue = string_target; + transferData.result = 1; + } +} + +/** + * This implementation of <code>nativeToJava</code> converts a platform specific + * representation of plain text to a java <code>String</code>. + * + * @param transferData the platform specific representation of the data to be converted + * @return a java <code>String</code> containing text if the conversion was successful; otherwise null + * + * @see Transfer#nativeToJava + */ +public Object nativeToJava(TransferData transferData){ + if (!isSupportedType(transferData) || transferData.pValue is null) return null; + char** list; + int count = OS.gdk_text_property_to_utf8_list(transferData.type, transferData.format, transferData.pValue, transferData.length, &list); + if (count is 0) return null; + char[] utf8 = tango.stdc.stringz.fromUtf8z( list[0] ).dup; + OS.g_strfreev(list); + return new ArrayWrapperString( utf8 ); +} + +protected int[] getTypeIds() { + return [UTF8_STRING_ID, COMPOUND_TEXT_ID, STRING_ID]; +} + +protected char[][] getTypeNames() { + return [UTF8_STRING, COMPOUND_TEXT, STRING]; +} + +bool checkText(Object object) { + if( object is null ) return false; + ArrayWrapperString astr = cast(ArrayWrapperString)object; + if( astr is null ) return false; + return astr.array.length > 0; +} + +protected bool validate(Object object) { + return checkText(object); +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/Transfer.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.Transfer; + + +import dwt.internal.Converter; +import dwt.internal.gtk.OS; +import dwt.dnd.TransferData; + +static import tango.stdc.stringz; + +/** + * <code>Transfer</code> provides a mechanism for converting between a java + * representation of data and a platform specific representation of data and + * vice versa. It is used in data transfer operations such as drag and drop and + * clipboard copy/paste. + * + * <p>You should only need to become familiar with this class if you are + * implementing a Transfer subclass and you are unable to subclass the + * ByteArrayTransfer class.</p> + * + * @see ByteArrayTransfer + */ +public abstract class Transfer { + +/** + * Returns a list of the platform specific data types that can be converted using + * this transfer agent. + * + * <p>Only the data type fields of the <code>TransferData</code> objects are filled + * in.</p> + * + * @return a list of the data types that can be converted using this transfer agent + */ +abstract public TransferData[] getSupportedTypes(); + +/** + * Returns true if the <code>TransferData</code> data type can be converted + * using this transfer agent, or false otherwise (including if transferData is + * <code>null</code>). + * + * @param transferData a platform specific description of a data type; only the data + * type fields of the <code>TransferData</code> object need to be filled in + * + * @return true if the transferData data type can be converted using this transfer + * agent + */ +abstract public bool isSupportedType(TransferData transferData); + +/** + * 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 public char[][] getTypeNames(); + +/** + * 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 public int[] getTypeIds(); + +/** + * 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 dwt.DWTException <ul> + * <li>ERROR_INVALID_DATA - if object does not contain data in a valid format or is <code>null</code></li> + * </ul> + */ +abstract public 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 public 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(char[] formatName){ + if (formatName is null) return OS.GDK_NONE; + char* buffer = tango.stdc.stringz.toStringz( formatName ); + return cast(int)/*64*/OS.gdk_atom_intern(buffer, false); +} + +/** + * 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 + */ +public bool validate(Object object) { + return true; +} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/TransferData.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.dnd.TransferData; + + +/** + * The <code>TransferData</code> class is a platform specific data structure for + * describing the type and the contents of data being converted by a transfer agent. + * + * <p>As an application writer, you do not need to know the specifics of + * TransferData. TransferData instances are passed to a subclass of Transfer + * and the Transfer object manages the platform specific issues. + * You can ask a Transfer subclass if it can handle this data by calling + * Transfer.isSupportedType(transferData).</p> + * + * <p>You should only need to become familiar with the fields in this class if you + * are implementing a Transfer subclass and you are unable to subclass the + * ByteArrayTransfer class.</p> + */ +public class TransferData { + /** + * The type is a unique identifier of a system format or user defined format. + * (Warning: This field is platform dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT + * public API. It is marked public only so that it can be shared + * within the packages provided by DWT. It is not available on all + * platforms and should never be accessed from application code. + * </p> + */ + public void* type; + + /** + * Specifies the number of units in pValue. + * (Warning: This field is platform dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT + * public API. It is marked public only so that it can be shared + * within the packages provided by DWT. It is not available on all + * platforms and should never be accessed from application code. + * </p> + * + * @see TransferData#format for the size of one unit + */ + public int length; + + /** + * Specifies the size in bits of a single unit in pValue. + * (Warning: This field is platform dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT + * public API. It is marked public only so that it can be shared + * within the packages provided by DWT. It is not available on all + * platforms and should never be accessed from application code. + * </p> + * + * This is most commonly 8 bits. + */ + public int format; + + /** + * Pointer to the data being transferred. + * (Warning: This field is platform dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT + * public API. It is marked public only so that it can be shared + * within the packages provided by DWT. It is not available on all + * platforms and should never be accessed from application code. + * </p> + */ + public char* pValue; + + /** + * 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 DWT + * public API. It is marked public only so that it can be shared + * within the packages provided by DWT. 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; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/TreeDragSourceEffect.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,145 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.TreeDragSourceEffect; + + +import dwt.DWT; +import dwt.graphics.Image; +import dwt.internal.gtk.OS; +import dwt.widgets.Display; +import dwt.widgets.Tree; +import dwt.dnd.DragSourceEffect; +import dwt.dnd.DragSourceEvent; + +import Math = tango.math.Math; + +/** + * This class provides default implementations to display a source image + * when a drag is initiated from a <code>Tree</code>. + * + * <p>Classes that wish to provide their own source image for a <code>Tree</code> can + * extend <code>TreeDragSourceEffect</code> class and override the <code>TreeDragSourceEffect.dragStart</code> + * method and set the field <code>DragSourceEvent.image</code> with their own image.</p> + * + * Subclasses that override any methods of this class must call the corresponding + * <code>super</code> method to get the default drag under effect implementation. + * + * @see DragSourceEffect + * @see DragSourceEvent + * + * @since 3.3 + */ +public class TreeDragSourceEffect : 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 this(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 !is 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 !is null) dragSourceImage.dispose(); + dragSourceImage = null; + + Tree tree = cast(Tree) control; + if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) return null; + /* + * Bug in GTK. gtk_tree_selection_get_selected_rows() segmentation faults + * in versions smaller than 2.2.4 if the model is NULL. The fix is + * to give a valid pointer instead. + */ + auto handle = tree.handle; + auto selection = OS.gtk_tree_view_get_selection (handle); + int dummy; + void* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null; + auto list = OS.gtk_tree_selection_get_selected_rows (selection, &model); + if (list is null) return null; + int count = Math.min(10, OS.g_list_length (list)); + + Display display = tree.getDisplay(); + if (count is 1) { + auto path = OS.g_list_nth_data (list, 0); + auto pixmap = OS.gtk_tree_view_create_row_drag_icon(handle, path); + dragSourceImage = Image.gtk_new(display, DWT.ICON, pixmap, null); + } else { + int width = 0, height = 0; + int w , h; + int[] yy = new int[count], hh = new int[count]; + GdkDrawable* [] pixmaps = new GdkDrawable*[count]; + GdkRectangle rect; + for (int i=0; i<count; i++) { + auto path = OS.g_list_nth_data (list, i); + OS.gtk_tree_view_get_cell_area (handle, path, null, &rect); + pixmaps[i] = OS.gtk_tree_view_create_row_drag_icon(handle, path); + OS.gdk_drawable_get_size(pixmaps[i], &w, &h); + width = Math.max(width, w); + height = rect.y + h - yy[0]; + yy[i] = rect.y; + hh[i] = h; + } + auto source = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, -1); + auto gcSource = OS.gdk_gc_new(source); + auto mask = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, 1); + auto gcMask = OS.gdk_gc_new(mask); + GdkColor color; + color.pixel = 0; + OS.gdk_gc_set_foreground(gcMask, &color); + OS.gdk_draw_rectangle(mask, gcMask, 1, 0, 0, width, height); + color.pixel = 1; + OS.gdk_gc_set_foreground(gcMask, &color); + for (int i=0; i<count; i++) { + OS.gdk_draw_drawable(source, gcSource, pixmaps[i], 0, 0, 0, yy[i] - yy[0], -1, -1); + OS.gdk_draw_rectangle(mask, gcMask, 1, 0, yy[i] - yy[0], width, hh[i]); + OS.g_object_unref(pixmaps[i]); + } + OS.g_object_unref(gcSource); + OS.g_object_unref(gcMask); + dragSourceImage = Image.gtk_new(display, DWT.ICON, source, mask); + } + OS.g_list_free (list); + + return dragSourceImage; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/dnd/TreeDropTargetEffect.d Fri Jan 18 00:34:32 2008 +0100 @@ -0,0 +1,224 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.dnd.TreeDropTargetEffect; + + +import dwt.graphics.Point; +import dwt.internal.gtk.OS; +import dwt.widgets.Tree; +import dwt.dnd.DropTargetEffect; +import dwt.dnd.DropTargetEvent; +import dwt.dnd.DND; +import dwt.dwthelper.System; + +/** + * This class provides a default drag under effect (eg. select, insert, scroll and expand) + * when a drag occurs over a <code>Tree</code>. + * + * <p>Classes that wish to provide their own drag under effect for a <code>Tree</code> + * can extend the <code>TreeDropTargetEffect</code> class and override any applicable methods + * in <code>TreeDropTargetEffect</code> to display their own drag under effect.</p> + * + * Subclasses that override any methods of this class must call the corresponding + * <code>super</code> method to get the default drag under effect implementation. + * + * <p>The feedback value is either one of the FEEDBACK constants defined in + * class <code>DND</code> which is applicable to instances of this class, + * or it must be built by <em>bitwise OR</em>'ing together + * (that is, using the <code>int</code> "|" operator) two or more + * of those <code>DND</code> effect constants. + * </p> + * <p> + * <dl> + * <dt><b>Feedback:</b></dt> + * <dd>FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE, FEEDBACK_INSERT_AFTER, FEEDBACK_EXPAND, FEEDBACK_SCROLL</dd> + * </dl> + * </p><p> + * Note: Only one of the styles FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE or + * FEEDBACK_INSERT_AFTER may be specified. + * </p> + * + * @see DropTargetAdapter + * @see DropTargetEvent + * + * @since 3.3 + */ +public class TreeDropTargetEffect : DropTargetEffect { + static const int SCROLL_HYSTERESIS = 150; // milli seconds + static const int EXPAND_HYSTERESIS = 1000; // milli seconds + + int scrollIndex = -1; + long scrollBeginTime; + + int expandIndex = -1; + long expandBeginTime; + + /** + * 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 this(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) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE; + if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 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) { + 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 = cast(Tree) control; + auto handle = tree.handle; + OS.gtk_tree_view_unset_rows_drag_dest(handle); + + scrollBeginTime = 0; + scrollIndex = -1; + expandBeginTime = 0; + expandIndex = -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 = cast(Tree) control; + int effect = checkEffect(event.feedback); + + auto handle = tree.handle; + Point coordinates = new Point(event.x, event.y); + coordinates = tree.toControl(coordinates); + void* path; + OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y, &path, null, null, null); + int index = -1; + if (path !is null) { + auto indices = OS.gtk_tree_path_get_indices(path); + if (indices !is null) { + int depth = OS.gtk_tree_path_get_depth(path); + index = indices[depth - 1]; + } + } + if ((effect & DND.FEEDBACK_SCROLL) is 0) { + scrollBeginTime = 0; + scrollIndex = -1; + } else { + if (index !is -1 && scrollIndex is index && scrollBeginTime !is 0) { + if (System.currentTimeMillis() >= scrollBeginTime) { + GdkRectangle cellRect; + OS.gtk_tree_view_get_cell_area (handle, path, null, &cellRect); + if (cellRect.y < cellRect.height) { + int tx, ty; + OS.gtk_tree_view_widget_to_tree_coords(handle, cellRect.x, cellRect.y - cellRect.height, &tx, &ty); + OS.gtk_tree_view_scroll_to_point (handle, -1, ty); + } else { + //scroll down + OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y + cellRect.height, &path, null, null, null); + if (path !is null) { + OS.gtk_tree_view_scroll_to_cell(handle, path, null, false, 0, 0); + OS.gtk_tree_path_free(path); + path = null; + } + OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y, &path, null, null, null); + } + scrollBeginTime = 0; + scrollIndex = -1; + } + } else { + scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS; + scrollIndex = index; + } + } + if ((effect & DND.FEEDBACK_EXPAND) is 0) { + expandBeginTime = 0; + expandIndex = -1; + } else { + if (index !is -1 && expandIndex is index && expandBeginTime !is 0) { + if (System.currentTimeMillis() >= expandBeginTime) { + OS.gtk_tree_view_expand_row (handle, path, false); + expandBeginTime = 0; + expandIndex = -1; + } + } else { + expandBeginTime = System.currentTimeMillis() + EXPAND_HYSTERESIS; + expandIndex = index; + } + } + if (path !is null) { + int position = -1; + if ((effect & DND.FEEDBACK_SELECT) !is 0) position = OS.GTK_TREE_VIEW_DROP_INTO_OR_BEFORE; + if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 0) position = OS.GTK_TREE_VIEW_DROP_BEFORE; + if ((effect & DND.FEEDBACK_INSERT_AFTER) !is 0) position = OS.GTK_TREE_VIEW_DROP_AFTER; + if (position !is -1) { + OS.gtk_tree_view_set_drag_dest_row(handle, path, position); + } else { + OS.gtk_tree_view_unset_rows_drag_dest(handle); + } + } else { + OS.gtk_tree_view_unset_rows_drag_dest(handle); + } + + if (path !is null) OS.gtk_tree_path_free (path ); + } + +}
--- a/dwt/dwthelper/System.d Thu Jan 17 15:44:59 2008 +0100 +++ b/dwt/dwthelper/System.d Fri Jan 18 00:34:32 2008 +0100 @@ -115,5 +115,11 @@ alias SimpleType!(Object[]).arraycopy arraycopy; alias SimpleType!(void*[]).arraycopy arraycopy; alias SimpleType!(void*[]).arraycopy arraycopy; + + static long currentTimeMillis(){ + //PORTING_FIXMe + return 0; + } + }
--- a/dwt/dwthelper/utils.d Thu Jan 17 15:44:59 2008 +0100 +++ b/dwt/dwthelper/utils.d Fri Jan 18 00:34:32 2008 +0100 @@ -24,10 +24,11 @@ } } -alias ArrayWrapperT!(int) ArrayWrapperInt; -alias ArrayWrapperT!(Object) ArrayWrapperObject; -alias ArrayWrapperT!(char) ArrayWrapperString; -alias ArrayWrapperT!(char[]) ArrayWrapperString2; +alias ArrayWrapperT!(byte) ArrayWrapperByte; +alias ArrayWrapperT!(int) ArrayWrapperInt; +alias ArrayWrapperT!(Object) ArrayWrapperObject; +alias ArrayWrapperT!(char) ArrayWrapperString; +alias ArrayWrapperT!(char[]) ArrayWrapperString2;
--- a/dwt/graphics/Image.d Thu Jan 17 15:44:59 2008 +0100 +++ b/dwt/graphics/Image.d Fri Jan 18 00:34:32 2008 +0100 @@ -950,7 +950,7 @@ * * @private */ -public static Image gtk_new(Device device, int type, int /*long*/ pixmap, int /*long*/ mask) { +public static Image gtk_new(Device device, int type, GdkDrawable* pixmap, GdkDrawable* mask) { if (device is null) device = Device.getDevice(); Image image = new Image(); image.type = type;
--- a/dwt/internal/gtk/OS.d Thu Jan 17 15:44:59 2008 +0100 +++ b/dwt/internal/gtk/OS.d Fri Jan 18 00:34:32 2008 +0100 @@ -48,6 +48,7 @@ public alias dwt.internal.c.glib_object.GTypeClass GTypeClass; public alias dwt.internal.c.glib_object.GInterfaceInfo GInterfaceInfo; public alias dwt.internal.c.glib_object.GTypeQuery GTypeQuery; +public alias dwt.internal.c.glib_object.GError GError; public alias dwt.internal.c.gdk.GdkColor GdkColor; public alias dwt.internal.c.gdk.GdkRegion GdkRegion; @@ -76,6 +77,7 @@ public alias dwt.internal.c.gdk.GdkEventFocus GdkEventFocus; public alias dwt.internal.c.gdk.GdkWindowAttr GdkWindowAttr; public alias dwt.internal.c.gdk.GdkEventWindowState GdkEventWindowState; +public alias dwt.internal.c.gdk.GdkDragContext GdkDragContext; public alias dwt.internal.c.pango.PangoFontDescription PangoFontDescription; public alias dwt.internal.c.pango.PangoTabArray PangoTabArray; @@ -485,6 +487,7 @@ public alias dwt.internal.c.gtk.GtkAccelKey GtkAccelKey; public alias dwt.internal.c.gtk.GtkAccelGroupClass GtkAccelGroupClass; public alias dwt.internal.c.gtk.GtkAccelGroup GtkAccelGroup; +public alias dwt.internal.c.gtk.GtkClipboard GtkClipboard; public alias dwt.internal.c.gtk.GtkTreeModel GtkTreeModel; public alias dwt.internal.c.gtk.GtkTreePath GtkTreePath; @@ -1278,7 +1281,7 @@ mixin ForwardGtkOsCFunc!(.g_utf8_strlen); mixin ForwardGtkOsCFunc!(.g_utf8_to_utf16); mixin ForwardGtkOsCFunc!(.gdk_atom_intern); -// mixin ForwardGtkOsCFunc!(.gdk_atom_name); + mixin ForwardGtkOsCFunc!(.gdk_atom_name); mixin ForwardGtkOsCFunc!(.gdk_beep); mixin ForwardGtkOsCFunc!(.gdk_bitmap_create_from_data); mixin ForwardGtkOsCFunc!(.gdk_cairo_region); @@ -1395,9 +1398,9 @@ mixin ForwardGtkOsCFunc!(.gdk_screen_width); mixin ForwardGtkOsCFunc!(.gdk_screen_width_mm); mixin ForwardGtkOsCFunc!(.gdk_set_program_class); -// mixin ForwardGtkOsCFunc!(.gdk_utf8_to_compound_text); -// mixin ForwardGtkOsCFunc!(.gdk_utf8_to_string_target); -// mixin ForwardGtkOsCFunc!(.gdk_text_property_to_utf8_list ); + mixin ForwardGtkOsCFunc!(.gdk_utf8_to_compound_text); + mixin ForwardGtkOsCFunc!(.gdk_utf8_to_string_target); + mixin ForwardGtkOsCFunc!(.gdk_text_property_to_utf8_list ); mixin ForwardGtkOsCFunc!(.gdk_unicode_to_keyval); mixin ForwardGtkOsCFunc!(.gdk_visual_get_system); mixin ForwardGtkOsCFunc!(.gdk_window_at_pointer);